<p>PHP 8.4 升级到 8.5 的兼容性问题集中在四方面:createfunction() 和 each() 被彻底移除、可空类型必须用 ?string 而非 string|null、动态属性默认禁止需显式声明或加 #[AllowDynamicProperties]、mysql* 函数及部分扩展失效需替换为 PDO/mysqli 并更新 zval 访问方式。</p>

PHP 8.4 升级到 8.5 的兼容性问题集中在函数移除、类型语法收紧、动态属性限制和扩展依赖变更四方面。这不是渐进式调整,而是多个“警告变致命”的硬性切断,必须逐项检查并修复,否则代码会直接崩溃。
被彻底移除的函数调用会立即报错
create_function() 和 each() 在 PHP 8.5 中已完全消失,不是弃用,是删除。任何调用都会触发 Fatal error:
-
create_function():常见于老模板引擎、回调注册或动态逻辑拼接。必须替换为匿名函数,优先用短闭包
fn($a) => $a * 2;传统写法function($a) { return $a * 2; }也可用,但更冗长。 -
each():基本只出现在
while (list(,$v) = each($arr))这类老式遍历中。统一改为foreach ($arr as $v)或foreach ($arr as $k => $v),语义清晰且无风险。 - 注意:有些代码把
create_function()当作简易 eval 使用,这本身存在严重安全风险,升级正好强制清理掉这类隐患。
可空类型语法必须显式声明
PHP 8.5 禁止在联合类型中混用 string|null 写法,哪怕它语义等价。以下写法在 8.4 可能仅警告,但在 8.5 直接 TypeError:
- 错误示例:
function greet(string|null $name): string - 正确写法:
function greet(?string $name): string - 同理,
int|null→?int,array|null→?array - 如果函数参数本就允许 null 却没加
?(如function log(string $msg)),传入null会立刻崩,不再静默转为空字符串。
动态属性默认禁止,类需明确定义
未在类中声明的属性赋值,比如 $user->nickname = 'abc',在 PHP 8.5 中默认触发 Fatal error:
立即学习“PHP免费学习笔记(深入)”;
- 最稳妥做法:在类里提前定义,如
public string $nickname;或public ?string $nickname; - 若确需保留动态行为(例如从 JSON 构建 DTO),可在类上加
#[AllowDynamicProperties]属性,但仅限必要场景,不建议泛滥使用。 - 注意:该限制与
declare(strict_types=1)无关,是独立的运行时校验。
扩展与底层依赖必须同步更新
mysql_* 函数彻底不可用,PDO 或 mysqli 是唯一合法路径;同时部分第三方扩展(尤其自研或老旧 C 扩展)可能因 zval 结构变化或 Zend API 调整而编译失败或运行异常:
- 检查 php.ini,删掉所有
extension=mysql.so或extension=php_mysql.dll行,否则 PHP 启动失败。 - 确认项目封装类(如
Db::query())底层没偷偷调用 mysql_* —— 很多老封装只是套壳,内核仍是废弃函数。 - 自研扩展需重跑
phpize && ./configure && make,重点检查是否还在直接访问zval.value.lval等旧字段,应改用Z_LVAL(zv)等标准宏。 - Laravel 等框架需确认版本:Laravel 11.x 是目前唯一明确适配 PHP 8.5 的主版本;10.x 及更早版本可能出现类型推断异常或扩展加载失败。



















