PHP 8.5 升级指南 了解即将废弃的 11 个功能和完整迁移方案
PHP 8.5 计划于 2025 年 11 月 20 日发布,带来了新功能、语法改进,当然还有废弃功能。废弃就是告诉你某些语言特性、函数或行为要在未来版本(通常是 PHP 9.0)中被移除或变得更严格。早点升级能避免代码出问题,保持兼容性,也能让你用上更现代、更安全的 PHP。
这篇文章我会讲:
- PHP 8.5 中的主要废弃功能
- 现有代码可能出现的问题
- 替代/替换策略
- 你可以遵循的迁移路线图
原文链接-PHP 8.5 升级指南 了解即将废弃的 11 个功能和完整迁移方案
PHP 8.5 中被废弃的功能
以下是 PHP 8.5 中最重要的一些废弃功能,主要来源于 PHP RFCs 和变更日志。
__sleep()
和 __wakeup()
魔术方法
这些方法不能用了。改用 __serialize()
和 __unserialize()
。
非标准的类型转换/标量转换名称
用 integer
、double
、boolean
、binary
这些转换名称不行了。要用标准形式:int
、float
、bool
、string
。
使用反引号(`)作为 shell_exec() 的别名
反引号语法执行 shell 命令不能用了。换成 shell_exec()
。
在 array_key_exists() 中使用 null 作为数组偏移
传 null
作为键不行了。要传有效的键类型。
常量重复声明
同一个常量定义多次不行了。
某些 INI 指令的废弃
以下指令被废弃或移除:
report_memleaks
register_argc_argv
(在 HTTP-SAPI 中)disable_classes
标准库函数的 null 参数
给 readdir()
、rewinddir()
、closedir()
这些函数传 null
作为目录句柄不行了。
资源关闭/释放函数
手动关闭函数不能用了,现在资源都是对象,由析构函数自动处理。比如:
finfo_close()
xml_parser_free()
curl_close()
curl_share_close()
imagedestroy()
MHASH_* 常量
老的 MHASH_*
常量不能用了。改用现代哈希 API(hash()
、openssl
)。
用户输出处理器返回非字符串
自定义输出缓冲处理器必须返回字符串。返回其他类型不行了。
从自定义输出缓冲处理器中发出输出
在自定义输出处理器里面直接输出内容不行了。
还有一些与边界情况下魔术方法相关的废弃,以及对 Directory 类的更改(例如,不允许 new Directory()
,没有动态属性,不能克隆,不能序列化)。
你的代码可能出现的问题
废弃功能本身一般不会马上让代码挂掉——PHP 先会给你警告。但有些废弃功能会导致错误或不兼容,特别是:
- 你开了严格的
error_reporting
或自定义错误处理器,把废弃当成错误处理 - 你升级到 PHP 9.0 时,废弃功能直接被删掉了
- 第三方库/插件在用废弃功能
容易踩坑的地方:
- 用了
__sleep()
/__wakeup()
的序列化逻辑,或者序列化的对象需要这些魔术方法 - 老代码里用了非标准类型名称(比如
boolean
而不是bool
)做转换 - 用反引号语法跑 shell 命令的代码——这个经常被忽略
- 代码里有
array_key_exists(null, $array)
这种写法,或者给目录操作传 null 句柄 - 自定义缓冲/输出处理器会输出或者期望非字符串数据
- 用了
MHASH_*
常量的代码。老代码库或老包里经常有 - Directory 对象上加动态属性,或者用
new Directory()
而不是dir()
等
替换和替代策略
每个废弃功能怎么替换,看下面:
__sleep()
/ __wakeup()
改用 __serialize()
和 __unserialize()
。这俩更靠谱,向前兼容。如果要处理老的序列化数据,写个适配器支持两种格式。
非标准转换(integer、double、boolean、binary)
换成标准类型转换:int
、float
、bool
、string
。在代码库里搜索替换。PHPStan 或 Psalm 这些静态分析工具能帮你找出剩下的非标准转换。
反引号别名 shell_exec()
把反引号(`command`
)换成 shell_exec('command')
。这样更清楚、更安全,也能避免注入问题。
数组偏移中的 null(array_key_exists())
要传有效的键。如果键可能是 null,先处理一下:
- 检查存在用
isset()
- 检查对象属性用
property_exists()
常量重复声明
常量只定义一次。
- 把重复的声明合并
- 用命名空间来组织常量
- 别条件性重复声明,除非真的需要
废弃的 INI 指令
从 php.ini 或 .user.ini 里删掉这些过时的指令:
report_memleaks
register_argc_argv
(HTTP-SAPI)disable_classes
确保你的应用不再依赖这些设置。
资源释放/关闭函数
让析构函数自动处理清理,别手动调用:
finfo_close()
xml_parser_free()
curl_close()
curl_share_close()
imagedestroy()
如果真的要手动释放,先检查对象是否有效,或者用更新的 API。
MHASH 常量
把老的 MHASH_*
常量换成现代哈希 API:
hash()
hash_hmac()
password_hash()
openssl_*()
函数
这样更安全,也向前兼容。
输出缓冲处理器
更新自定义输出处理器:
- 必须返回字符串
- 别在处理器里面直接输出。这样能保证各个 PHP 版本行为一致
Directory 类更改
别直接用 new Directory()
。改用 dir()
。
- 删掉动态属性赋值
- 别克隆或序列化 Directory 对象
- 检查代码库里的用法,该重构的重构
迁移路线图:如何安全升级
升级代码库(特别是中型/大型/老项目)到 PHP 8.5 不出问题,需要好好规划。实用路线图:
摸底
用静态分析工具(PHPStan、Psalm、PhpDepend)找废弃用法。
搜索这些模式:__sleep
、__wakeup
、反引号、非标准转换、MHASH_*
等。
也要检查配置(php.ini)、自定义错误处理器、输出缓冲代码等。
开废弃警告
在开发/测试环境里,把 error_reporting
设成包含 E_DEPRECATED
和 E_WARNING
。
可以的话,把废弃当成要记录的事(或者让 CI 失败)来早点发现问题。
写兼容代码
序列化方面:如果要支持老的序列化数据,写个适配器同时支持 __sleep
风格和新方法。
老库用了废弃常量或行为的,考虑包装一下或者打个补丁。
一点点重构
从风险小的地方开始,比如小工具函数、内部代码、不重要的功能。
- 换掉非标准类型转换
- 删掉反引号用法
- 换成新的哈希函数
好好测试
用单元测试和集成测试。确保行为(特别是序列化、输出缓冲、目录操作)还是对的。
测试还要验证新版本里不会有错误/废弃通知。
测试/预生产环境升 PHP 8.5
代码清理完了,在测试环境部署 PHP 8.5,开完整错误报告。盯着有没有新问题。
看日志,有问题就修。
为 PHP 9 做准备
8.5 里废弃的功能,9.0 里通常就直接删了,所以要确保代码向前兼容。
关注 PHP 9.0 的 RFCs。
更新依赖
很多第三方库可能也在用废弃功能。看看有没有支持 8.5 的库/框架新版本。
有些依赖如果被废弃了,可能要换掉。
需要注意的事项/陷阱
序列化格式兼容性:如果你用 __sleep/__wakeup
序列化过数据,存在会话、缓存、数据库里,你得处理反序列化这种格式。
魔术方法行为变化:一些边界行为(回退、返回 null)现在可能会警告;如果你的代码依赖这些,可能会收到警告或者行为变化。
动态属性:内置类(比如 Directory)或者删了 #[\AllowDynamicProperties]
的类,运行时加新属性现在可能会失败或警告。
INI 设置副作用:删掉废弃的 INI 指令可能会改变行为(比如 register_argc_argv
),特别是 CLI vs HTTP 环境,或者跟某些第三方工具一起用的时候。
性能和错误噪音:如果用了很多废弃功能,开启废弃通知可能会刷屏日志。要想好怎么管理或者抑制(但别忽略)这些警告。
示例:重构一段代码
这里有一个具体的小例子。假设我们有:
<?phpclass Legacy {public function __sleep(): array{// 清理或关闭逻辑return ['prop1', 'prop2'];}public function __wakeup(){// 重新初始化资源}public function run(){echo `ls -la`; // 使用反引号$val = (double) $this->someValue;}
}
重构后:
<?phpclass Modern {public function __serialize(): array{// 清理或关闭逻辑return ['prop1' => $this->prop1, 'prop2' => $this->prop2];}public function __unserialize(array $data): void{$this->prop1 = $data['prop1'];$this->prop2 = $data['prop2'];// 重新初始化资源}public function run(){echo shell_exec('ls -la'); // 使用 shell_exec$val = (float) $this->someValue; // 使用标准转换}
}
总结
- PHP 8.5 废弃的功能挺多,也很有针对性:魔术方法改了、类型转换标准化了、目录/资源处理更安全了、老常量废弃了等等
- 很多不会马上让代码挂掉,但会警告,升级到 PHP 9.0 时可能就真挂了
- 早点开始:在开发/测试环境开
E_DEPRECATED
,看看哪里需要改 - 用新的替换废弃功能(比如
__serialize()
、标准类型、新库函数) - 更新依赖。用现代 PHP 功能让代码更干净、更安全、更好维护
升级到 PHP 8.5 不只是为了新功能——也是清理老代码的毛病、减少技术债、为以后做准备。有个靠谱的迁移计划,能减少麻烦,代码也会更精简、更强大。