| 148 |
lars |
1 |
PHP Parser
|
|
|
2 |
==========
|
|
|
3 |
|
|
|
4 |
[](https://coveralls.io/github/nikic/PHP-Parser?branch=master)
|
|
|
5 |
|
|
|
6 |
This is a PHP 5.2 to PHP 8.2 parser written in PHP. Its purpose is to simplify static code analysis and
|
|
|
7 |
manipulation.
|
|
|
8 |
|
|
|
9 |
[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.2).
|
|
|
10 |
|
|
|
11 |
[Documentation for version 3.x][doc_3_x] (unsupported; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.2).
|
|
|
12 |
|
|
|
13 |
Features
|
|
|
14 |
--------
|
|
|
15 |
|
|
|
16 |
The main features provided by this library are:
|
|
|
17 |
|
|
|
18 |
* Parsing PHP 5, PHP 7, and PHP 8 code into an abstract syntax tree (AST).
|
|
|
19 |
* Invalid code can be parsed into a partial AST.
|
|
|
20 |
* The AST contains accurate location information.
|
|
|
21 |
* Dumping the AST in human-readable form.
|
|
|
22 |
* Converting an AST back to PHP code.
|
|
|
23 |
* Experimental: Formatting can be preserved for partially changed ASTs.
|
|
|
24 |
* Infrastructure to traverse and modify ASTs.
|
|
|
25 |
* Resolution of namespaced names.
|
|
|
26 |
* Evaluation of constant expressions.
|
|
|
27 |
* Builders to simplify AST construction for code generation.
|
|
|
28 |
* Converting an AST into JSON and back.
|
|
|
29 |
|
|
|
30 |
Quick Start
|
|
|
31 |
-----------
|
|
|
32 |
|
|
|
33 |
Install the library using [composer](https://getcomposer.org):
|
|
|
34 |
|
|
|
35 |
php composer.phar require nikic/php-parser
|
|
|
36 |
|
|
|
37 |
Parse some PHP code into an AST and dump the result in human-readable form:
|
|
|
38 |
|
|
|
39 |
```php
|
|
|
40 |
<?php
|
|
|
41 |
use PhpParser\Error;
|
|
|
42 |
use PhpParser\NodeDumper;
|
|
|
43 |
use PhpParser\ParserFactory;
|
|
|
44 |
|
|
|
45 |
$code = <<<'CODE'
|
|
|
46 |
<?php
|
|
|
47 |
|
|
|
48 |
function test($foo)
|
|
|
49 |
{
|
|
|
50 |
var_dump($foo);
|
|
|
51 |
}
|
|
|
52 |
CODE;
|
|
|
53 |
|
|
|
54 |
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
|
|
55 |
try {
|
|
|
56 |
$ast = $parser->parse($code);
|
|
|
57 |
} catch (Error $error) {
|
|
|
58 |
echo "Parse error: {$error->getMessage()}\n";
|
|
|
59 |
return;
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
$dumper = new NodeDumper;
|
|
|
63 |
echo $dumper->dump($ast) . "\n";
|
|
|
64 |
```
|
|
|
65 |
|
|
|
66 |
This dumps an AST looking something like this:
|
|
|
67 |
|
|
|
68 |
```
|
|
|
69 |
array(
|
|
|
70 |
0: Stmt_Function(
|
|
|
71 |
byRef: false
|
|
|
72 |
name: Identifier(
|
|
|
73 |
name: test
|
|
|
74 |
)
|
|
|
75 |
params: array(
|
|
|
76 |
0: Param(
|
|
|
77 |
type: null
|
|
|
78 |
byRef: false
|
|
|
79 |
variadic: false
|
|
|
80 |
var: Expr_Variable(
|
|
|
81 |
name: foo
|
|
|
82 |
)
|
|
|
83 |
default: null
|
|
|
84 |
)
|
|
|
85 |
)
|
|
|
86 |
returnType: null
|
|
|
87 |
stmts: array(
|
|
|
88 |
0: Stmt_Expression(
|
|
|
89 |
expr: Expr_FuncCall(
|
|
|
90 |
name: Name(
|
|
|
91 |
parts: array(
|
|
|
92 |
0: var_dump
|
|
|
93 |
)
|
|
|
94 |
)
|
|
|
95 |
args: array(
|
|
|
96 |
0: Arg(
|
|
|
97 |
value: Expr_Variable(
|
|
|
98 |
name: foo
|
|
|
99 |
)
|
|
|
100 |
byRef: false
|
|
|
101 |
unpack: false
|
|
|
102 |
)
|
|
|
103 |
)
|
|
|
104 |
)
|
|
|
105 |
)
|
|
|
106 |
)
|
|
|
107 |
)
|
|
|
108 |
)
|
|
|
109 |
```
|
|
|
110 |
|
|
|
111 |
Let's traverse the AST and perform some kind of modification. For example, drop all function bodies:
|
|
|
112 |
|
|
|
113 |
```php
|
|
|
114 |
use PhpParser\Node;
|
|
|
115 |
use PhpParser\Node\Stmt\Function_;
|
|
|
116 |
use PhpParser\NodeTraverser;
|
|
|
117 |
use PhpParser\NodeVisitorAbstract;
|
|
|
118 |
|
|
|
119 |
$traverser = new NodeTraverser();
|
|
|
120 |
$traverser->addVisitor(new class extends NodeVisitorAbstract {
|
|
|
121 |
public function enterNode(Node $node) {
|
|
|
122 |
if ($node instanceof Function_) {
|
|
|
123 |
// Clean out the function body
|
|
|
124 |
$node->stmts = [];
|
|
|
125 |
}
|
|
|
126 |
}
|
|
|
127 |
});
|
|
|
128 |
|
|
|
129 |
$ast = $traverser->traverse($ast);
|
|
|
130 |
echo $dumper->dump($ast) . "\n";
|
|
|
131 |
```
|
|
|
132 |
|
|
|
133 |
This gives us an AST where the `Function_::$stmts` are empty:
|
|
|
134 |
|
|
|
135 |
```
|
|
|
136 |
array(
|
|
|
137 |
0: Stmt_Function(
|
|
|
138 |
byRef: false
|
|
|
139 |
name: Identifier(
|
|
|
140 |
name: test
|
|
|
141 |
)
|
|
|
142 |
params: array(
|
|
|
143 |
0: Param(
|
|
|
144 |
type: null
|
|
|
145 |
byRef: false
|
|
|
146 |
variadic: false
|
|
|
147 |
var: Expr_Variable(
|
|
|
148 |
name: foo
|
|
|
149 |
)
|
|
|
150 |
default: null
|
|
|
151 |
)
|
|
|
152 |
)
|
|
|
153 |
returnType: null
|
|
|
154 |
stmts: array(
|
|
|
155 |
)
|
|
|
156 |
)
|
|
|
157 |
)
|
|
|
158 |
```
|
|
|
159 |
|
|
|
160 |
Finally, we can convert the new AST back to PHP code:
|
|
|
161 |
|
|
|
162 |
```php
|
|
|
163 |
use PhpParser\PrettyPrinter;
|
|
|
164 |
|
|
|
165 |
$prettyPrinter = new PrettyPrinter\Standard;
|
|
|
166 |
echo $prettyPrinter->prettyPrintFile($ast);
|
|
|
167 |
```
|
|
|
168 |
|
|
|
169 |
This gives us our original code, minus the `var_dump()` call inside the function:
|
|
|
170 |
|
|
|
171 |
```php
|
|
|
172 |
<?php
|
|
|
173 |
|
|
|
174 |
function test($foo)
|
|
|
175 |
{
|
|
|
176 |
}
|
|
|
177 |
```
|
|
|
178 |
|
|
|
179 |
For a more comprehensive introduction, see the documentation.
|
|
|
180 |
|
|
|
181 |
Documentation
|
|
|
182 |
-------------
|
|
|
183 |
|
|
|
184 |
1. [Introduction](doc/0_Introduction.markdown)
|
|
|
185 |
2. [Usage of basic components](doc/2_Usage_of_basic_components.markdown)
|
|
|
186 |
|
|
|
187 |
Component documentation:
|
|
|
188 |
|
|
|
189 |
* [Walking the AST](doc/component/Walking_the_AST.markdown)
|
|
|
190 |
* Node visitors
|
|
|
191 |
* Modifying the AST from a visitor
|
|
|
192 |
* Short-circuiting traversals
|
|
|
193 |
* Interleaved visitors
|
|
|
194 |
* Simple node finding API
|
|
|
195 |
* Parent and sibling references
|
|
|
196 |
* [Name resolution](doc/component/Name_resolution.markdown)
|
|
|
197 |
* Name resolver options
|
|
|
198 |
* Name resolution context
|
|
|
199 |
* [Pretty printing](doc/component/Pretty_printing.markdown)
|
|
|
200 |
* Converting AST back to PHP code
|
|
|
201 |
* Customizing formatting
|
|
|
202 |
* Formatting-preserving code transformations
|
|
|
203 |
* [AST builders](doc/component/AST_builders.markdown)
|
|
|
204 |
* Fluent builders for AST nodes
|
|
|
205 |
* [Lexer](doc/component/Lexer.markdown)
|
|
|
206 |
* Lexer options
|
|
|
207 |
* Token and file positions for nodes
|
|
|
208 |
* Custom attributes
|
|
|
209 |
* [Error handling](doc/component/Error_handling.markdown)
|
|
|
210 |
* Column information for errors
|
|
|
211 |
* Error recovery (parsing of syntactically incorrect code)
|
|
|
212 |
* [Constant expression evaluation](doc/component/Constant_expression_evaluation.markdown)
|
|
|
213 |
* Evaluating constant/property/etc initializers
|
|
|
214 |
* Handling errors and unsupported expressions
|
|
|
215 |
* [JSON representation](doc/component/JSON_representation.markdown)
|
|
|
216 |
* JSON encoding and decoding of ASTs
|
|
|
217 |
* [Performance](doc/component/Performance.markdown)
|
|
|
218 |
* Disabling Xdebug
|
|
|
219 |
* Reusing objects
|
|
|
220 |
* Garbage collection impact
|
|
|
221 |
* [Frequently asked questions](doc/component/FAQ.markdown)
|
|
|
222 |
* Parent and sibling references
|
|
|
223 |
|
|
|
224 |
[doc_3_x]: https://github.com/nikic/PHP-Parser/tree/3.x/doc
|
|
|
225 |
[doc_4_x]: https://github.com/nikic/PHP-Parser/tree/4.x/doc
|