上个月把服务器的PHP从7.4升级到了8.5,本以为是个简单的版本升级,结果踩了一堆坑。前后折腾了一周才稳定下来。记录一下这次升级过程中遇到的问题和解决方案,给要升级的同学提个醒。
为什么要升级
先说一下为什么要升级。我们用的PHP7.4已经停止官方维护了,安全更新也停了。而且PHP8.x在性能上有明显提升,JIT、命名参数、联合类型、枚举这些新特性也确实好用。
本来计划是先升到8.1,稳定后再往上升。但既然要升,干脆一步到位,直接上8.5。现在想想,这个决定有点冲动了。
坑一:废弃函数一大堆
升级完第一件事,日志里全是Deprecated警告。数了一下,大大小小有二十多处。
1. curl_close() 被废弃
这个最意外。从PHP8.0开始,curl资源就变成了对象,由GC自动回收,curl_close()已经没有实际作用了。到8.5直接标记为废弃。
解决方案:把所有curl_close($ch)改成unset($ch)。虽然不写也没事,但写了更规范。
2. imagedestroy() 被废弃
和curl_close一样的道理,GD资源在PHP8.0之后也变成了对象。这个影响比较大,因为我们图片处理的地方挺多的。
解决方案:封装了一个gd_free()函数,PHP7.x调用imagedestroy,PHP8.x直接跳过。
3. 其他废弃函数
还有一些零散的,比如strftime()、each()、create_function()这些,都是老代码里的。逐个替换成对应的新函数。
坑二:unserialize() 报错
升级后缓存系统频繁报错:
Warning: unserialize(): Error at offset 0 of 1 bytes
查了半天,发现是缓存文件的问题。PHP7.4的时候,有些缓存数据序列化后存文件,读取的时候unserialize。但升级到8.5后,原来的序列化数据格式有细微变化,导致反序列化失败。
解决方案:unserialize的时候加@抑制警告,失败就重新生成缓存。同时把缓存格式改成了JSON,更通用也更安全。
坑三:类型严格化
PHP8.x对类型的要求严格了很多。以前能跑的代码,升级后直接报错。
1. 隐式类型转换变严格
比如把字符串传给int类型的参数,PHP7.4会自动转换,PHP8.x直接报TypeError。我们有几处数据库查询的参数传了字符串类型的数字,全部要改成(int)强转。
2. 算术运算类型检查
PHP8.0开始,对数组、资源做算术运算会抛TypeError。以前有个地方不小心把数组当数字加了,PHP7.4默默给了个结果,PHP8.x直接炸了。
3. 可选参数之前不能有必填参数
这个在PHP8.0就废弃了,8.5直接报错。有几个老函数的参数顺序写得不对,必填参数跟在可选参数后面,全部要调整。
坑四:第三方库不兼容
这个是最头疼的。我们用了一些第三方库,有些已经不维护了,升级PHP后直接报错。
比如一个老的PDF生成库,用了很多PHP4风格的构造函数(和类名同名的方法),PHP8.x已经完全不支持了。找了一圈替代品,花了两天时间替换。
还有一个邮件库,用了preg_replace的/e修饰符,PHP7就已经废弃了,8.5直接移除了。改成preg_replace_callback搞定。
建议:升级前先把所有第三方库列出来,确认每个库都支持目标PHP版本。不支持的,提前找好替代品。
坑五:性能反而下降了
升级完发现,有些接口的响应时间反而变长了。查了半天,发现是OPcache的配置问题。
PHP8.5的OPcache默认配置和7.4不太一样,我们沿用了老的配置,导致缓存命中率很低。重新调整了opcache.memory_consumption、opcache.max_accelerated_files、opcache.validate_timestamps这些参数后,性能才上来。
另外,PHP8.x的JIT默认是关闭的,需要手动开启。对于计算密集型的任务,JIT提升很明显。但我们是Web应用,JIT的提升不大,反而可能增加内存占用,最后没开。
坑六:错误处理变化
PHP8.x把很多以前的Warning改成了Error。比如未定义数组下标,PHP7.4是Notice,PHP8.x直接是Warning,而且默认会显示。
我们有几处代码直接访问可能不存在的数组下标,比如$arr['key'],如果key不存在,PHP7.4默默给个null,PHP8.x会报警告。虽然不影响功能,但日志里全是警告,看着难受。
解决方案:全部改成$arr['key'] ?? '',或者用array_key_exists先判断。
升级建议
总结一下这次升级的经验:
1. 不要跨大版本直接升
从7.4直接升到8.5,跨度太大,问题集中爆发。建议7.4→8.0→8.1→8.2→8.5逐步升级,每个版本稳定运行一段时间再升下一个。
2. 先在测试环境跑通
一定要有测试环境,把所有功能测一遍再上生产。我们就是测试环境没测全,上线后才发现一些边缘功能有问题。
3. 打开所有错误报告
升级前把error_reporting开到E_ALL,把所有警告、通知都修掉。不要带着警告升级,不然升级后全是报错。
4. 准备好回滚方案
万一升级出问题,要能快速回滚。我们是用的多版本PHP共存,出问题直接切回7.4,几分钟就能恢复。
5. 关注官方升级指南
PHP官方的迁移指南写得很详细,每个版本的不兼容变更都列出来了。升级前一定要通读一遍。
写在最后
虽然踩了这么多坑,但升级到PHP8.5还是值得的。性能提升明显,代码质量也因为类型严格化而提高了不少。
技术升级就是这样,过程痛苦,但熬过去之后,系统会更健康。不要因为怕踩坑就不升级,一直用老版本,技术债只会越积越多。
当然,也不要像我一样脑子一热就跨大版本直接升。稳一点,慢一点,比什么都强。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录