Composer update 不检测 PHP 8.1+ 协变/逆变兼容性,仅负责依赖安装;真正发现此类问题需依靠 PHPStan Level 8、Psalm —strict 或 PHP 8.1+ 运行时触发,php-compatibility 工具对此无效。

Composer update 本身不检测 PHP 8.x 类型协变兼容性
它只管装包,不管代码能不能跑——composer update 完全不检查你的类方法签名是否违反 PHP 8.1+ 的协变/逆变规则(比如子类重写父类方法时,参数类型变窄、返回类型变宽)。这类错误只有运行时或静态分析时才会暴露,Composer 哪怕装了一堆 PHP 8 兼容的包,也拦不住你代码里藏着 TypeError: Declaration of Child::foo(string $x): int must be compatible with Parent::foo(mixed $x): float。
真正能发现协变问题的三个实操路径
别指望 Composer 自己报错,得靠外部工具主动扫:
-
PHPStan Level 8:它是目前对协变/逆变校验最严格的免费静态分析器。加
--level=8后会明确指出哪些方法签名违反了 PHP 8.1+ 的类型协变规则。配置里必须启用phpVersion: 8.1或更高,否则默认按 PHP 7 解析,直接跳过检查 -
Psalm —strict:比 PHPStan 更早支持协变细节,但需手动开启
allowPhpStormGenerics="true"并在psalm.xml中设置phpVersion="8.1",否则它会把合法的协变写法当成错误 -
PHP 8.1+ 运行时触发:把 CI 的 PHP 版本设为 8.1+,然后跑
vendor/bin/phpunit --no-coverage。一旦测试执行到相关方法,就会立刻抛出Fatal error,错误信息比静态分析更直白,但代价是得等测试跑起来才看到
为什么 php-compatibility 检查器对协变无效
phpcompatibility/php-compatibility 只识别语法级废弃(如 mysql_* 函数、__autoload),它不解析类继承关系,也不校验方法签名的类型兼容性。它能告诉你“PHP 8.1 移除了什么”,但不会告诉你“你写的这个 protected function getData(): array 在继承自 interface HasData { function getData(): iterable; } 时是否合法”——后者才是协变的核心场景。
CI 中必须加守卫层,不能只信 composer update
哪怕 composer update 成功、所有依赖都标着 "php": "^8.2",你的代码仍可能因协变规则崩在第一行 new Child()。CI 脚本里至少要包含:phpstan analyse --level=8 src/ + php -d zend.assertions=1 vendor/bin/phpunit --stop-on-failure。漏掉任意一项,就等于把协变风险留给生产环境去发现。
立即学习“PHP免费学习笔记(深入)”;



















