1php-ast 2======= 3 4This extension exposes the abstract syntax tree generated by PHP 7 and 8. 5 6**This is the documentation for version 1.x.y. See also [documentation for version 0.1.x][v0_1_x].** 7 8Table of Contents 9----------------- 10 11 * [Installation](#installation) 12 * [API overview](#api-overview) 13 * [Basic usage](#basic-usage) 14 * [Example](#example) 15 * [Metadata](#metadata) 16 * [Flags](#flags) 17 * [AST node kinds](#ast-node-kinds) 18 * [AST versioning](#ast-versioning) 19 * [Differences to PHP-Parser](#differences-to-php-parser) 20 21Installation 22------------ 23 24**Windows**: Download a [prebuilt Windows DLL](http://windows.php.net/downloads/pecl/releases/ast/) 25and move it into the `ext/` directory of your PHP installation. Furthermore add 26`extension=php_ast.dll` to your `php.ini` file. 27 28**Unix (PECL)**: Run `pecl install ast` and add `extension=ast.so` to your `php.ini`. 29 30**Unix (Compile)**: Compile and install the extension as follows. 31 32```sh 33phpize 34./configure 35make 36sudo make install 37``` 38 39Additionally add `extension=ast.so` to your `php.ini` file. 40 41API overview 42------------ 43 44Defines: 45 46 * `ast\Node` class 47 * `ast\Metadata` class 48 * `ast\AST_*` kind constants 49 * `ast\flags\*` flag constants 50 * `ast\parse_file(string $filename, int $version)` 51 * `ast\parse_code(string $code, int $version [, string $filename = "string code"])` 52 * `ast\get_kind_name(int $kind)` 53 * `ast\kind_uses_flags(int $kind)` 54 * `ast\get_metadata()` 55 * `ast\get_supported_versions(bool $exclude_deprecated = false)` 56 57Basic usage 58----------- 59 60Code can be parsed using either `ast\parse_code()`, which accepts a code string, or 61`ast\parse_file()`, which accepts a file path. Additionally, both functions require a `$version` 62argument to ensure forward-compatibility. The current version is 100. 63 64```php 65$ast = ast\parse_code('<?php ...', $version=100); 66// or 67$ast = ast\parse_file('file.php', $version=100); 68``` 69 70The abstract syntax tree returned by these functions consists of `ast\Node` objects. 71`ast\Node` is declared as follows: 72 73```php 74namespace ast; 75class Node { 76 public $kind; 77 public $flags; 78 public $lineno; 79 public $children; 80} 81``` 82 83The `kind` property specifies the type of the node. It is an integral value, which corresponds to 84one of the `ast\AST_*` constants, for example `ast\AST_STMT_LIST`. See the 85[AST node kinds section](#ast-node-kinds) for an overview of the available node kinds. 86 87The `flags` property contains node specific flags. It is always defined, but for most nodes it is 88always zero. See the [flags section](#flags) for a list of flags supported by the different node 89kinds. 90 91The `lineno` property specifies the *starting* line number of the node. 92 93The `children` property contains an array of child-nodes. These children can be either other 94`ast\Node` objects or plain values. There are two general categories of nodes: Normal AST nodes, 95which have a fixed set of named child nodes, as well as list nodes, which have a variable number 96of children. The [AST node kinds section](#ast-node-kinds) contains a list of the child names for 97the different node kinds. 98 99Example 100------- 101 102Simple usage example: 103 104```php 105<?php 106 107$code = <<<'EOC' 108<?php 109$var = 42; 110EOC; 111 112var_dump(ast\parse_code($code, $version=70)); 113 114// Output: 115object(ast\Node)#1 (4) { 116 ["kind"]=> 117 int(132) 118 ["flags"]=> 119 int(0) 120 ["lineno"]=> 121 int(1) 122 ["children"]=> 123 array(1) { 124 [0]=> 125 object(ast\Node)#2 (4) { 126 ["kind"]=> 127 int(517) 128 ["flags"]=> 129 int(0) 130 ["lineno"]=> 131 int(2) 132 ["children"]=> 133 array(2) { 134 ["var"]=> 135 object(ast\Node)#3 (4) { 136 ["kind"]=> 137 int(256) 138 ["flags"]=> 139 int(0) 140 ["lineno"]=> 141 int(2) 142 ["children"]=> 143 array(1) { 144 ["name"]=> 145 string(3) "var" 146 } 147 } 148 ["expr"]=> 149 int(42) 150 } 151 } 152 } 153} 154``` 155 156The [`util.php`][util] file defines an `ast_dump()` function, which can be used to create a more 157compact and human-readable dump of the AST structure: 158 159```php 160<?php 161 162require 'path/to/util.php'; 163 164$code = <<<'EOC' 165<?php 166$var = 42; 167EOC; 168 169echo ast_dump(ast\parse_code($code, $version=70)), "\n"; 170 171// Output: 172AST_STMT_LIST 173 0: AST_ASSIGN 174 var: AST_VAR 175 name: "var" 176 expr: 42 177``` 178 179To additionally show line numbers pass the `AST_DUMP_LINENOS` option as the second argument to 180`ast_dump()`. 181 182A more substantial AST dump can be found [in the tests][test_dump]. 183 184Metadata 185-------- 186 187There are a number of functions which provide meta-information for the AST structure: 188 189`ast\get_kind_name()` returns a string name for an integral node kind. 190 191`ast\kind_uses_flags()` determines whether the `flags` of a node kind may ever be non-zero. 192 193`ast\get_metadata()` returns metadata about all AST node kinds. The return value is a map from AST 194node kinds to `ast\Metadata` objects defined as follows. 195 196```php 197namespace ast; 198class Metadata 199{ 200 public $kind; 201 public $name; 202 public $flags; 203 public $flagsCombinable; 204} 205``` 206 207The `kind` is the integral node kind, while `name` is the same name as returned by the 208`get_kind_name()` function. 209 210`flags` is an array of flag constant names, which may be used by the node kind. `flagsCombinable` 211specifies whether the flag should be checked using `===` (not combinable) or using `&` (combinable). 212Together these two values provide programmatic access to the information listed in the 213[flags section](#flags). 214 215The AST metadata is intended for use in tooling for working the AST, such as AST dumpers. 216 217Flags 218----- 219 220This section lists which flags are used by which AST node kinds. The "combinable" flags can be 221combined using bitwise or and should be checked by using `$ast->flags & ast\flags\FOO`. The 222"exclusive" flags are used standalone and should be checked using `$ast->flags === ast\flags\BAR`. 223 224``` 225// Used by ast\AST_NAME (exclusive) 226ast\flags\NAME_FQ (= 0) // example: \Foo\Bar 227ast\flags\NAME_NOT_FQ // example: Foo\Bar 228ast\flags\NAME_RELATIVE // example: namespace\Foo\Bar 229 230// Used by ast\AST_METHOD, ast\AST_PROP_DECL, ast\AST_PROP_GROUP, 231// ast\AST_CLASS_CONST_DECL, ast\AST_CLASS_CONST_GROUP, and ast\AST_TRAIT_ALIAS (combinable) 232ast\flags\MODIFIER_PUBLIC 233ast\flags\MODIFIER_PROTECTED 234ast\flags\MODIFIER_PRIVATE 235ast\flags\MODIFIER_STATIC 236ast\flags\MODIFIER_ABSTRACT 237ast\flags\MODIFIER_FINAL 238ast\flags\MODIFIER_READONLY 239 240// Used by ast\AST_CLOSURE, ast\AST_ARROW_FUNC (combinable) 241ast\flags\MODIFIER_STATIC 242 243// Used by ast\AST_FUNC_DECL, ast\AST_METHOD, ast\AST_CLOSURE, ast\AST_ARROW_FUNC (combinable) 244ast\flags\FUNC_RETURNS_REF // legacy alias: ast\flags\RETURNS_REF 245ast\flags\FUNC_GENERATOR // used only in PHP >= 7.1 246 247// Used by ast\AST_CLOSURE_VAR 248ast\flags\CLOSURE_USE_REF 249 250// Used by ast\AST_CLASS (combinable since PHP 8.1 enums) 251ast\flags\CLASS_ABSTRACT 252ast\flags\CLASS_FINAL 253ast\flags\CLASS_TRAIT 254ast\flags\CLASS_INTERFACE 255ast\flags\CLASS_ANONYMOUS 256ast\flags\CLASS_ENUM // php 8.1 enums 257ast\flags\CLASS_READONLY // php 8.2 readonly classes 258 259// Used by ast\AST_PARAM (combinable) 260ast\flags\PARAM_REF 261ast\flags\PARAM_VARIADIC 262ast\flags\PARAM_MODIFIER_PUBLIC (available since 1.0.8, same as ast\flags\MODIFIER_* in PHP >= 8.0) 263ast\flags\PARAM_MODIFIER_PROTECTED (available since 1.0.8) 264ast\flags\PARAM_MODIFIER_PRIVATE (available since 1.0.8) 265 266// Used by ast\AST_TYPE (exclusive) 267ast\flags\TYPE_ARRAY 268ast\flags\TYPE_CALLABLE 269ast\flags\TYPE_VOID 270ast\flags\TYPE_BOOL 271ast\flags\TYPE_LONG 272ast\flags\TYPE_DOUBLE 273ast\flags\TYPE_STRING 274ast\flags\TYPE_ITERABLE 275ast\flags\TYPE_OBJECT 276ast\flags\TYPE_NULL // php 8.0 union types 277ast\flags\TYPE_FALSE // php 8.0 union types 278ast\flags\TYPE_TRUE // php 8.2 true type 279ast\flags\TYPE_STATIC // php 8.0 static return type 280ast\flags\TYPE_MIXED // php 8.0 mixed type 281ast\flags\TYPE_NEVER // php 8.1 never type 282 283// Used by ast\AST_CAST (exclusive) 284ast\flags\TYPE_NULL 285ast\flags\TYPE_BOOL 286ast\flags\TYPE_LONG 287ast\flags\TYPE_DOUBLE 288ast\flags\TYPE_STRING 289ast\flags\TYPE_ARRAY 290ast\flags\TYPE_OBJECT 291 292// Used by ast\AST_UNARY_OP (exclusive) 293ast\flags\UNARY_BOOL_NOT 294ast\flags\UNARY_BITWISE_NOT 295ast\flags\UNARY_MINUS 296ast\flags\UNARY_PLUS 297ast\flags\UNARY_SILENCE 298 299// Used by ast\AST_BINARY_OP and ast\AST_ASSIGN_OP (exclusive) 300ast\flags\BINARY_BITWISE_OR 301ast\flags\BINARY_BITWISE_AND 302ast\flags\BINARY_BITWISE_XOR 303ast\flags\BINARY_CONCAT 304ast\flags\BINARY_ADD 305ast\flags\BINARY_SUB 306ast\flags\BINARY_MUL 307ast\flags\BINARY_DIV 308ast\flags\BINARY_MOD 309ast\flags\BINARY_POW 310ast\flags\BINARY_SHIFT_LEFT 311ast\flags\BINARY_SHIFT_RIGHT 312ast\flags\BINARY_COALESCE 313 314// Used by ast\AST_BINARY_OP (exclusive) 315ast\flags\BINARY_BOOL_AND 316ast\flags\BINARY_BOOL_OR 317ast\flags\BINARY_BOOL_XOR 318ast\flags\BINARY_IS_IDENTICAL 319ast\flags\BINARY_IS_NOT_IDENTICAL 320ast\flags\BINARY_IS_EQUAL 321ast\flags\BINARY_IS_NOT_EQUAL 322ast\flags\BINARY_IS_SMALLER 323ast\flags\BINARY_IS_SMALLER_OR_EQUAL 324ast\flags\BINARY_IS_GREATER 325ast\flags\BINARY_IS_GREATER_OR_EQUAL 326ast\flags\BINARY_SPACESHIP 327 328// Used by ast\AST_MAGIC_CONST (exclusive) 329ast\flags\MAGIC_LINE 330ast\flags\MAGIC_FILE 331ast\flags\MAGIC_DIR 332ast\flags\MAGIC_NAMESPACE 333ast\flags\MAGIC_FUNCTION 334ast\flags\MAGIC_METHOD 335ast\flags\MAGIC_CLASS 336ast\flags\MAGIC_TRAIT 337 338// Used by ast\AST_USE, ast\AST_GROUP_USE and ast\AST_USE_ELEM (exclusive) 339ast\flags\USE_NORMAL 340ast\flags\USE_FUNCTION 341ast\flags\USE_CONST 342 343// Used by ast\AST_INCLUDE_OR_EVAL (exclusive) 344ast\flags\EXEC_EVAL 345ast\flags\EXEC_INCLUDE 346ast\flags\EXEC_INCLUDE_ONCE 347ast\flags\EXEC_REQUIRE 348ast\flags\EXEC_REQUIRE_ONCE 349 350// Used by ast\AST_ARRAY (exclusive), since PHP 7.1 351ast\flags\ARRAY_SYNTAX_SHORT 352ast\flags\ARRAY_SYNTAX_LONG 353ast\flags\ARRAY_SYNTAX_LIST 354 355// Used by ast\AST_ARRAY_ELEM (exclusive) 356ast\flags\ARRAY_ELEM_REF 357 358// Used by ast\AST_DIM (combinable), since PHP 7.4 359ast\flags\DIM_ALTERNATIVE_SYNTAX 360ast\flags\ENCAPS_VAR_DOLLAR_CURLY // php 8.2 deprecation, only available in php 8.2+ 361 362// Used by ast\AST_VAR (combinable), since PHP 8.2 363ast\flags\ENCAPS_VAR_DOLLAR_CURLY 364ast\flags\ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR 365 366// Used by ast\AST_CONDITIONAL (combinable), since PHP 7.4 367ast\flags\PARENTHESIZED_CONDITIONAL 368``` 369 370AST node kinds 371-------------- 372 373This section lists the AST node kinds that are supported and the names of their child nodes. 374 375``` 376AST_ARRAY_ELEM: value, key 377AST_ARROW_FUNC: name, docComment, params, stmts, returnType, attributes 378AST_ASSIGN: var, expr 379AST_ASSIGN_OP: var, expr 380AST_ASSIGN_REF: var, expr 381AST_ATTRIBUTE: class, args // php 8.0+ attributes (version 80+) 382AST_BINARY_OP: left, right 383AST_BREAK: depth 384AST_CALL: expr, args 385AST_CALLABLE_CONVERT: // php 8.1+ first-class callable syntax 386AST_CAST: expr 387AST_CATCH: class, var, stmts 388AST_CLASS: name, docComment, extends, implements, stmts, (for enums) type 389AST_CLASS_CONST: class, const 390AST_CLASS_CONST_GROUP class, attributes, type // version 80+ 391AST_CLASS_NAME: class // version 70+ 392AST_CLONE: expr 393AST_CLOSURE: name, docComment, params, uses, stmts, returnType, attributes 394AST_CLOSURE_VAR: name 395AST_CONDITIONAL: cond, true, false 396AST_CONST: name 397AST_CONST_ELEM: name, value, docComment 398AST_CONTINUE: depth 399AST_DECLARE: declares, stmts 400AST_DIM: expr, dim 401AST_DO_WHILE: stmts, cond 402AST_ECHO: expr 403AST_EMPTY: expr 404AST_ENUM_CASE: name, expr, docComment, attributes // php 8.1+ enums 405AST_EXIT: expr 406AST_FOR: init, cond, loop, stmts 407AST_FOREACH: expr, value, key, stmts 408AST_FUNC_DECL: name, docComment, params, stmts, returnType, attributes 409 uses // prior to version 60 410AST_GLOBAL: var 411AST_GOTO: label 412AST_GROUP_USE: prefix, uses 413AST_HALT_COMPILER: offset 414AST_IF_ELEM: cond, stmts 415AST_INCLUDE_OR_EVAL: expr 416AST_INSTANCEOF: expr, class 417AST_ISSET: var 418AST_LABEL: name 419AST_MAGIC_CONST: 420AST_MATCH: cond, stmts // php 8.0+ match 421AST_MATCH_ARM: cond, expr // php 8.0+ match 422AST_METHOD: name, docComment, params, stmts, returnType, attributes 423 uses // prior to version 60 424AST_METHOD_CALL: expr, method, args 425AST_METHOD_REFERENCE: class, method 426AST_NAME: name 427AST_NAMED_ARG: name, expr // php 8.0 named parameters 428AST_NAMESPACE: name, stmts 429AST_NEW: class, args 430AST_NULLABLE_TYPE: type // Used only since PHP 7.1 431AST_NULLSAFE_METHOD_CALL: expr, method, args // php 8.0 null safe operator 432AST_NULLSAFE_PROP: expr, prop // php 8.0 null safe operator 433AST_PARAM: type, name, default, attributes, docComment 434AST_POST_DEC: var 435AST_POST_INC: var 436AST_PRE_DEC: var 437AST_PRE_INC: var 438AST_PRINT: expr 439AST_PROP: expr, prop 440AST_PROP_ELEM: name, default, docComment 441AST_PROP_GROUP: type, props, attributes // version 70+ 442AST_REF: var // only used in foreach ($a as &$v) 443AST_RETURN: expr 444AST_SHELL_EXEC: expr 445AST_STATIC: var, default 446AST_STATIC_CALL: class, method, args 447AST_STATIC_PROP: class, prop 448AST_SWITCH: cond, stmts 449AST_SWITCH_CASE: cond, stmts 450AST_THROW: expr 451AST_TRAIT_ALIAS: method, alias 452AST_TRAIT_PRECEDENCE: method, insteadof 453AST_TRY: try, catches, finally 454AST_TYPE: 455AST_UNARY_OP: expr 456AST_UNPACK: expr 457AST_UNSET: var 458AST_USE_ELEM: name, alias 459AST_USE_TRAIT: traits, adaptations 460AST_VAR: name 461AST_WHILE: cond, stmts 462AST_YIELD: value, key 463AST_YIELD_FROM: expr 464 465// List nodes (numerically indexed children): 466AST_ARG_LIST 467AST_ARRAY 468AST_ATTRIBUTE_LIST // php 8.0+ attributes (version 80+) 469AST_ATTRIBUTE_GROUP // php 8.0+ attributes (version 80+) 470AST_CATCH_LIST 471AST_CLASS_CONST_DECL 472AST_CLOSURE_USES 473AST_CONST_DECL 474AST_ENCAPS_LIST // interpolated string: "foo$bar" 475AST_EXPR_LIST 476AST_IF 477AST_LIST 478AST_MATCH_ARM_LIST // php 8.0+ match 479AST_NAME_LIST 480AST_PARAM_LIST 481AST_PROP_DECL 482AST_STMT_LIST 483AST_SWITCH_LIST 484AST_TRAIT_ADAPTATIONS 485AST_USE 486AST_TYPE_UNION // php 8.0+ union types 487AST_TYPE_INTERSECTION // php 8.1+ intersection types 488``` 489 490AST Versioning 491-------------- 492 493The `ast\parse_code()` and `ast\parse_file()` functions each accept a required AST `$version` 494argument. The idea behind the AST version is that we may need to change the format of the AST to 495account for new features in newer PHP versions, or to improve it in other ways. Such changes will 496always be made under a new AST version, while previous formats continue to be supported for some 497time. 498 499Old AST versions may be deprecated in minor versions and removed in major versions of the AST extension. 500 501A list of currently supported versions is available through `ast\get_supported_versions()`. The 502function accepts a boolean argument that determines whether deprecated versions should be excluded. 503 504In the following the changes in the respective AST versions, as well as their current support state, 505are listed. 506 507### 100 (current) 508 509Supported since 1.1.1 (2023-11-12). 510 511* Add a `type` child node for all AST_CLASS_CONST_GROUP nodes. 512 513### 90 (stable) 514 515Supported since 1.0.14 (2021-07-24) 516 517* Same as AST version 85. 518 519### 85 (stable) 520 521Supported since 1.0.11 (2021-04-20) 522 523* Add a `type` child node (for enum type) for all AST_CLASS nodes. 524 525### 80 (stable) 526 527Supported since 1.0.10 (2020-09-12). 528 529* `mixed` type hints are now reported as an `AST_TYPE` with type `TYPE_MIXED` instead of an `AST_NAME`. 530* `AST_CLASS_CONST_GROUP` nodes are emitted for class constant declarations wrapping the `AST_CLASS_CONST_DECL` and any attributes. 531 Previously, `AST_CLASS_CONST_DECL` would be emitted. 532* `AST_PARAM`, `AST_CLASS_DECL`, `AST_METHOD`, `AST_PROP_DECL`, `AST_CLOSURE`, `AST_FUNC_DECL`, and `AST_ARROW_FUNC` nodes 533 now contain an attributes child. 534 535### 70 (stable) 536 537Supported since 1.0.1 (2019-02-11). 538 539* `AST_PROP_GROUP` was added to support PHP 7.4's typed properties. 540 The property visibility modifiers are now part of `AST_PROP_GROUP` instead of `AST_PROP_DECL`. 541 542 Note that property group type information is only available with AST versions 70+. 543* `AST_CLASS_NAME` is created instead of `AST_CLASS_CONST` for `SomeClass::class`. 544 545### 60 (deprecated) 546 547Supported since 0.1.7 (2018-10-06). 548Deprecated in php-ast 1.1.0. 549 550* `AST_FUNC_DECL` and `AST_METHOD` no longer generate a `uses` child. Previously this child was 551 always `null`. 552* `AST_CONST_ELEM` now always has a `docComment` child. Previously it was absent on PHP 7.0. 553 On PHP 7.0 the value is always `null`. 554 555### 50 (deprecated) 556 557Supported since 0.1.5 (2017-07-19). 558Deprecated in php-ast 1.1.0. 559 560This is the oldest AST version available in 1.0.0. See the 561[0.1.x AST version changelog][v0_1_x_versions] for information on changes prior to this version. 562 563Differences to PHP-Parser 564------------------------- 565 566Next to php-ast I also maintain the [PHP-Parser][php-parser] library, which has some overlap with 567this extension. This section summarizes the main differences between php-ast and PHP-Parser so you 568may decide which is preferable for your use-case. 569 570The primary difference is that php-ast is a PHP extension (written in C) which exports the AST 571internally used by PHP 7 and 8. PHP-Parser on the other hand is library written in PHP. This has a number 572of consequences: 573 574 * php-ast is significantly faster than PHP-Parser, because the AST construction is implemented in 575 C. 576 * php-ast needs to be installed as an extension, on Linux either by compiling it manually or 577 retrieving it from a package manager, on Windows by loading a DLL. PHP-Parser is installed as a 578 Composer dependency. 579 * php-ast only runs on PHP >= 7.0 (php-ast 1.0.16 was the last version supporting php <= 7.1), as prior versions did not use an internal AST. PHP-Parser 580 supports PHP >= 5.5. 581 * php-ast may only parse code that is syntactically valid on the version of PHP it runs on. This 582 means that it's not possible to parse code using features of newer versions (e.g. PHP 7.4 code 583 while running on PHP 7.2). Similarly, it is not possible to parse code that is no longer 584 syntactically valid on the used version (e.g. some PHP 5 code may no longer be parsed -- however 585 most code will work). PHP-Parser supports parsing both newer and older (up to PHP 5.2) versions. 586 * php-ast can only parse code which is syntactically valid, while PHP-Parser can provide a partial 587 AST for code that contains errors (e.g., because it is currently being edited). 588 * php-ast only provides the starting line number (and for declarations the ending line number) of 589 nodes, because this is the only part that PHP itself stores. PHP-Parser provides precise file 590 offsets. 591 592There are a number of differences in the AST representation and available support code: 593 594 * The PHP-Parser library uses a separate class for every node type, with child nodes stored as 595 type-annotated properties. php-ast uses one class for everything, with children stored as 596 arrays. The former approach is friendlier to developers because it has very good IDE integration. 597 The php-ast extension does not use separate classes, because registering hundreds of classes was 598 judged a no-go for a bundled extension. 599 * The PHP-Parser library contains various support code for working with the AST, while php-ast only 600 handles AST construction. The reason for this is that implementing this support code in C is 601 extremely complicated and there is little other benefit to implementing it in C. The main 602 components that PHP-Parser offers that may be of interest are: 603 * Node dumper (human readable representation): While the php-ast extension does not directly 604 implement this, a `ast_dump` function is provided in the `util.php` file. 605 * Pretty printer (converting the AST back to PHP code): This is not provided natively, but the 606 [php-ast-reverter][php-ast-reverter] package implements this functionality. 607 * Name resolution (resolving namespace prefixes and aliases): There is currently no standalone 608 package for this. 609 * AST traversal / visitation: There is currently no standalone package for this either, but 610 implementing a recursive AST walk is easy. 611 612The [tolerant-php-parser-to-php-ast][tolerant-php-parser-to-php-ast] project can convert the AST produced by 613[tolerant-php-parser][tolerant-php-parser] (Another pure PHP parser library) into the format used by the php-ast extension. 614This can be used as a slow fallback in 615case the php-ast extension is not available. It may also be used to produce a partial php-ast output 616for code with syntax errors. 617 618 [parser]: http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_language_parser.y 619 [util]: https://github.com/nikic/php-ast/blob/master/util.php 620 [test_dump]: https://github.com/nikic/php-ast/blob/master/tests/001.phpt 621 [php-parser]: https://github.com/nikic/PHP-Parser 622 [php-ast-reverter]: https://github.com/tpunt/php-ast-reverter 623 [tolerant-php-parser]: https://github.com/Microsoft/tolerant-php-parser 624 [tolerant-php-parser-to-php-ast]: https://github.com/tysonandre/tolerant-php-parser-to-php-ast 625 [v0_1_x]: https://github.com/nikic/php-ast/tree/v0.1.x#php-ast 626 [v0_1_x_versions]: https://github.com/nikic/php-ast/tree/v0.1.x#ast-versioning 627