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