解析器与 AST

TypePHP 复用 nikic/php-parser 作为前端词法/语法分析器(依赖固定版本 5.6.1)。解析得到的 PHP AST 是后续所有翻译与符号收集的输入。本章说明 AST 从何而来、以何种形态进入编译器。

Sources: composer.json · project.yml

AST 来源

解析发生在两个时机:

  1. 预处理阶段Preprocessor::prepareFile() 解析每个 PHP 文件,收集类/函数/常量/属性等符号,构建全局符号表(详见 预处理与符号表)。
  2. 转换阶段doConvert() 通过 parseCachedAst() 解析同一文件,得到供代码生成的 AST。
parseCachedAst() 做了两层缓存——同一文件的 AST 在进程内复用,避免重复解析;这也是编译性能优化(S1)的关键点之一。

Sources: src/Preprocessor.php · src/Translator.php

表达式翻译:Parser Trait 集合

编译器主体 CompilerBase 并未把「PHP 表达式 → C++」的逻辑塞进一个巨型方法,而是拆成 src/Parser/ 下的 21 个 trait,每个 trait 负责一类语法结构:

Trait负责的 PHP 结构
BinaryOpTrait+ - * / 等二元运算
AssignOpTrait+=??= 等复合赋值
UnaryExpressionTrait!-++ 等一元运算
FunctionCallTrait普通函数调用
MethodCallTrait / UniversalMethodCall对象/静态方法调用
PropertyAccessTrait属性读写
ArrayExpressionTrait数组字面量
ForeachTrait / LoopControlTraitforeach / for / while
SelectionExpressionTrait / SwitchTraitif / switch
ConditionalControlTrait?: / match
NullsafeAccessTrait?->
ClassConstantFetchTrait类常量读取
TypeConversionTrait / TypeDetectionTrait类型转换与 instanceof
ConstantExpressionTrait编译期常量折叠
ExceptionControlFlowTraittry/catch/throw
StdContainerTraitstd 容器操作

Sources: src/CompilerBase.php · src/Parser/

访客链

doConvert() 在遍历 AST 前先挂载四个 NodeVisitor

$traverser->addVisitor(new NameResolver(...));           // 全限定名解析
$traverser->addVisitor(new Visitor(...));                // Transform lowering(见 transform)
$traverser->addVisitor(new ConstantExpressionValidationVisitor(...));
$traverser->addVisitor(new RuntimeAttributeFactoryLowering(...));

NameResolver 把短名解析为全限定名(但不替换节点),让后续生成能拿到准确的命名空间路径。

Sources: src/Translator.php

相关阅读