编程 用 Rector 把 PHP 5.3 项目升到 8.5:它基于 AST,不是查找替换

2026-09-22 21:31:12

用 Rector 把 PHP 5.3 项目升到 8.5:它基于 AST,不是查找替换

Rector 做两件事:Instant Upgrades 和 Automated Refactoring。前者覆盖从 PHP 5.3 到 8.5 的版本升级,也覆盖 Symfony、PHPUnit、Doctrine 等主流开源项目的版本迁移;后者可以接进 CI 做持续重构,压住代码质量。

安装:

composer require rector/rector --dev

使用方式有两种粒度:单条 rule,或者一组 rules,也就是 set。在项目根目录建 rector.php

use Rector\Config\RectorConfig;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector;

return RectorConfig::configure()
->withRules([TypedPropertyFromStrictConstructorRector::class])
->withPreparedSets(deadCode: true, codeQuality: true);

先干跑,看 diff:

vendor/bin/rector src --dry-run

确认无误后去掉 --dry-run 才真正落盘:

vendor/bin/rector src

文档在 ,规则查询在 。调试用 --debug 打印嵌套异常,配合 Xdebug 时加 --xdebug

一个必须先知道的缺点:AST 不管空格

Rector 基于 nikic/php-parser 的 AST。AST 不理解空格,写回文件时格式会乱——PHP 代码和 docblock 都跑不掉。所以团队必须另外配一个编码标准工具来格式化,比如 ECS 或 PHP-CS-Fixer。指望 Rector 输出直接符合团队风格是不现实的。

并行模式在大多数 OS 上可用,Windows 上即使按 Troubleshooting Parallel 的说明处理,也可能撞上解决不了的问题,可以改用 cmd 或 bash(别用 PowerShell 7)。PHP + HTML 混合的文件,应用改动后要人工复核。

社区维护的框架规则包不少:drupal-rectorcraftcms/rectorshopware-rectortypo3-rectordriftingly/rector-laravelcakephp/upgraderector-symfonyrector-phpunitrector-doctrine 等。

集成节奏:别一次上全部规则

官方集成指南()给的做法是渐进的。

第一步只上 1–3 条容易、安全的规则,确认第一个 PR 合并之后再往上加。

升级 PHP 版本时更要小心:composer.json 里写了 php ^7.4,不代表代码真的用上了 7.4 的特性。withPhpSets() 会一次性启用 5.3 / 5.4 / … / 7.4 共 100+ 条规则,太危险。正确做法是一次一个版本:withPhpSets(php53: true) 跑完、合并,第二天改成 php54: true,一步步来。prepared sets 同理,用 withCodeQualityLevel() / withDeadCodeLevel() / withTypeCoverageLevel() 这类分级方法渐进启用,level 从 1 开始。

RectorConfig 常用的方法:

  • withPaths(array)withSkip(array)withRules(array)
  • withPreparedSets(...)withPhpSets(...)
  • withAttributesSets(symfony: true, doctrine: true)
  • withComposerBased(phpunit: true, symfony: true)
  • withPhpLevel(int)
  • withDeadCodeLevel(int)withCodeQualityLevel(int)withCodingStyleLevel(int)withTypeCoverageLevel(int)
  • withPhpVersion(PhpVersion::PHP_82)

CI 里的退出码语义

在 CI 里跑:

vendor/bin/rector --dry-run

如果存在可重构项,命令以退出码 2 结束,可以直接用来实现「有变更即失败」。官方提供 SetupCICommand 生成 CI 工作流配置,模板包括 templates/rector-github-action-check.yamlrector-gitlab-check.yaml

实战:跨版本升级

PHP 8.4 都出了,项目还卡在 7.4,用 SetList::PHP_80 跑一次,构造函数里的赋值模式会被自动识别,改成构造器属性提升(constructor promotion)。跨多个版本升级,链式添加规则集即可。

批量质量重构的场景:一段无类型声明、嵌套 if-else、带未使用私有方法、还在用旧写法 strpos 的老代码,一次启用四套:

return RectorConfig::configure()
->withPaths([__DIR__ . '/src'])
->withSets([SetList::CODE_QUALITY, SetList::DEAD_CODE, SetList::EARLY_RETURN, SetList::TYPE_DECLARATION]);

跑完同一个文件会发生这些变化:构造器属性提升、返回类型声明补上、嵌套 if 改成 early return、未使用的私有方法删除、strpos 换成 str_contains、布尔返回值简化。一次运行,多条规则同时生效。

这里有个规则竞争要注意:同时启用 CODE_QUALITY 时,它里面的 CombineIfRector 可能把同样的嵌套 if 合并成 && 条件,而不是走 early return。两个规则的目标冲突,按团队偏好二选一。

类名和命名空间的全项目重命名基于 AST 替换,不会误伤字符串或注释里的同名内容。

安全实践

  • Rector 基于 AST,先用 dry-run 预览。
  • 务必用版本控制,改动前提交,随时可以回滚。
  • 跨多个大版本(比如 5.6 → 8.1)要逐级升级,不要一步到位。
  • 自动重构只保证语法层面正确,逻辑等价靠单元测试;升级后全量跑测试。
  • 第三方依赖的兼容性取决于库作者,Rector 管不到。
复制全文 生成海报 PHP Rector 代码重构 PHP升级 静态分析 CI

推荐文章

程序员茄子在线接单