0x01 Introduction
PHP-Parser是基于PHP内部词法分析方法token_get_all来实现的一个抽象语法树(AST)分析工具。
- 参考: PHP-Parser
0x02 使用
安装
使用composer 安装
1 | composer require nikic/php-parser |
基本用法
1 | //加载 |
比如target.php
的内容是: 1
$a = 1;//要加php标签
那么输出: 1
array( 0: Stmt_Expression( expr: Expr_Assign( var: Expr_Variable( name: a ) expr: Scalar_LNumber( value: 1 ) ) ) )
可以看到输出为一个节点数组,这里只有一行,因此只有一个元素。 可以看你到每个节点都是(类型_节点名)表示,在nikic\lib\PhpParser\Node
节点下定义,因为在PHP中有大约140种不同的节点[1],这里大致分为了三类:
- PhpParser: 声明节点(statement nodes),一些声明性的内容,如声明一个类,不具有返回值。
- PhpParser: 表达式节点(expression nodes),具有返回值,且能在其他表达式中调用的。
- PhpParser: 纯量节点(scalar values), 包含字符串,数字,常量等。
还有一些节点不在次三类中。
节点遍历
在解析AST的时候PHP-Parser
提供了四个钩子,分别在遍历前和遍历后执行beforeTraverse
和afterTravers
在访问每一个节点时执行enterNode
和leaveNode
。我们需要写一个Visitor子类来描述我们要在这个步骤上做什么。
1 | use PhpParser\Node; |
这是官方的例子, 描述的是在访问每一个节点后将所有的字符串内容变为foo
我们可以根据上面描述的几类节点更改。比如我要把所有变量名改成var
1 | if ($node instanceof Node\Expr\Variable){ |
遍历一个节点的时候enterNode
比leaveNode
先执行, 在使用enterNode
的时候节点的子节点还没有访问,一次我们可以使用NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN
等来进行访问控制。具体参照官方文档[2]
例子: 比如我们要对一个php中的函数进行切片,可以使用简单的例子:
1 | se PhpParser\Node; |
这里使用了NodeFinder
这个更简便的操作[3]。