Skip to content
CAI
Software that uses CAICheck a score

nikic/PHP-Parser

71.6

Strong · 26 September 2026

22.1k

lines of production code

PHP

primary language

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a PHP parser library that converts PHP source code into an Abstract Syntax Tree (AST) and can regenerate source code from that tree. It supports parsing and generating code for PHP versions ranging from 7.4 through 8.5, including modern features like enums, attributes, and property hooks. The library provides tools for programmatic AST construction, format-preserving code modification, and robust error recovery during parsing.

How it got here

2011–2012 — Initial scaffolding and parser foundation

16 changes.

The project established its development infrastructure, including coding standards, static analysis, and dependency management, while completely restructuring the parser engine by removing legacy components. This period focused on rebuilding the grammar and node representation from scratch, supported by comprehensive test suites covering PHP 7.4 through 8.4 syntax features.

2014 — PHP 8+ AST and Builder Modernization

20 changes.

The PhpParser library underwent a comprehensive overhaul to support modern PHP versions (8.0–8.4), introducing a redesigned AST with dedicated node classes for new syntaxes like enums, attributes, and property hooks. A fluent Builder API was rewritten to facilitate programmatic AST construction, while an emulative lexer and new node visitors enhanced parsing flexibility and traversal capabilities. The update also included a standard pretty printer and extensive test coverage to ensure accuracy and backward compatibility.

2015–2023 — PHP 7-8 parser support and format preservation

15 changes.

The project implemented dedicated parser and lexer support for PHP 7 and PHP 8 features, including modern syntax like enums, match expressions, and nullsafe operators. It introduced internal infrastructure for format-preserving pretty printing using a Myers diff algorithm to maintain original code layout during AST modifications. Extensive test coverage was added to validate these new parsing capabilities, error recovery mechanisms, and the round-trip fidelity of the pretty printer.

Features

Add support for \_\_PROPERTY\_\_ magic constant

The parser now recognizes the \\_\PROPERTY\\\ magic constant, represented by the new \Scalar\\MagicConst\\Property\ class. This change extends the existing set of supported magic constants (such as \\\CLASS\\\, \\\DIR\\\, \\\FILE\\\, \\\FUNCTION\\\, \\\LINE\\\, \\\METHOD\\\, \\\NAMESPACE\\\, and \\\TRAIT\\_\) to include property context, allowing accurate parsing of PHP code that utilizes this constant.

lib/PhpParser/Node/Scalar/MagicConst · high confidence

Added PHP 7 and PHP 8 parser implementations

The library now includes dedicated parser classes for PHP 7 and PHP 8 syntax, allowing users to parse code specific to these versions. These generated parser classes (\Php7\ and \Php8\) extend the base \ParserAbstract\ and define version-specific token constants and parsing tables, enabling accurate AST generation for PHP 7 and PHP 8 features.

lib/PhpParser/Parser · high confidence

Added PHP-Parser fuzzing infrastructure

New tools have been added to the repository to support fuzzing the PHP-Parser library. This includes a corpus generation script (generateCorpus.php) that extracts test inputs from existing parser and pretty-printer tests, a dictionary file (php.dict) containing PHP keywords and constructs to guide the fuzzer, and a target script (target.php) that configures the php-fuzzer to parse code, pretty-print it, and verify that the AST remains identical after round-tripping. The target also handles specific edge cases like clone expressions and group use statements to ensure robust testing.

tools · high confidence

Emulative lexer supports bidirectional PHP version emulation

The lexer now includes an Emulative class that allows tokenizing PHP code for a target version different from the host runtime. It automatically detects whether forward emulation (host older than target) or reverse emulation (host newer than target) is needed and applies the appropriate token emulators, such as those for match expressions, nullsafe operators, attributes, and readonly modifiers, ensuring accurate parsing across PHP version mismatches.

lib/PhpParser/Lexer · high confidence

Expanded lexer emulation for modern PHP syntax features

