跳转到主要内容

什么是 PHP AST

AST(Abstract Syntax Tree,抽象语法树)是将源码分解为「具有语义结构」的树。 在你编写代码生成工具、静态分析工具、自动重构工具时,AST 几乎是必备基础。用字符串替换容易出错的转换,用 AST 就能按「function call」「class declaration」「use statement」等语法单元安全处理。

PHP 的内部 AST

PHP 7 以后的 Zend Engine 并不直接把 PHP 代码转换为 opcode,而是先转换为内部 AST 再编译。
  • php -r 执行的一行代码,内部也走完全相同的编译管线
  • OPcache 会缓存最终生成的 opcode 供复用
  • 在通常的应用开发中,几乎没有机会直接操作这份内部 AST
也就是说,当你想「用 AST 编辑代码」时,实用的做法不是操作 PHP 运行时内部 AST,而是使用用户态可用的 AST 库。

nikic/PHP-Parser 包

nikic/PHP-Parser 是将 PHP 代码解析、遍历、再生成为 AST 的标准库。README 与官方文档介绍的基本流程分为 3 步。

安装

composer require nikic/php-parser

基本解析示例(代码转 AST)

<?php

use PhpParser\Error;
use PhpParser\ParserFactory;

$code = <<<'CODE'
<?php
function greet(string $name): void {
    echo "Hello, {$name}";
}
CODE;

$parser = (new ParserFactory())->createForNewestSupportedVersion();

try {
    $ast = $parser->parse($code);
} catch (Error $error) {
    echo "Parse error: {$error->getMessage()}\n";
    return;
}

用 NodeVisitor 模式遍历、修改 AST

<?php

use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;

$traverser = new NodeTraverser();

$traverser->addVisitor(new class extends NodeVisitorAbstract {
    public function leaveNode(Node $node)
    {
        if ($node instanceof Node\Scalar\Int_) {
            return new Node\Scalar\String_((string) $node->value);
        }
    }
});

$modifiedAst = $traverser->traverse($ast);
继承 NodeVisitorAbstract 后只需实现所需的钩子(enterNode / leaveNode)。复杂的转换建议在 enterNode 收集信息,在 leaveNode 做替换。

用 Pretty Printer 再生成代码

<?php

use PhpParser\PrettyPrinter;

$prettyPrinter = new PrettyPrinter\Standard();
$newCode = $prettyPrinter->prettyPrintFile($modifiedAst);

echo $newCode;
采用这套流程,你的转换对象就从「作为字符串的代码」变成了「作为语法树的代码」。

Laravel/Chisel 中的使用示例

laravel/chisel 是用于对 Starter Kit 做后处理裁剪的库。它在 composer.json 中依赖 nikic/php-parser 的 5.x 系列。 Chisel 中的 Laravel\Chisel\Ast\Source 按下列顺序进行 AST 编辑:
  1. ParserFactory::createForNewestSupportedVersion() 解析代码
  2. NodeTraverser 添加多个 Visitor(如 RemoveImportVisitor)执行转换
  3. PhpParser\PrettyPrinter\StandardprintFormatPreserving() 保留原格式回写
通过这种设计,use 语句、trait、interface 的移除都可以基于语法而非文本替换来安全执行。

用例

使用 AST 可以让以下开发更好推进:
  • 代码生成 CLI(生成模板后按语法级别编辑)
  • 静态分析工具(检测特定语法、发现违规)
  • 自动重构(API 迁移、命名调整的半自动化)
  • 项目模板的后处理(如 Chisel 的功能移除/替换)

小结

在一般的 Laravel 应用开发中,PHP AST 并非日常都会用到的功能。 不过,若你要做工具或包开发,AST 会成为实现「不易出错、可复现代码变更」的强大基础。先用 nikic/php-parser 的 Parser、Visitor、Pretty Printer 三件套在一个小型 CLI 上尝试即可。
最后修改于 2026年7月13日