PHP 7.4 迁移至 PHP 8.3 应首选 PHPStan(v1.12+)进行静态检测,因其能提前发现类型不匹配、动态属性、联合类型误用等 php -l 完全无法识别的关键兼容性问题。

直接上结论:PHP 7.4 迁移到 PHP 8.3,phpstan 是当前最可靠、覆盖最全的静态检测工具,比 php -l 或 psalm 更早暴露类型不匹配、动态属性、联合类型误用等关键问题。
为什么不用 php -l 就开始迁移?
php -l 只校验语法是否合法,对 PHP 8.3 的兼容性陷阱完全无感。比如以下代码在 PHP 7.4 能跑,在 8.3 会运行时报错,但 php -l 仍显示“Syntax OK”:
function getValue(): string|int { return null; }这类联合类型中漏掉 ?null 或返回值越界的问题,必须靠静态分析才能提前揪出。
-
php -l不检查类型声明是否自洽(如string|int是否允许null) - 不识别已被移除的函数(如
create_function()在 8.3 已彻底消失) - 无法发现动态属性赋值(
$obj->foo = 'bar'在 8.3 触发弃用警告,但语法无错)
PHPStan 安装与最低可用配置
别跳过这步——默认安装的 phpstan/phpstan 是基础版,对 PHP 8.3 特性支持不完整。必须指定版本:
立即学习“PHP免费学习笔记(深入)”;
composer require --dev phpstan/phpstan:^1.12
然后创建 phpstan.neon(项目根目录),内容至少包含:
parameters:
level: 5
paths:
- src/
- tests/
inferPrivatePropertyTypeFromConstructor: true
checkDynamicProperties: true-
level: 5是迁移起点:能捕获mb_strpos第三个参数为 float、json_encode对 NaN 处理变更等典型 8.0+ 问题 -
checkDynamicProperties: true强制检测未声明属性赋值,对应 PHP 8.3 的弃用警告 - 若项目含大量
__call或魔术方法,加reportMagicMethods: false避免误报(但需人工复查)
常见报错对照表:看到这些就该改代码
PHPStan 输出不是噪音,每条都对应一个真实运行风险。重点盯住这几类:
-
Parameter #3 $offset of function mb_strpos expects int, float given→ 检查所有mb_strpos(..., ..., round(...)),统一加(int)强转 -
Call to function create_function() will always result in an error→ 替换为fn()箭头函数或function() use (...),注意闭包变量捕获 -
Access to undefined property User::$email→ 类没声明$email属性,要么补声明public ?string $email;,要么加#[AllowDynamicProperties]注解(仅限遗留模型) -
PHPDoc tag @return with type string|int is not subtype of native type string|int|null→ 函数声明了string|int但实际返回了null,必须改成string|int|null或加判空逻辑
别忽略 php.ini 和扩展的隐性影响
PHPStan 跑得再准,也检测不到扩展缺失导致的运行时失败。PHP 8.3 中以下扩展行为已变:
-
redis扩展 5.3.6 不支持 PHP 8.3(需升至 5.3.7+ 或改用pecl/redis开发版) -
igbinary3.2.14 与 8.3 不兼容,会导致unserialize()崩溃,必须升级到 3.4.0+ - 即使
php -m显示mbstring已加载,也要确认mbstring.func_overload在 php.ini 中设为0(PHP 8.3 默认禁用该选项,旧配置可能残留)
最易被跳过的点:PHPStan 不报错,但项目一启动就 Fatal error: Uncaught Error: Class "Redis" not found——因为扩展根本没加载成功,而不是代码写错了。



