The lexer now supports token emulation for a wide range of newer PHP language features, enabling the parser to handle code written for PHP 8.0 through 8.5 on older runtimes. This includes support for PHP 8.0 features such as the nullsafe operator (?-\>), match expressions, and the \#\[ attribute syntax; PHP 8.1 additions like enums, explicit octal literals (0o...), and readonly properties (including handling readonly as a function name); and PHP 8.4/8.5 capabilities including asymmetric visibility modifiers (e.g., public(set)), the \_\property\\_ magic constant, the pipe operator (\|\>), and the void cast operator ((void)). A new KeywordEmulator base class and ReverseEmulator wrapper were introduced to streamline and unify these emulation implementations.

lib/PhpParser/Lexer/TokenEmulator · high confidence

Initial project scaffolding and configuration

The repository is initialized with essential configuration files to standardize development and distribution. An .editorconfig enforces consistent coding styles (UTF-8, LF line endings, 4-space indentation). A .gitattributes file defines export-ignores to exclude development artifacts (tests, docs, tools, CI configs) from release archives. A .gitignore file excludes local IDE and build caches. Coding standards are enforced via a PHP-CS-Fixer configuration based on PSR-12. Static analysis is configured with PHPStan (level 6) and a baseline file. Testing is set up with a PHPUnit configuration. Additionally, a Makefile provides shortcuts for running PHPStan, PHP-CS-Fixer, and tests, and a comprehensive CONTRIBUTING.md guide outlines the process for adding new syntax support.

(repo-wide) · high confidence

Internal refactoring for format-preserving pretty printing

The library introduces several internal classes in the PhpParser\\Internal namespace to support format-preserving pretty printing (FPPP). This includes a Myers diff algorithm implementation (Differ, DiffElem) to calculate edit scripts for code changes, a TokenStream class to manage token positions and indentation, and a TokenPolyfill to normalize tokenization across PHP versions. Additionally, a PrintableNewAnonClassNode is added to correctly handle the token offset ordering of anonymous classes during printing.

lib/PhpParser/Internal · high confidence

Introduce Standard pretty printer with support for modern PHP syntax

The library now includes a new \PrettyPrinter\\Standard\ class that handles the generation of PHP code from AST nodes. This implementation adds support for modern PHP features including union and intersection types, named arguments, attributes, and property hooks. It also correctly formats complex string literals (including heredocs and nowdocs with flexible indentation) and ensures proper precedence handling for operators like null coalescing and spaceship.

lib/PhpParser/PrettyPrinter · high confidence

Introduce php-parse CLI tool with error recovery and stdin support

Adds a new \bin/php-parse\ executable that parses PHP source code into an abstract syntax tree and supports multiple output operations including node dumping, pretty-printing, JSON serialization, and name resolution. The tool now allows parsing from standard input (using \-\ as a filename) and includes an error recovery mode (\--with-recovery\) that continues parsing despite syntax errors while reporting them to stderr, rather than failing immediately. It also supports specifying the target PHP version for parsing and displays detailed column information for errors when requested.

bin · high confidence

New AST node visitors for cloning, finding, and parent/sibling linking

Added several new node visitors to the library: CloningVisitor creates deep copies of AST nodes while linking them to their originals via an 'origNode' attribute (required for format-preserving pretty printing); CommentAnnotatingVisitor attaches comment nodes to AST elements based on token positions; FindingVisitor and FirstFindingVisitor allow users to locate all or the first nodes matching a custom filter callback; NodeConnectingVisitor links child nodes to their parents and siblings (previous/next) using attributes, with optional weak references to avoid memory leaks; and ParentConnectingVisitor provides a simpler version that only links to the parent node. These visitors enhance the ability to traverse, analyze, and manipulate PHP ASTs with better context awareness and immutability support.

lib/PhpParser/NodeVisitor · high confidence

PHP 8.0+ syntax support in the AST

The AST node definitions in \lib/PhpParser/Node/Expr\ have been updated to support modern PHP syntax. This includes new nodes for arrow functions (\ArrowFunction\), match expressions (\Match\\), throw expressions (\Throw\\), and the nullsafe operator (\NullsafeMethodCall\, \NullsafePropertyFetch\). Call expressions (\FuncCall\, \MethodCall\, \StaticCall\, \New\_\) now extend a \CallLike\ base class to support partial function application and first-class callables. Additionally, \ClassConstFetch\ now supports dynamic class constant fetches.

