不改代码,90%的老项目在PHP 8下无法启动或关键路径崩溃;主因是函数签名强制类型校验、mysql_*等函数彻底移除、错误升级为TypeError、扩展ABI不兼容(如redis.so需5.3.0+)及静默逻辑变更(如==行为收紧、mbstring默认编码改为UTF-8)。

PHP 7 升级到 PHP 8 不是版本号一换就完事,而是会触发大量运行时错误、语法拒绝、扩展失效和逻辑静默变更。不改代码,90% 的老项目在 PHP 8 下无法启动或关键路径崩溃。
函数签名与内置行为变严格
PHP 8 强化类型系统,很多内置函数从“宽松接受”变成“强制校验”,传错类型直接抛 Fatal error: Uncaught TypeError:
-
array_key_exists('id', $_GET):若$_GET被 unset 或为字符串,会崩;需加判断is_array($_GET) -
json_decode($str, 1):第二个参数必须是true或false,不能传1;全量替换为json_decode($str, true) -
preg_replace(..., -1):$limit不再支持负数;依赖-1表示“全部替换”的逻辑,要改用-1替换为PREG_REPLACE_MAXLEN或改写正则逻辑 -
strlen(null)、mb_strlen(null):PHP 7 返回0或警告,PHP 8 直接报错;所有外部输入(如$_POST、数据库字段)调用前先判空或默认值
废弃函数与语法被彻底移除
这些不是警告,是直接 Call to undefined function 或 Parse error,必须手动替换:
-
mysql_*系列:已从 PHP 7.0 开始废弃,PHP 8 彻底删除;统一迁移到mysqli或PDO,注意连接对象传递和错误处理方式变化 -
create_function():全部改为匿名函数function($a, $b) { return $a + $b; }或 PHP 7.4+ 的短闭包fn($a, $b) => $a + $b -
each():用foreach替代;若需键值分离逻辑,改用key()/current()/next() - 花括号下标
$str{0}:语法级报错;一律改为$str[0] -
assert('1+1==2'):字符串参数被禁用;改为assert(1 + 1 === 2),确保传布尔表达式
扩展与第三方依赖不兼容
即使函数名还在,扩展本身可能因 ABI 不匹配而加载失败或类找不到:
立即学习“PHP免费学习笔记(深入)”;
-
redis.so:PHP 7.4 的扩展不能直接用于 PHP 8;ABI ID 是20200930,必须重装 Redis 扩展 5.3.0+ 版本 -
gd.so、curl.so等:检查是否启用,用php -m | grep gd验证;GD 需 2.3.0+,否则图像处理报错 - 框架版本卡点:ThinkPHP 5.1 及以下、Laravel 7 及以下、Symfony 5.x 默认不支持 PHP 8;升级前确认框架文档明确标注 “PHP 8 supported”
- Composer 依赖:运行
composer check-platform-reqs,并设置"platform": {"php": "8.1"}锁定平台版本,避免装入旧版不兼容包
静默逻辑变更与类型陷阱
这类问题不会立即报错,但会让业务逻辑“悄悄走偏”,最难排查:
-
match表达式:严格比较,'1' !== 1;若原switch依赖松散匹配(比如解析 JSON 数字字符串),需显式转换:match ((string)$x) { ... } - 弱比较
==行为收紧:'123a' == 123在 PHP 7 返回true,PHP 8 返回false;权限、状态码等松散比对场景务必改用===或filter_var($x, FILTER_VALIDATE_INT) - 返回类型声明报错:
function getId(): int若实际返回null,PHP 7 是 warning,PHP 8 是TypeError;ORM 模型中未设默认值的字段访问器要补?? 0或改用联合类型: int|null -
mbstring默认编码从ISO-8859-1改为UTF-8;中文乱码、mb_strlen()计数异常,需统一确认mb_internal_encoding('UTF-8')显式设置



















