本文目录导读:

PHP 框架升级(如从 Laravel 6 到 10,或 ThinkPHP 5.0 到 6.0)是一项高风险、高回报的系统维护工作,规划不当可能导致业务中断数周甚至回滚失败。
以下是一套经过实战检验的 PHP 框架升级四阶段规划法,从评估到上线可逐步落地。
第一阶段:评估与锁定(1-2天)
目标:摸清家底,制定“升还是不升”的决策。
-
Why(为什么要升?)
- 必要升级:当前框架版本已停止安全支持(EOL,如 PHP 7.4 已停更、Laravel 6 已停更)。这是最硬性的理由。
- 非必要升级:为了新特性(如枚举、Laravel 10 的 Native Type Declarations),如果代码老旧且没有安全风险,可暂缓。
-
What(依赖清单)
- 运行
composer show -i确认 PHP 版本(升级框架常需要高版本 PHP)。 - 列出所有 第三方包(扩展包)。
- 逐一检查每个包的 Upgrade Guide,看它们是否兼容目标框架版本。
- 重点:找到卡脖子的包(如过时的支付SDK、短信包),这往往是升级的主要工作量。
- 运行
-
Roadmap(版本跳跃策略)
- 不跨大版本:例如从 Laravel 5.5 到 10,绝不能直接跳,必须按
5 -> 6.x -> 7.x -> 8.x -> 9.x -> 10.x逐步升级,或至少按官方支持的“一步升级版”来跳(如 Laravel 8 可以直接跳到 9,但 8 不能直接跳到 10)。 - 推荐路径:先升级到当前大版本的最新小版本(如 5.5.48),再升级到下个大版本。
- 不跨大版本:例如从 Laravel 5.5 到 10,绝不能直接跳,必须按
第二阶段:代码与兼容性分析(核心耗时阶段)
目标:编写“缺陷清单”,明确需要改动的代码范围。
-
使用静态分析工具辅助扫描
- PHPStan / Psalm 设定
level max,它能发现废弃方法、类型错误。 - Rector:自动升级神器,它可以自动执行框架的大量重构(如
array_转短语法,替换废弃类),在升级前跑一次 Rector,能自动修复 60%-80% 的兼容性问题。
- PHPStan / Psalm 设定
-
重点关注(框架升级中改动最大的部分):
- 废弃方法/类:如 Laravel 6 中废弃的
$request->only()行为变化,Laravel 7 中 Blade 的 转义规则。 - 配置文件结构变化:如 ThinkPHP 的
config.php格式变化,Laravel 的Auth配置路径变更。 - Facades 与 Eloquent 变动:如
Carbon 2的默认时区变化,或者Model的$dates属性被移除需替换为$casts。 - 核心服务变化:如
自定义异常处理接口改名,Queue驱动逻辑变动。
- 废弃方法/类:如 Laravel 6 中废弃的
-
模拟升级环境
- 不建议直接在旧项目上
composer update。 - 必须在 Git 新分支或本地 Docker 环境中操作。
- 不建议直接在旧项目上
第三阶段:分步实施与测试(迭代验证)
目标:让新版本代码在测试环境中跑通所有业务逻辑。
建议策略:分模块、小步快跑
-
锁定中间版本
- 先升级到本大版本最新版(如旧版 5.5 -> 5.5.48)。
- 安装新框架包:
composer require laravel/framework:^6.0 --with-all-dependencies(注意:这会开始报错,需要逐条修复)。
-
灰度测试:创建“升级分支”
git checkout -b upgrade/laravel-7- 强制保持主分支不动,所有修改在升级分支上。
-
批量修复规则
- 第一遍:自动修复(Rector 跑一遍)。
- 第二遍:手动修改弃用方法、配置、数据库(如
created_at字段格式变化引发的序列化问题)。 - 第三遍:修复第三方包冲突(可能需
--ignore-platform-req临时跳过,但最终要解决)。
-
CI/CD 测试
- 在本地跑
php artisan test(单元测试)。 - 必须覆盖:API 接口返回结构、数据库 CRUD、支付回调、定时任务。
- 特别注意:验证 Session/Cookie 机制是否变化(新版框架加密密钥要求变化)。
- 在本地跑
第四阶段:灰度发布与监控回滚
目标:在生产环境中平滑切换,且能不中断服务地回滚。
-
线上灰度
- 全量切换太危险,先用 10% 的流量 指向升级后的服务器组。
- 或者:在 负载均衡器 上设置
Cookie-Based Routing,让指定 IP(如测试人员、小部分用户)先体验新版本。
-
监控重点
- 日志监控:PHP Warning、Error(特别是弃用 Deprecated)。
- 性能监控:新版框架是否更慢?注意 Laravel 9+ 的编译性能变化。
- 业务报警:支付成功率、用户登录次数、接口响应时间曲线。
-
回滚策略
- 代码回滚:直接
git checkout旧分支并部署。 - 数据库回滚:这是最关键的,如果在升级过程中运行了
php artisan migrate导致数据库字段变化,数据库可能无法直接回滚。 - 保险做法:升级期间,数据库结构不做破坏性修改(如只加字段,不删字段、不改字段类型),这样代码回滚后数据库也能兼容。
- 代码回滚:直接
关键风险点与避坑指南
| 风险点 | 表现 | 解决方案 |
|---|---|---|
| PHP 版本不兼容 | composer install 报错 |
先升级服务器 PHP 版本(如 4 -> 8.1),再升级框架,两者不要在同一次发布中做。 |
| 数据库字段变化 | 旧代码对 created_at 是字符串,新框架是 Carbon 对象 |
在中转版本中统一 $casts,不要直接删除旧数据表结构。 |
| 第三方包停维护 | 发现支付包不支持新版 Laravel | 要么自己 fork 改包(要求高),要么更换包(需重写业务逻辑)。这是升级的最大阻力,建议把它作为升级决策的依据之一。 |
| 缓存/序列化问题 | Redis 中缓存了旧对象,新版反序列化失败 | 升级后建议 清空所有 Cache 和 Session(或者设置缓存 key 前缀增加版本号)。 |
一套可直接复用的升级计划模板
Day 1:评估
- 确定目标版本(如
Laravel 8 -> Laravel 10)。- 检查 PHP 版本要求(需 8.1+)。
- 列出所有第三方包并确认兼容性。
Day 2-3:代码重构
- 创建分支
upgrade/laravel10。- 安装新框架及依赖,修复废弃方法。
- 更新配置文件(尤其
.env变量)。- 修改测试用例(单元测试)。
Day 4:测试
- 跑完整 CI pipeline。
- 手动测试核心流程(登录、支付、订单状态流转)。
- 进行性能压测(线上压力测试)。
Day 5:灰度发布
- 发布至预发布环境。
- 执行平滑灰度(10% 流量)。
- 监控 Log、Error Rate。
Day 6:全量 + 观察
- 若灰度无问题,全量切换。
- 保留回滚能力 24 小时。
最后一句建议:如果项目极度复杂(如共存几十个第三方包且多数不再更新),且没有安全漏洞要求,建议不要强行追求最新版本——稳定胜过一切,升级不是为了“潮流”,而是为了安全和持续集成能力。