lib/PhpParser/Node/Expr · high confidence

PHP 8.4 language features: property hooks and asymmetric visibility

The AST node definitions in lib/PhpParser/Node/Stmt have been updated to support PHP 8.4 syntax. The Property node now includes a $hooks array to represent property hooks and new flags (PUBLIC\_SET, PROTECTED\_SET, PRIVATE\SET) to model asymmetric visibility modifiers. Additionally, the ClassLike node now provides getTraitUses() to retrieve trait usage statements, and the Class\ node includes an isReadonly() method to check for readonly class declarations.

lib/PhpParser/Node/Stmt · high confidence

Removals

Removal of legacy Lexer, NodeAbstract, and Parser components

The \lib\ directory has removed the \Lexer.php\, \NodeAbstract.php\, and \Parser.php\ files. This eliminates the previous hand-written or generated lexer and parser infrastructure, along with the abstract node base class, from the library's public API.

lib · high confidence

Behavioural changes

AST node model overhaul with support for modern PHP features

The internal AST node structure has been completely redesigned to support newer PHP syntaxes and improve type safety. This update introduces dedicated node classes for PHP 8.0+ features, including \Attribute\ and \AttributeGroup\ for attributes, \PropertyHook\ for property hooks, and \MatchArm\ for match expressions. It also adds support for partial function application via \ArgPlaceholder\, first-class callables via \VariadicPlaceholder\, and complex type declarations through \NullableType\, \UnionType\, and \IntersectionType\. The \Name\ class now uses a string representation instead of an array of parts, and the \Param\ node has been expanded to handle constructor property promotion, visibility flags, and readonly modifiers. Additionally, several legacy node names have been updated (e.g., \DeclareDeclare\ to \DeclareItem\, \UseUse\ to \UseItem\) with backward-compatibility aliases provided.

lib/PhpParser/Node · high confidence

Add explicit getType() methods to AssignOp node classes

The AssignOp node classes in lib/PhpParser/Node/Expr/AssignOp now include explicit public getType() methods that return their specific node type strings (e.g., 'Expr\_AssignOp\_BitwiseAnd', 'Expr\_AssignOp\_Coalesce'). This change ensures consistent type identification across all assignment operation nodes, supporting features like the ??= operator and pow operator (PHP 5.6) mentioned in the commit history, while maintaining backward compatibility with existing code.

lib/PhpParser/Node/Expr/AssignOp · high confidence

Binary operators now have dedicated node classes

The library has refactored binary expression handling by introducing a distinct class for each operator (e.g., \BitwiseAnd\, \Coalesce\, \Spaceship\, \Pow\) under \PhpParser\\Node\\Expr\\BinaryOp\. Each class implements \getOperatorSigil()\ to return the specific symbol (such as \??\, \\<=\>\, or \\\\) and \getType()\ to provide a unique type identifier. This change replaces the previous monolithic approach, allowing consumers to identify and handle specific binary operations more precisely.

lib/PhpParser/Node/Expr/BinaryOp · high confidence

Cast nodes split into dedicated classes with explicit kind constants

The \lib/PhpParser/Node/Expr/Cast\ directory now contains separate classes for each cast type (\Array\\, \Bool\\, \Double\, \Int\\, \Object\\, \String\\, \Unset\\, \Void\\), replacing the previous monolithic structure. This change introduces specific \KIND\\*\ constants to distinguish between PHP syntax variants (e.g., \bool\ vs \boolean\, \int\ vs \integer\, \float\/\double\/\real\, \string\ vs \binary\), allowing users to precisely identify the exact cast syntax used in the source code rather than just the target type.

lib/PhpParser/Node/Expr/Cast · high confidence

Comprehensive rewrite of the PHP code builder API

