PHPStan用composer require --dev phpstan/phpstan安装并自动生成phpstan.neon;Psalm需先composer require --dev vimeo/psalm再运行vendor/bin/psalm --init生成psalm.xml,二者均不建议全局安装且需在配置中明确paths以确保扫描正确目录。

PHPStan 和 Psalm 的安装方式差异
PHPStan 推荐用 composer require --dev phpstan/phpstan 安装,它默认不带配置文件,首次运行会提示生成 phpstan.neon;Psalm 则必须先初始化:composer require --dev vimeo/psalm,再执行 vendor/bin/psalm --init 生成 psalm.xml。两者都不建议全局安装——路径不可控,且 composer scripts 依赖本地 vendor/bin/ 下的可执行文件。
在 composer.json 中定义 scripts 钩子
直接写进 "scripts" 段,避免每次手动敲长命令。注意:Psalm 默认扫描 src/ 和 tests/,PHPStan 默认只扫 src/,若项目结构不同(比如用 lib/ 或 app/),必须在配置文件里改 paths,否则钩子跑出来全是“未扫描到文件”。
{
"scripts": {
"analyse": [
"@phpstan",
"@psalm"
],
"phpstan": "phpstan analyse --no-progress --level=5",
"psalm": "psalm --no-severity-highlighting --show-info=false"
}
}
关键点:
-
--level=5是 PHPStan 的推荐起始等级,太低(如 0)几乎不报错,太高(如 8)可能因类型推导失败误报 - Psalm 的
--show-info=false关闭冗余提示,否则 CI 日志刷屏 - 两个命令都加了
--no-progress/--no-severity-highlighting,避免 ANSI 控制符干扰 CI 环境输出
CI 流水线中调用与退出码处理
GitHub Actions、GitLab CI 等环境里,直接运行 composer analyse 即可。但要注意:PHPStan 和 Psalm 在发现错误时返回非零退出码(1),这是正确行为——CI 会因此中断流程。如果想让 CI 继续运行并汇总结果(比如同时跑 PHPStan + Psalm + PHPUnit),得用 && 连接,或用 || true 强制继续(不推荐,掩盖问题)。
立即学习“PHP免费学习笔记(深入)”;
常见陷阱:
- 没加
--no-interaction,Psalm 初始化后残留交互提示,导致 CI 卡住 - PHPStan 配置里写了
includes:引入了不存在的 neon 文件,直接报错退出,而不是分析失败 - Psalm 的
psalm.xml中errorLevel="1"被误设为"0",等于关闭所有检查
如何让静态分析真正落地而不被绕过
最常被忽略的是「分析范围」和「类型注解覆盖」。PHPStan 对 PHPDoc 类型(如 @param string[] $items)强依赖;Psalm 更进一步,能推导泛型和数组键类型,但前提是代码里有足够注解或 PHP 8.0+ 原生类型。没有注解的函数参数、返回值、属性,两者都会跳过深度检查。
实操建议:
- 先用
phpstan analyse --generate-baseline生成基线,把当前存量问题记下来,后续只报新增问题 - Psalm 可以用
psalm --update-baseline更新基线,但别在 CI 里自动执行,容易把新 bug 当旧债 - 在
composer.json的scripts里加"analyse:strict": "phpstan analyse --level=max"作为阶段性目标,而非默认命令
类型系统不是开关,是渐进过程。配置文件里少一行 paths,或多一个 ignoreErrors,就可能让关键路径彻底失效。











