关于 php-upgrade
面向 PHP 应用维护者的升级技能,指导按版本顺序逐步升级。流程包括查阅迁移指南、兼容性审计、自动化代码修改、更新依赖和测试。
主要功能
- 01逐个 PHP 版本升级
- 02查阅官方迁移指南
- 03审计兼容性与依赖
- 04使用 Rector 执行代码转换
- 05部署前测试与验证
适用场景
- 01规划 PHP 小版本升级
- 02查找不兼容代码和扩展
- 03自动更新代码并检查回归问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ krzysztofsurdy/ code-virtuoso --skill php-upgrade安装后在 Claude Code 中输入/php-upgrade确认已加载。
附带文件references/upgrade-process.md
详细介绍
PHP 版本升级
每次只升级一个次版本,绝不跳过版本。每个步骤都会暴露在下一个版本中会变成错误的弃用项。每次升级都遵循相同的周期:审查、自动化、测试、部署。
核心原则
| 原则 | 含义 |
|---|---|
| 先看变更日志 | 每次升级前,获取该次升级对应的官方 php.net 迁移指南。切勿依赖此技能中的静态列表或模型记忆 |
| 一次升级一个版本 | 按顺序从 8.2 -> 8.3 -> 8.4 -> 8.5 升级。跳过版本会导致无法隔离问题 |
| 升级前修复弃用项 | N 版本中的弃用项会在 N+1 版本中变成错误,因此必须修复 |
| 先自动化,再手动处理 | 手动修改代码前,先运行 Rector 和 PHPCompatibility。它们能捕获 80% 以上的必要更改 |
| 用测试证明升级成功 | 只有目标版本上的测试套件通过,升级才算完成 |
| 固定平台版本 | 在 composer.json 中设置 config.platform.php,使其与最低部署目标一致 |
升级流程概览
阶段 0:阅读迁移指南
修改任何代码前,阅读当前版本到目标版本之间每次升级对应的官方指南。每次升级都有单独的页面,页面名称为目标版本对应的 migrationXY:
| 升级 | 页面 |
|---|---|
| 7.4 -> 8.0 | https://www.php.net/manual/en/migration80.php |
| 8.4 -> 8.5 | https://www.php.net/manual/en/migration85.php |
每份指南都包含子页面:migrationXY.incompatible.php(不向后兼容的更改)、migrationXY.deprecated.php,以及(如果存在)migrationXY.removed-extensions.php。至少阅读前两个。
获取指南的方法:
- 使用
docs-lookup技能。 对于 PHP,它会解析为 Context7 库 ID/websites/php_net_manual_en。查询“从 PHP X.Y 迁移到 PHP X.Z、不向后兼容的更改和弃用的功能” - **备用方法:**直接获取上述 php.net URL,或向用户索要发行说明
- 记录适用项。 在代码库中使用 grep 搜索列出的每个项目,并保留搜索结果,作为自动化和手动修复步骤的工作清单
“按版本列出的已知陷阱”表格可作为 grep 搜索的起点,但不能替代指南。
阶段 1:审查
修改任何代码前,先了解升级的工作量。
- 使用目标版本运行 PHPCompatibility,找出不兼容的代码。最后一个稳定版本(9.3.5,2019 年发布)早于 PHP 8.1,缺少大多数较新的规则。请安装
10.0.0-alpha2或更高版本,该版本包含 PHP 8.x 代码嗅探器,并先阅读其升级说明 - 使用目标 PHP 二进制文件运行 php-parallel-lint,以发现语法错误
- 运行
composer outdated,检查所有依赖项是否支持目标版本 - 对照代码检查阶段 0 中列出的项目
- 检查 PHP 扩展的兼容性(
ext-intl、ext-mbstring等)
阶段 2:自动化
使用 Rector 批量应用代码转换。
// rector.php
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withPaths([__DIR__ . '/src', __DIR__ . '/tests'])
->withPhpSets(php85: true); // adjust to target version
始终先进行试运行:
vendor/bin/rector process --dry-run
检查更改,然后应用:
vendor/bin/rector process
将 Rector 更改与手动修复分别提交,以保持 git 历史整洁。
阶段 3:更新依赖项
- 在
composer.json中更新 PHP 版本约束:"php": ">=8.5" - 更新
config.platform.php,使其与目标版本一致 - 运行
composer update并解决冲突 - 根据需要更新 PHP 扩展
阶段 4:测试和部署
- 在新 PHP 版本下运行完整测试套件
- 运行静态分析(PHPStan/Psalm)
- 部署到预发布环境并验证
- 部署后监控生产日志中的弃用提示
有关工具配置、CI 流水线设置和 Docker 注意事项,请参阅升级流程参考。
工具
| 工具 | 用途 | 使用时机 |
|---|---|---|
| Rector | 基于 AST 的自动代码转换 | 审计后的第一步。处理大多数机械性变更 |
| PHPCompatibility | 用于跨版本兼容性的 PHP_CodeSniffer 规则集 | 审计阶段。在开始前识别所有不兼容代码 |
| php-parallel-lint | 并行语法检查(比串行快约 20 倍) | 审计阶段。捕获新版本下的语法错误 |
| PHPStan/Psalm | 静态分析 | 验证阶段。转换后捕获类型错误 |
| symfony/phpunit-bridge | 在测试输出中汇总弃用项 | 持续进行。跟踪升级期间的弃用项数量 |
各版本间已知陷阱
最容易导致实际升级失败的项目。每一项均摘自对应版本升级路径的 php.net 迁移页面。其他内容请获取完整指南(阶段 0)。
| 升级路径 | 陷阱 |
|---|---|
| 7.4 -> 8.0 | 0 == "abc" 现在结果为 false(数字会转换为字符串)。对数组、资源或对象进行算术运算会抛出 TypeError。@ 不再屏蔽致命错误。读取未定义的变量、键和属性会产生警告。使用未定义的裸常量会抛出 Error。create_function() 和 each() 已移除。. 的优先级现在低于 + 和 - |
| 8.0 -> 8.1 | 向不可为 null 的内置参数传递 null 已弃用。会损失精度的浮点数到整数转换已弃用。未实现 __serialize() 和 __unserialize() 的 Serializable 已弃用。继承的方法与父类共享 static 变量。向 false 追加内容已弃用。写入整个 $GLOBALS 数组会报错 |
| 8.1 -> 8.2 | 动态属性已弃用(请声明属性,或添加 #[\AllowDynamicProperties])。"${var}" 插值已弃用。utf8_encode() 和 utf8_decode() 已弃用。"self::method" 这类可调用对象已弃用。strtolower()、ucfirst() 等函数不再受区域设置影响 |
| 8.2 -> 8.3 | 对空字符串或非字母数字字符串使用 ++ 和 -- 已弃用。不带参数的 get_class() 已弃用。日期扩展错误现在使用 DateError 和 DateException 类型,而不是警告。带有静态属性的 Trait 会重新声明父类的属性。对空数组使用负索引会使下一个键变为 n+1 |
| 8.3 -> 8.4 | 隐式可为 null 的参数(T $x = null)已弃用,请使用 ?T。E_STRICT 以及使用 E_USER_ERROR 的 trigger_error() 已弃用。exit() 会进行类型检查。IMAP、OCI8、PDO_OCI 和 PSpell 已移至 PECL。GMP 为 final。名为 _ 的类已弃用。0 ** -1 已弃用 |
| 8.4 -> 8.5 | Opcache 始终内置,zend_extension=opcache.so 现在会发出警告,因此请从 php.ini 和 Docker 配置中移除它。反引号运算符、(boolean)、(integer)、(double) 和 (binary) 强制转换、null 数组偏移以及 case x; 已弃用。__sleep() 和 __wakeup() 已软弃用。disable_classes INI 已移除。Trait 会在父类之前绑定。将无法容纳在 int 中的浮点数强制转换为 int 现在会发出警告 |
常见陷阱
| 陷阱 | 影响 | 预防措施 |
|---|---|---|
| 跳过版本 | 无法确定哪些更改导致了哪些问题 | 始终一次升级一个版本 |
| 忽略弃用警告 | 弃用功能会在下一个版本中变成致命错误 | 升级前修复所有弃用问题 |
| 不检查依赖项 | 第三方软件包可能不支持目标版本 | 开始前运行 composer outdated 并检查支持情况 |
使用 --ignore-platform-reqs | 绕过安全检查并导致运行时错误 | 绝不要使用。应改为修复实际的约束 |
未锁定 config.platform.php | 本地 PHP 与生产环境不同,导致安装不匹配 | 始终将其设置为与生产环境一致 |
| 大批量运行 Rector 且不审查 | Rector 在边缘情况下可能会进行错误转换 | 始终先试运行、审查更改,并分小批次运行 |
| 忘记 PHP 扩展 | 扩展会改变行为,或在不同版本间被弃用 | 升级前审查所有必需的扩展 |
快速参考:升级检查清单
- 查阅目标版本的 php.net 迁移指南
- 针对目标版本运行 PHPCompatibility 扫描
- 使用目标 PHP 二进制文件运行 php-parallel-lint
- 确认所有 Composer 依赖项都支持目标版本
- 配置并运行 Rector,设置目标版本(先试运行)
- 审查并提交 Rector 的更改
- 为剩余问题应用手动修复
- 更新
composer.json中的 PHP 约束和config.platform.php - 运行
composer update - 在目标 PHP 版本上运行完整测试套件
- 运行静态分析(PHPStan/Psalm)
- 部署到预发布环境并验证
- 部署到生产环境并监控日志
参考文件
| 参考资料 | 内容 |
|---|---|
| 升级流程 | 工具配置、CI 流水线设置、Docker 策略和分步命令 |
与其他技能的集成
| 情况 | 推荐技能 |
|---|---|
| 查找某个版本跳转的迁移指南 | 使用 docs-lookup 技能 |
| 同步升级 Symfony 和 PHP | 使用 frameworks/symfony/ 中的 symfony-upgrade 技能 |
| PHP 升级后更新 Composer 依赖项 | 使用 composer-dependencies 技能 |
| 改进 PHP 代码模式(DTO、枚举、严格类型) | 从 dirnbauer/webconsulting-skills 或 netresearch/php-modernization-skill 安装 php-modernization |
| 升级后运行静态分析 | testing |
评论
支持 Markdown