The builder classes in lib/PhpParser/Builder have been completely rewritten to support modern PHP features and provide a more consistent, fluent API. This update introduces dedicated builders for new language constructs, including enums (Enum\_, EnumCase), readonly classes, and typed class constants. It also adds support for PHP 8.1+ features such as constructor property promotion (via visibility modifiers on ParamBuilder), asymmetric visibility (makePrivateSet/makeProtectedSet), and property hooks. The API has been unified with consistent method naming (e.g., setType, addAttribute) and improved type handling, allowing users to generate code for the latest PHP versions with greater precision and ease.

lib/PhpParser/Builder · high confidence

Grammar files restructured and preprocessor updated

The grammar directory has been reorganized: the old \zend\_language\parser.\\ files and the \analyzer.php\ tool have been removed, while new files \php.y\, \parser.template\, and \rebuildParsers.php\ have been added to define and build the parser. The preprocessor script (renamed to \phpyLang.php\) has been updated to support these new grammar constructs, including changes to how node creation and macros are resolved.

grammar · high confidence

PhpParser library refactored with modern PHP 8+ features and expanded builder support

The PhpParser library has been significantly refactored to target PHP 8.0+, introducing a new Builder API for constructing AST nodes programmatically (including builders for classes, interfaces, traits, enums, and use statements) and a ConstExprEvaluator for evaluating constant expressions at runtime. The internal architecture has been modernized with strict typing, the introduction of a Modifiers class for handling visibility and other modifiers, and a new ErrorHandler interface with Collecting and Throwing implementations. Additionally, the library now supports PHP 8.4 features such as asymmetric visibility modifiers and property hooks, and improves error reporting with column information.

lib/PhpParser · high confidence

Removal of legacy PHP parser node classes

The \lib/Node\ directory has been completely cleared of all previously existing PHP parser node classes (such as \Node\_ClassStmt\, \Node\_FuncStmt\, and \Node\_Expr\ variants). These files, which previously defined the AST node structure for the parser, have been deleted, indicating a significant restructuring or migration of the parser's internal node representation.

lib/Node · high confidence

Renamed scalar AST nodes and added support for modern PHP numeric/string syntax

The scalar node classes have been renamed to align with PHP 7 type naming conventions: \LNumber\ is now \Int\\, \DNumber\ is now \Float\\, \Encapsed\ is now \InterpolatedString\, and \EncapsedStringPart\ is now \InterpolatedStringPart\. Deprecated compatibility aliases are provided for existing code. These nodes now support modern PHP features, including numeric literal separators (underscores) in integers and floats, explicit octal prefixes (\0o\), binary literals, and PHP 7 Unicode escape sequences (\\\u{...}\) in strings. The \Int\\ node exposes a \kind\ attribute to distinguish between decimal, octal, hex, and binary literals, while \Float\\ and \String\_\ nodes expose a \rawValue\ attribute preserving the original source representation.

lib/PhpParser/Node/Scalar · high confidence

Test coverage

Added comprehensive test suite for PhpParser components; Added dedicated test classes for PHP 7 and PHP 8 parsers; Added function statement parser tests; Added parser statement tests for PHP 8.0+ features and syntax updates; Added parser tests for Uniform Variable Syntax (UVS) expressions; Added parser tests for comment handling, reserved keywords, and formatting attributes; Added parser tests for fetch and call expressions; Added parser tests for generator yield expressions; Added parser tests for loop statements; Added parser tests for namespace and use statement handling; Added parser tests for scalar literals and string handling; Added test coverage for PHP 8.4 class statement parsing; Added test coverage for the pretty printer; Added test infrastructure and code parsing test utilities; Added tests for CallLike node behavior; Added tests for NodeVisitor utilities; Added tests for parser error handling and recovery; Added tests for scalar node raw value attributes and magic constant methods; Added tests for the emulative lexer's keyword replacement and tokenization; Added tests for the internal Differ component; Added unit tests for Node classes; Added unit tests for PHP-Parser builder classes; Added unit tests for statement node modifiers and accessors; Expanded expression-level pretty printer test coverage; Expanded formatting-preservation test coverage for PHP 8+ syntax; Expanded pretty-printer test coverage for statement-level PHP features; Expanded test coverage for PHP expression parsing; New test runner for php-src integration tests.

