phpstan更适合快速落地和ci轻量检查,psalm类型推导更强但配置维护成本高;两者不兼容,不可随意切换;phpstan依赖显式paths扫描而非autoloader,需手动配置app/、lib/等路径;psalm开启allowphpstormgenerics会增强泛型校验但增加报错与耗时。

PHPStan 更适合快速落地和 CI 轻量检查,Psalm 类型推导更强但配置和维护成本高;两者不兼容,别在已有配置的项目里随意切换。
PHPStan 报 “Call to an undefined method” 却方法明明存在
这不是代码写错了,是 PHPStan 没扫描到类定义路径。它不依赖 Composer autoloader,而是靠 AST 解析 + 显式声明的 paths 列表来定位类。
- 检查
phpstan.neon中是否漏了实际存放类的目录,比如app/Models、lib/或packages/*/src - 别指望
autoload-dev能让 PHPStan 找到类——它压根不走 autoloader - PSR-4 映射名和真实目录名不一致(如
App\Helpers\→helpers/)时,PHPStan 会跳过,老老实实按物理路径写进paths - 常见错误现象:Laravel 项目里
phpstan analyse总报 Eloquent 关系方法未定义,本质就是没把app/加进paths
Psalm 开启 allowPhpStormGenerics 后报错暴增
这个开关一开,Psalm 就开始认真校验 PhpStorm 风格的 PHPDoc 泛型注解,比如 @param array<string user></string> 或 @return Collection<post></post>。不是你写错了,是它终于“睁眼”了。
- 默认关闭;打开前务必先跑
psalm --init生成 baseline,否则历史问题直接卡死 CI - 开启后分析耗时增加 15%~30%,尤其在大量使用
Illuminate\Support\LazyCollection的 Laravel 项目中明显 -
array<int string></int>和list<string></string>在 Psalm v5+ 语义不同:list要求键连续从 0 开始,混用会触发InvalidReturnType - 只在团队统一用 PhpStorm + PHPDoc 泛型时启用,否则纯属自找麻烦
新项目该选 PHPStan 还是 Psalm?
新项目起步优先用 phpstan/phpstan + --level max,稳;强类型诉求(如重构 legacy、写 SDK)再引入 vimeo/psalm。
- PHPStan 配置轻量(NEON)、上手快、CI 友好,对 Laravel 黑魔法(Eloquent、中间件)识别较好
- Psalm 类型推导更细,支持条件类型、污点分析、自动修复,但 XML 配置重、学习曲线陡
- 如果项目里已有
phpstan.neon或psalm.xml,别轻易换——迁移成本远超预期,且两者无法共存 - 都用
composer require --dev安装,别用全局 PHAR,CI 中易出版本漂移
CI 中 PHPStan / Psalm 跑得太慢或内存溢出
静态分析不是越严越好,CI 环境要平衡精度与效率。默认全量扫描在大项目里很容易超时或 OOM。
- 限制线程数:
phpstan analyse --threads=2(GitHub Actions 默认只有 2 核) - 优化 autoload:CI 中禁用 dev autoloader,避免加载测试辅助类干扰分析
- 用精简配置:CI 不必跑 full level,可用
--level=5或基于 baseline 的增量检查 - Psalm 可用 Docker 镜像加速:
docker run -v $PWD:/app --rm -it ghcr.io/danog/psalm:latest /composer/vendor/bin/psalm --no-cache
最常被忽略的一点:类型分析工具的价值不在“报多少错”,而在“你是否理解每个报错背后的类型契约”。一个 mixed 提示背后可能是缺失的 PHPDoc,也可能是设计上本就不该动态构造类型——这时候该改代码,而不是加 ignoreErrors。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











