# 解析器与 AST TypePHP 复用 **nikic/php-parser** 作为前端词法/语法分析器(依赖固定版本 `5.6.1`)。解析得到的 PHP AST 是后续所有翻译与符号收集的输入。本章说明 AST 从何而来、以何种形态进入编译器。 Sources: [composer.json](composer.json#L10) · [project.yml](project.yml#L34-L35) ## AST 来源 解析发生在两个时机: 1. **预处理阶段**:`Preprocessor::prepareFile()` 解析每个 PHP 文件,收集类/函数/常量/属性等符号,构建全局符号表(详见 [预处理与符号表](preprocessor))。 2. **转换阶段**:`doConvert()` 通过 `parseCachedAst()` 解析同一文件,得到供代码生成的 AST。 > `parseCachedAst()` 做了两层缓存——同一文件的 AST 在进程内复用,避免重复解析;这也是编译性能优化(S1)的关键点之一。 Sources: [src/Preprocessor.php](src/Preprocessor.php#L116) · [src/Translator.php](src/Translator.php#L2459) ## 表达式翻译:Parser Trait 集合 编译器主体 `CompilerBase` 并未把「PHP 表达式 → C++」的逻辑塞进一个巨型方法,而是拆成 `src/Parser/` 下的 **21 个 trait**,每个 trait 负责一类语法结构: | Trait | 负责的 PHP 结构 | |---|---| | `BinaryOpTrait` | `+ - * /` 等二元运算 | | `AssignOpTrait` | `+=`、`??=` 等复合赋值 | | `UnaryExpressionTrait` | `!`、`-`、`++` 等一元运算 | | `FunctionCallTrait` | 普通函数调用 | | `MethodCallTrait` / `UniversalMethodCall` | 对象/静态方法调用 | | `PropertyAccessTrait` | 属性读写 | | `ArrayExpressionTrait` | 数组字面量 | | `ForeachTrait` / `LoopControlTrait` | `foreach` / `for` / `while` | | `SelectionExpressionTrait` / `SwitchTrait` | `if` / `switch` | | `ConditionalControlTrait` | `?:` / `match` | | `NullsafeAccessTrait` | `?->` | | `ClassConstantFetchTrait` | 类常量读取 | | `TypeConversionTrait` / `TypeDetectionTrait` | 类型转换与 `instanceof` | | `ConstantExpressionTrait` | 编译期常量折叠 | | `ExceptionControlFlowTrait` | `try/catch/throw` | | `StdContainerTrait` | `std` 容器操作 | Sources: [src/CompilerBase.php](src/CompilerBase.php#L43-L63) · [src/Parser/](src/Parser/) ## 访客链 `doConvert()` 在遍历 AST 前先挂载四个 `NodeVisitor`: ```php $traverser->addVisitor(new NameResolver(...)); // 全限定名解析 $traverser->addVisitor(new Visitor(...)); // Transform lowering(见 transform) $traverser->addVisitor(new ConstantExpressionValidationVisitor(...)); $traverser->addVisitor(new RuntimeAttributeFactoryLowering(...)); ``` `NameResolver` 把短名解析为全限定名(但不替换节点),让后续生成能拿到准确的命名空间路径。 Sources: [src/Translator.php](src/Translator.php#L2460-L2467) ## 相关阅读 - 符号如何被收集 → [预处理与符号表](preprocessor) - 遍历中做了哪些改写 → [AST 转换](transform) - 解析结果的消费方 → [代码生成](generator)