Dependencies

Initial composer.json setup with PHP 7.4+ and PHPUnit 9 requirements

This change introduces the project's dependency manifest (composer.json), establishing a minimum PHP version of 7.4 and requiring the ext-tokenizer and ext-json extensions. It sets up PHPUnit 9 for development testing and configures PSR-4 autoloading for the library and its tests, while also defining a bin entry for the php-parse tool. A separate tools/composer.json is added to manage development utilities like php-cs-fixer and phpstan.

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

Score

  • CAI 47 → 72 (+25.1)
  • Rubric changed (rubric-2026.08.15 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 85 → 88 (+3.1)
  • Architecture 94 → 100 (+5.6)
  • Maturity 57 → 56 (-1.5)
  • Readiness 27 → 80 (+53.0)
  • Security 56 → 92 (+35.8)

Resolved (75)

  • Coverage not measured — test suite did not build
  • Dimension evaluation failed
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php8.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php8.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php8.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Parser/Php8.php)
  • Duplicated block (16 lines × 4) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (16 lines × 4) (lib/PhpParser/Parser/Php8.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php7.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php8.php)
  • Duplicated block (5 lines × 2) (lib/PhpParser/Parser/Php8.php)
  • …and 55 more

New (111)

  • BuilderHelpers.normalizeValue (cognitive 17) (lib/PhpParser/BuilderHelpers.php)
  • Change coupling: DNumber.php ↔ LNumber.php (lib/PhpParser/Node/Scalar/DNumber.php)
  • Change coupling: Php7.php ↔ Php8.php (lib/PhpParser/Parser/Php7.php)
  • ClassTooLong: ParserAbstract (lib/PhpParser/ParserAbstract.php)
  • ClassTooLong: Php7 (lib/PhpParser/Parser/Php7.php)
  • ClassTooLong: Php8 (lib/PhpParser/Parser/Php8.php)
  • ClassTooLong: PrettyPrinterAbstract (lib/PhpParser/PrettyPrinterAbstract.php)
  • ClassTooLong: Standard (lib/PhpParser/PrettyPrinter/Standard.php)
  • CommentAnnotatingVisitor.enterNode (cognitive 20) (lib/PhpParser/NodeVisitor/CommentAnnotatingVisitor.php)
  • Consistent use of addStmt across all declaration builders. Declaration also provides addStmts for bulk addition, which is a helpful convenience method. No inconsistency.
  • Differ.calculateTrace (cognitive 18) (lib/PhpParser/Internal/Differ.php)
  • Differ.coalesceReplacements (cognitive 18) (lib/PhpParser/Internal/Differ.php)
  • Documentation: no installation or build instructions (README.md)
  • Documentation: no licence statement (README.md)
  • Documentation: no usage examples (README.md)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Error.php)
  • Duplicated block (10 lines × 2) (lib/PhpParser/Node/Stmt/Goto_.php)
  • Duplicated block (11 lines × 2) (lib/PhpParser/Node/Expr/NullsafePropertyFetch.php)
  • Duplicated block (11 lines × 3) (lib/PhpParser/Builder/Class_.php)
  • Duplicated block (16 lines × 2) (lib/PhpParser/Node/Expr/MethodCall.php)
  • …and 91 more

Changes since last survey

  • 5 commits — 5 feature/other, 0 fixes

By area

  • lib/PhpParser — 4 commits
  • (root) — 1 commit

Notable commits

  • change: Cheap check first in dereferenceLhsRequiresParens() (#1160)
  • change: Implement support for partial function application
  • change: Release PHP-Parser 5.9.0
  • change: Suppress warning on hexdec/bindec/octdec overflow
  • change: Use iteration over recursion in PrettyPrinterAbstract:: newOperandRequiresParens()

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

nikic/PHP-Parser was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 26 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit 5d907dc3c30e379b9168436286e9a2c2f699a2dd — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-a9cd699f3cd5.