PHP项目CI环境下PHPStan与Psalm报错本地无异常的调试求助
解决CI环境下PHPStan与Psalm持续失败的实战方案
先说说Psalm报的ReflectionUnionType::getName()未定义错误——虽然你说代码里没写显式的联合类型(比如int|float),但这个问题大概率和环境差异或者依赖缓存有关:
- PHP版本坑:
ReflectionUnionType是PHP 8.0才有的类,但它根本没有getName()方法!正确的调用应该是getTypes()来获取类型数组。Psalm的PHAR包可能在CI的PHP版本下触发了错误的代码分支:- 先查CI环境的PHP版本:如果是8.0+,那可能是Psalm旧版本PHAR的兼容性bug;如果CI用的是低于8.0的PHP,那
ReflectionUnionType本身都不该存在,说明Psalm加载了错误的反射逻辑。
- 先查CI环境的PHP版本:如果是8.0+,那可能是Psalm旧版本PHAR的兼容性bug;如果CI用的是低于8.0的PHP,那
- CI缓存搞事情:GitHub Actions的vendor目录或PHAR包可能缓存了旧文件,试试在CI脚本里加清理步骤:
rm -rf vendor/psalm composer clear-cache composer install --no-cache - 隐藏的联合类型:说不定是第三方依赖、注解工具或者动态生成的代码里有联合类型?本地和CI的依赖安装可能有差异,比如CI用了
--no-dev而本地没开?可以在CI里跑个命令看看加载的类:php -r "var_dump(get_declared_classes());"
再看PHPStan的报错——找不到规则类的数组key,还有getUseStatements()返回null,这基本是依赖冲突或者PHAR包损坏导致的:
- PHAR包换源码安装:PHPStan的PHAR包里内置的Nette Utils版本可能和你项目依赖的版本打架,试试放弃PHAR,直接用composer装源码版:
composer require --dev phpstan/phpstan --update-with-all-dependencies - 强制刷新CI缓存:GitHub Actions的缓存可能存了损坏的PHAR文件,改改CI.yml,强制重新下载最新的工具包:
# 替换原来的PHAR安装步骤 - name: 安装PHPStan run: curl -O https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar && chmod +x phpstan.phar - name: 安装Psalm run: curl -O https://github.com/vimeo/psalm/releases/latest/download/psalm.phar && chmod +x psalm.phar - 检查规则配置:看看你的
phpstan.neon或者phpstan.dist.neon里有没有引用DuplicateKeysInLiteralArraysRule?如果这个规则在当前PHPStan版本里被删了或者改名了,就会加载失败,先注释掉试试。
最后,既然本地没问题CI有问题,核心就是让CI和本地环境完全对齐:
- 锁死依赖版本:在
composer.json里给PHPStan、Psalm这些工具指定精确版本,比如:
避免CI自动装最新版本搞出差异。"require-dev": { "phpstan/phpstan": "1.10.32", "vimeo/psalm": "5.15.0" } - 同步PHP环境:对比本地和CI的PHP版本、扩展列表——比如CI用PHP 8.1,你本地是8.2,或者CI少装了某个扩展,都可能导致反射行为不一样。
- 抄本地命令:CI里完全照搬你本地运行的命令,比如本地用
./vendor/bin/psalm,CI也别用PHAR,直接跑vendor里的脚本。 - 开调试模式:在CI里跑工具时加
-vvv参数,看看详细日志:- Psalm:
./vendor/bin/psalm -vvv,能看到它加载了哪些类、处理了哪些文件 - PHPStan:
./vendor/bin/phpstan analyse -vvv,可以追踪规则加载的过程
- Psalm:
这类CI独有的问题,90%以上都是环境不对或者缓存坑,先对齐环境、清缓存、换源码安装,基本能解决。如果还是不行,就在CI里输出php -i的信息,和本地对比找差异。
内容的提问来源于stack exchange,提问作者Mirko Pagliai
相关产品推荐
相关产品推荐

