- 示例工程
- 数据库
- 教程
- 后端
【免费下载链接】sql-server-samples
Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for SQL Server, Azure SQL, Azure Synapse, and Azure SQL Edge
导读
本文以sql-server-samples仓库中 Laravel 示例所携带的nikic/php-parser依赖自带的官方升级文档(UPGRADE-1.0.md)为主体,系统讲解 PHP-Parser 从 0.9 升级到 1.0 时涉及的全部破坏性变更:PHP 运行版本要求、类名从下划线命名迁移到命名空间、Node::getType()返回值的大规模重命名,以及PrettyPrinterAbstract::pStmts()输出行为的变化。读完本文,你将掌握 1.0 时代的类名与类型命名规则,能够在不破坏自定义 Pretty Printer 与节点遍历逻辑的前提下完成迁移,并理解这些规则在源码(lib/PhpParser目录)中的落地方式。
说明:
php-parser在仓库中作为 Laravel 示例应用的第三方依赖被 vendored 于 samples/development-frameworks/laravel/vendor/nikic/php-parser(PHP 7 + Laravel 5.1 的 SQL Server todo 看板示例,见 laravel/README.md)。该目录同时包含UPGRADE-2.0.md与CHANGELOG.md,可作为继续追踪后续版本的参考。
一、升级背景:0.9 → 1.0 的核心变化脉络
PHP-Parser 1.0 是一次语义化大版本升级,包含多处破坏性变更。升级文档将其归纳为四个方面:
- PHP 运行版本要求提高:运行 PHP-Parser 需要 PHP 5.3+,但解析 PHP 5.2 源码的能力被保留;
- 类名全面命名空间化:
PHPParser_前缀迁移为PhpParser\命名空间,旧名称保留为别名; - 节点类型输出调整:
Node::getType()的返回字符串随类重命名而改变; - 杂项行为变更:移除
Template/TemplateLoader,调整pStmts()的前导换行输出。
从仓库的 composer.json 可以看到,1.x 时代库已经全面采用 PSR-4 自动加载:
"autoload": { "psr-4": { "PhpParser\\": "lib/PhpParser" } }这与文档中"迁移到命名空间化名称"的描述完全对应:lib/PhpParser目录下的所有类文件,均以PhpParser\为命名空间前缀。
二、PHP 版本要求:运行环境与解析能力的分离
升级文档明确指出:
PHP-Parser now requires PHP 5.3 or newer to run. It is however still possible toparsePHP 5.2 source code, while running on a newer version.
即:
- 运行要求:执行 PHP-Parser 本身需要 PHP 5.3 及以上;
- 解析能力:只要运行在较新版本上,仍然可以解析 PHP 5.2 时代的源码。
这意味着"解析器的运行环境"与"被解析代码的语法版本"是两个独立维度。1.0 的Lexer\Emulative正是这种兼容能力的实现载体——它通过模拟旧版词法行为来解析旧语法(后续版本中该 Lexer 继续承担向后兼容的职责)。仓库目录 lib/PhpParser/Lexer 下的 Emulative 实现即是证据。
同时,composer.json 中的依赖声明也从侧面印证了运行要求:
"require": { "php": ">=5.4", "ext-tokenizer": "*" }注意:仓库中 vendored 的这份 composer.json 声明的是
>=5.4(对应 2.x 的branch-alias显示该版本已进入 2.0 开发线),而本文所讲的 1.0 升级文档写于要求PHP 5.3+的时期。若你的环境同时涉及 1.x 与 2.x,请以对应版本的实际声明为准。
三、命名空间化迁移:从下划线前缀到PhpParser\
3.1 新旧类名对照
升级文档给出了最直接的代码迁移示例。
旧写法(0.9,仍然可用,但不推荐):
$parser = new \PHPParser_Parser(new \PHPParser_Lexer_Emulative); $prettyPrinter = new \PHPParser_PrettyPrinter_Default;新写法(1.0):
$parser = new \PhpParser\Parser(new PhpParser\Lexer\Emulative); $prettyPrinter = new \PhpParser\PrettyPrinter\Standard;对应关系可以概括为:
| 0.9(下划线风格) | 1.0(命名空间风格) |
|---|---|
PHPParser_Parser | PhpParser\Parser |
PHPParser_Lexer_Emulative | PhpParser\Lexer\Emulative |
PHPParser_PrettyPrinter_Default | PhpParser\PrettyPrinter\Standard |
上述新类在仓库中均有对应实现文件:lib/PhpParser/Parser.php、lib/PhpParser/Lexer/Emulative.php(目录形式)、lib/PhpParser/PrettyPrinter/Standard.php。
3.2 命名空间迁移的三个关键细节
(1)旧名称以别名形式保留。文档明确说明:"the old names using underscores are still available as aliases, as such most code should continue running on the new version without further changes." 因此升级后大多数既有代码可以原样运行,但官方建议尽快迁移到新名称。
(2)大小写敏感性问题。文档特别警告:PHP 类名在技术上不区分大小写,但自动加载器无法加载PHPParser\Parser或其他大小写变体。前缀由PHPParser变为PhpParser后,必须严格按新大小写书写,否则 PSR-4 自动加载将无法匹配到lib/PhpParser下的文件。
(3)保留关键字冲突导致类名尾下划线。由于与 PHP 保留关键字冲突,部分类名现在以尾下划线结尾,例如:
- 旧:
PHPParser_Node_Stmt_Class - 新:
PhpParser\Node\Stmt\Class_
(旧名称依然保留可用。)这一规则在仓库目录中可以直接验证:lib/PhpParser/Node/Stmt 下存在Class_.php、Trait_.php、If_.php、For_.php、While_.php、Break_.php、Continue_.php、Echo_.php、Switch_.php、Catch_.php、Case_.php、Use_.php、Const_.php、Global_.php、Static_.php、Return_.php、Throw_.php、TryCatch.php、Function_.php、Interface_.php、Namespace_.php等文件——凡是与关键字冲突的节点类,文件名都带尾下划线。
四、Node::getType()输出变化:理解规则再应对重命名
4.1 输出规则与源码实现
Node::getType()的返回格式在 1.0 中保持了下划线风格(而不是命名空间风格),且不包含类名中可能存在的尾下划线。因此对于未移动、未改名的节点类,输出与 0.9 完全一致。
仓库中的实现位于 lib/PhpParser/NodeAbstract.php:
public function getType() { return strtr(substr(rtrim(get_class($this), '_'), 15), '\\', '_'); }这一行代码完整解释了输出规则:
get_class($this)得到完整类名,例如PhpParser\Node\Stmt\Class_;rtrim(..., '_')去掉尾部可能存在的下划线(对应"不含尾下划线"的约定);substr(..., 15)截掉前 15 个字符,即PhpParser\Node\前缀;strtr(..., '\\', '_')将剩余命名空间分隔符\替换为_。
于是PhpParser\Node\Stmt\Class_的getType()返回Stmt_Class,与 0.9 一致。对于PhpParser\Node\Expr\AssignOp\Plus(Node\Expr\同样为 15 个字符),返回Expr_AssignOp_Plus。
4.2 受影响的完整重命名映射表
由于部分节点类被移动了命名空间或改名,getType()输出发生变化。升级文档给出的映射如下,升级文档与迁移代码时应逐条核对:
赋值运算节点(Expr_AssignXxx→Expr_AssignOp_Xxx):
Expr_AssignBitwiseAnd => Expr_AssignOp_BitwiseAnd Expr_AssignBitwiseOr => Expr_AssignOp_BitwiseOr Expr_AssignBitwiseXor => Expr_AssignOp_BitwiseXor Expr_AssignConcat => Expr_AssignOp_Concat Expr_AssignDiv => Expr_AssignOp_Div Expr_AssignMinus => Expr_AssignOp_Minus Expr_AssignMod => Expr_AssignOp_Mod Expr_AssignMul => Expr_AssignOp_Mul Expr_AssignPlus => Expr_AssignOp_Plus Expr_AssignShiftLeft => Expr_AssignOp_ShiftLeft Expr_AssignShiftRight => Expr_AssignOp_ShiftRight二元运算节点(Expr_Xxx→Expr_BinaryOp_Xxx):
Expr_BitwiseAnd => Expr_BinaryOp_BitwiseAnd Expr_BitwiseOr => Expr_BinaryOp_BitwiseOr Expr_BitwiseXor => Expr_BinaryOp_BitwiseXor Expr_BooleanAnd => Expr_BinaryOp_BooleanAnd Expr_BooleanOr => Expr_BinaryOp_BooleanOr Expr_Concat => Expr_BinaryOp_Concat Expr_Div => Expr_BinaryOp_Div Expr_Equal => Expr_BinaryOp_Equal Expr_Greater => Expr_BinaryOp_Greater Expr_GreaterOrEqual => Expr_BinaryOp_GreaterOrEqual Expr_Identical => Expr_BinaryOp_Identical Expr_LogicalAnd => Expr_BinaryOp_LogicalAnd Expr_LogicalOr => Expr_BinaryOp_LogicalOr Expr_LogicalXor => Expr_BinaryOp_LogicalXor Expr_Minus => Expr_BinaryOp_Minus Expr_Mod => Expr_BinaryOp_Mod Expr_Mul => Expr_BinaryOp_Mul Expr_NotEqual => Expr_BinaryOp_NotEqual Expr_NotIdentical => Expr_BinaryOp_NotIdentical Expr_Plus => Expr_BinaryOp_Plus Expr_ShiftLeft => Expr_BinaryOp_ShiftLeft Expr_ShiftRight => Expr_BinaryOp_ShiftRight Expr_Smaller => Expr_BinaryOp_Smaller Expr_SmallerOrEqual => Expr_BinaryOp_SmallerOrEqual魔术常量节点(Scalar_XxxConst→Scalar_MagicConst_Xxx):
Scalar_ClassConst => Scalar_MagicConst_Class Scalar_DirConst => Scalar_MagicConst_Dir Scalar_FileConst => Scalar_MagicConst_File Scalar_FuncConst => Scalar_MagicConst_Function Scalar_LineConst => Scalar_MagicConst_Line Scalar_MethodConst => Scalar_MagicConst_Method Scalar_NSConst => Scalar_MagicConst_Namespace Scalar_TraitConst => Scalar_MagicConst_Trait这些新类型的类文件在仓库中同样可以找到:lib/PhpParser/Node/Expr/AssignOp 目录下包含BitwiseAnd.php、BitwiseOr.php、BitwiseXor.php、Concat.php、Div.php、Minus.php、Mod.php、Mul.php、Plus.php、ShiftLeft.php、ShiftRight.php(以及 2.0 新增的Pow.php);lib/PhpParser/Node/Expr/BinaryOp 目录则对应二元运算节点;Scalar_MagicConst_*类位于 lib/PhpParser/Node/Scalar 下。
4.3 影响范围:谁需要关注这些变化
文档明确指出,这些变化会影响:
- 自定义 Pretty Printer(
pXxx()方法按getType()动态分派,见 PrettyPrinterAbstract.php 中$this->{'p' . $node->getType()}($node)的调用方式); - 将
Node::getType()返回值与特定字符串比较的代码(例如switch ($node->getType())或基于类型的条件分支)。
如果你在 0.9 时代针对Expr_AssignPlus、Expr_BitwiseAnd、Scalar_ClassConst等类型写了分支逻辑,升级 1.0 后必须同步更新字符串。
五、其他破坏性变更:模板类移除与 PrettyPrinter 换行行为
5.1Template与TemplateLoader被移除
升级文档说明:Template和TemplateLoader两个类已被移除,建议改用其他基于 PHP-Parser 构建的代码生成(code generation)项目。也就是说,任何依赖这两个类做模板化代码生成的代码,在 1.0 中都无法继续使用,需要替换实现方案。
5.2pStmts()输出前导换行
PrettyPrinterAbstract::pStmts()的行为发生变化:当语句列表非空时,现在会在开头输出一个前导换行符。自定义 Pretty Printer 应删除调用pStmts()前显式添加的换行。
文档给出的示例(pStmt_Trait的实现,即 trait 语句的打印方法):
旧写法(0.9):
public function pStmt_Trait(PHPParser_Node_Stmt_Trait $node) { return 'trait ' . $node->name . "\n" . '{' . "\n" . $this->pStmts($node->stmts) . "\n" . '}'; }新写法(1.0):
public function pStmt_Trait(Stmt\Trait_ $node) { return 'trait ' . $node->name . "\n" . '{' . $this->pStmts($node->stmts) . "\n" . '}'; }新旧代码的差异非常直观:新版中删除了'{'与pStmts()之间的"\n",因为pStmts()自身已经会输出前导换行(注意示例同时展示了 3.2 节提到的类名变化:PHPParser_Node_Stmt_Trait→Stmt\Trait_)。
源码实现与文档描述完全吻合,见 lib/PhpParser/PrettyPrinterAbstract.php:
protected function pStmts(array $nodes, $indent = true) { $result = ''; foreach ($nodes as $node) { $result .= "\n" . $this->pComments($node->getAttribute('comments', array())) . $this->p($node) . ($node instanceof Expr ? ';' : ''); } // ... }可以看到,每个语句在拼接时都以"\n"开头,这正是"语句列表非空时输出前导换行"的实现基础(该实现还顺带展示了注释打印与表达式分号补全的细节,可作为阅读 Pretty Printer 的切入点)。
六、升级检查清单
综合升级文档与仓库源码,从 0.9 迁移到 1.0 时建议按以下清单逐项核查:
- 运行环境:确认 PHP 版本 ≥ 5.3(参考 composer.json 的
require声明),并确认ext-tokenizer扩展可用; - 类名替换:将
PHPParser_前缀改为PhpParser\,注意大小写必须与 PSR-4 自动加载匹配;与 PHP 关键字冲突的类名(Class、Trait、If、For等)补上尾下划线,或继续使用旧别名; - 类型字符串更新:对照 4.2 节的完整映射表,更新所有与
Node::getType()返回值比较的代码,以及自定义 Pretty Printer 的pXxx()方法名(方法分派依赖getType()); - 模板类替换:移除对已删除的
Template/TemplateLoader的依赖,改用独立的代码生成方案; - 换行处理:删除自定义 Pretty Printer 中调用
pStmts()之前的显式换行,避免输出出现多余空行; - 回归验证:升级后运行解析、遍历与打印的完整测试,重点关注
Expr_AssignOp_*、Expr_BinaryOp_*、Scalar_MagicConst_*三类节点的输出是否符合预期。
完成以上步骤后,你的代码即可平稳运行在 PHP-Parser 1.0 之上;若后续继续向 2.x 迁移,可参考同一目录下的 UPGRADE-2.0.md。
- 示例工程
- 数据库
- 教程
- 后端
【免费下载链接】sql-server-samples
Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for SQL Server, Azure SQL, Azure Synapse, and Azure SQL Edge
相关推荐
PHP-Parser 1.0 升级完全指南:从 0.9 迁移到命名空间时代的 API 变更详解
PHP Parser 1.0 升级完全指南:从 0.9 迁移到命名空间时代的 API 变更详解 本指南以 PHP Parser 官方升级文档 UPGRADE 1
编译器静态分析代码生成RxDB 16.0.0 升级全解析:重命名重构、存储层重写与破坏性变更迁移指南
RxDB 16.0.0 升级全解析:重命名重构、存储层重写与破坏性变更迁移指南 RxDB 16.0.0(Efficiency Redefined)是一个以"内部
数据库NoSQL嵌入式数据库实时数据库Redux-Saga 1.0 迁移指南:v0.16.0 到 v1.0.0 的破坏性变更、API 重命名与新增 Effect 全解析
Redux Saga 1.0 迁移指南:v0.16.0 到 v1.0.0 的破坏性变更、API 重命名与新增 Effect 全解析 本文以 redux saga
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考