PHP AST执行,可以说是基于PHP源代码的一种静态分析。通过分析PHP源代码,将其转换成抽象语法树(AST),然后执行操作,返回执行结果。下面主要介绍PHP AST执行的实现原理以及其实际应用。
实现原理:
<?php $code = 'echo "Hello World!";'; $ast = ast\parse_code($code, $version=50); $serializedAst = serialize($ast); var_dump($serializedAst); ?>
上述代码中,将变量$code中存的PHP代码转化为AST并序列化成字符串,然后通过var_dump将结果打印出来,该结果就是PHP代码的AST的字符串形式。序列化过程中,AST被转化成了一些特定的数据类型,即:Constant、Identifier、UnaryOp、BinaryOp等类型。
针对AST字符串可以做很多实际应用,如代码压缩、代码验证(code linter)、自动修复代码错误等等。
实际应用:
代码压缩:
<?php $code = 'if (true) { echo "Hello World!"; }'; $tokens = token_get_all($code, TOKEN_PARSE); $ast = \ast\parse_code($code, $version = 50); $bits = \ast\flags\AST_BINARY_OP_BITWISE_OR; $rewriter = new \AstKit\Rewrite($ast); $rewriter->apply(function($node) use($bits) { if ($node instanceof \ast\Node && $node->kind === \ast\AST_BINARY_OP && $node->flags & $bits) { $node->flags ^= $bits; } }); $newCode = $rewriter->getNewCode(); var_dump($newCode); ?>
代码验证:
<?php $code = 'if ($a = true); { echo "Hello"; }'; $ast = \ast\parse_code($code, $version = 50); $linter = new \AstLinter\AstLinter(); $linter->registerCheck(new ASTCheck\NoMultiLineString()); $warnings = $linter->lint($ast); var_dump($warnings); ?>
自动修复代码错误:
<?php $code = 'if (true) { $a = 1; $b = 2; $c = 3; }'; $rewrite = new \AstKit\Rewrite(\ast\parse_code($code)); $shouldBreak = true; $notAssign = new \AstKit\Checker\NoAssign(); $rewrite->apply(function($node) use(&$shouldBreak, $notAssign) { if ($node instanceof \ast\Node && $node->kind === \ast\AST_IF) { $children = $node->children; foreach(end($children)->children as $child) { if (!$notAssign->check($child)) { $shouldBreak = false; break; } } } }); if ($shouldBreak) { $childNode = end($rewrite->getNode()->children)->children; array_pop($childNode); $rewrite->setNode($childNode[0]); } var_dump($rewrite->getNewCode()); ?>
总之,PHP AST执行在代码静态分析中有着广泛的应用,能够极大的提高代码的使用率和质量。