php 8.4 将此前 deprecated 行为升级为硬性报错:create_function() 被彻底移除,子类重声明父类 readonly 属性触发 fatal error,mixed/never 不再隐式接受 null,str_contains() 不能无脑替代 mb_strpos(),且 clone 含 readonly 属性对象直接抛 error。

PHP 8.4 本身不引入“破坏性变更”作为新特性,而是把此前已标记为 @deprecated 的行为升级为硬性报错——真正要规避的,是那些在 PHP 8.3 中还能跑、但在 8.4 中直接 Fatal error 的代码模式。
create_function() 调用必须彻底删除
这不是警告,是函数被物理移除。任何残留调用都会触发 Fatal error: Uncaught Error: Call to undefined function create_function()。
- 常见位置:旧版模板引擎(如 Smarty 2.x)、动态排序回调(
usort($arr, create_function(...)))、第三方 SDK 初始化钩子 - 替换方案优先级:匿名函数
fn($a, $b) => $a["id"] - $b["id"]> 普通闭包function($a, $b) { return ...; }> 绝对避免eval() - 注意:PHP 7.4+ 支持箭头函数,但若需兼容更低版本,用
function声明更稳妥
只读属性继承必须重构
子类重声明父类 readonly 属性会立即报错:Fatal error: Cannot redeclare readonly property,且无法通过反射绕过。
- 错误写法示例:
class Child extends Parent { public readonly int $name; }(即使类型不同也不行) - 正确做法:父类提供
get方法供子类读取;如需扩展状态,改用组合(private $data+ 方法封装)而非继承属性 - 构造函数中不能对继承来的
readonly属性二次赋值,哪怕只是想“重置”
mixed/never 类型不再隐式接受 null
声明为 function foo(mixed $x): never 时,传入 null 将触发 TypeError,而不再是静默转换。
- 影响范围:Laravel 辅助函数(如
Arr::get()返回mixed)、自定义验证器、DTO 构造参数 - 修复方式:显式写成
mixed|null,或在调用前做is_null()判断 - 静态分析工具(如 PHPStan level 9 +
phpVersion: '8.4')能提前捕获这类问题,仅靠php -l无法发现
str_contains() 不能无脑替代 strpos()
str_contains() 是字节级比较,不处理多字节边界。混用 mb_* 函数的旧逻辑直接替换会出错。
- 典型陷阱:原用
mb_strpos($str, '用户') !== false判断中文,换成str_contains($str, '用户')后可能漏匹配 - 安全做法:统一用
mb_strpos($str, $needle) !== false,或确保所有输入已标准化为 UTF-8 且不含 BOM - 注意:
str_contains('', '')返回true,与strpos('', '') === 0行为一致,这点无需调整
最易被忽略的是克隆含 readonly 属性的对象——PHP 8.4 会直接抛 Error,而不是静默失败。如果项目依赖 clone 做浅拷贝,必须改用工厂方法或手动复制构造逻辑。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











