在 composer.json 的 scripts 中定义自定义命令(如 "analyse": "phpstan analyse"),即可实现 PHPStan、Psalm 或 PHPCS 的一键检查;需确保对应工具已通过 dev 依赖安装,且命令按需触发而非绑定 post-install-cmd 等自动事件。

直接在 composer.json 的 scripts 里定义命令,就能把 PHPStan、Psalm 或 PHPCS 的检查变成一键操作——不需要额外封装 shell 脚本,也不依赖 CI 环境。
怎么在 composer.json 里注册静态分析命令
Composer 的 scripts 是最轻量的自动化入口。只要工具已通过 composer require --dev 安装,就能直接调用其二进制文件。
- PHPStan:确保已安装
phpstan/phpstan,然后在scripts中加一行"analyse": "phpstan analyse" - Psalm:安装
vimeo/psalm后,用"psalm": "psalm";若项目有配置文件,可加--config=psalm.xml - PHPCS:安装
squizlabs/php_codesniffer后,写成"cs-check": "phpcbf --standard=PSR12 --dry-run src/"(注意:用phpcbf带--dry-run才是检查,phpcs是只报告不修复)
示例片段:
"scripts": {
"analyse": "phpstan analyse",
"psalm": "psalm --config=psalm.xml",
"cs-check": "phpcbf --standard=PSR12 --dry-run src/"
}
之后运行 composer analyse 就等价于手动执行 vendor/bin/phpstan analyse。
为什么 post-install-cmd / post-update-cmd 不适合跑静态分析
这类生命周期脚本会在每次 composer install 或 composer update 后自动触发,但静态分析不是“环境就绪”的必要环节——它耗时、可能失败,且与依赖安装无逻辑耦合。
- 一旦
post-install-cmd里写了phpstan analyse,CI 拉取新依赖时就会卡住或报错,阻断流程 - 本地开发中,开发者只是想装个包,结果被强制跑 30 秒分析,体验断裂
- 真正需要的是「按需触发」,不是「被动强绑」
正确做法是把分析命令单独命名(如 analyse),再由人或 CI 显式调用。
如何让静态分析在 Git 提交前自动检查
靠 Composer 脚本本身做不到自动拦截,必须结合 Git Hook。但可以利用 Composer 统一管理 Hook 调用的命令入口。
- 先在
scripts中定义一个组合命令:"pre-commit-check": "composer cs-check && composer analyse" - 再用
captainhook/captainhook-phar或php-cs-fixer自带的钩子机制,让pre-commit执行composer run pre-commit-check - 注意:PHPCS 和 PHPStan 默认会输出非零退出码(失败时),Git Hook 会据此中止提交
这样既复用了 Composer 脚本的可移植性,又避免了在 .git/hooks/pre-commit 里硬编码路径或版本号。
容易被忽略的路径与 autoloader 问题
PHPStan 和 Psalm 都依赖 vendor/autoload.php 解析类引用,而 PHPCS 不依赖——这点差异直接影响脚本行为。
- 如果
composer install没跑完就执行composer analyse,PHPStan 会报Class 'SomeThirdPartyClass' not found,不是代码问题,是环境缺失 - CI 中常见错误:在
sonar-scanner前没跑composer install,导致 SonarQube 因 autoload 失败而漏检安全规则 -
phpcbf不读 autoload,所以即使vendor/为空也能跑,但会错过基于命名空间的规则(如fully_qualified_strict_types)
所有静态分析脚本都应默认假设 vendor/autoload.php 已就绪;若要支持无 vendor 场景,得显式传 --autoload-file= 参数(PHPStan 支持,Psalm 不支持)。











