最稳路径是 Git pre-commit 钩子 + Composer 脚本 + 本地 php-cs-fixer;必须用 composer run cs-fix(而非裸命令),因跨平台兼容与 PATH 注入依赖 Composer 封装;.php-cs-fixer.php 文件名和 setFinder() 调用不可省略,否则扫描失效;--dry-run 加 @php 前缀和 CI 的 set -e 是阻断不合规提交的三大关键。

直接说结论:靠 Git pre-commit 钩子 + Composer 脚本 + 本地安装的 php-cs-fixer,是当前 PHP 项目落地代码规范最稳的路径;任何跳过 composer.json 脚本封装、依赖全局命令或省略配置文件的做法,CI 或新成员拉代码时必挂。
pre-commit 钩子里为什么必须调用 composer run cs-fix 而不是直接跑 php-cs-fixer
因为 php-cs-fixer 命令在不同环境不一定能被识别:
- CI 环境默认不把
vendor/bin加进PATH,裸写php-cs-fixer会报command not found - Windows 下
vendor\bin\php-cs-fixer.bat和 Linux 的vendor/bin/php-cs-fixer路径不兼容,硬编码路径会跨平台失效 - Composer 脚本执行时自动将
vendor/bin注入子进程PATH,所以composer run cs-fix在所有系统都能命中本地二进制 - 脚本名
cs-fix可统一加参数,比如"cs-fix": "php-cs-fixer fix --verbose",无需每次改钩子脚本
.php-cs-fixer.php 文件名和内容格式稍错就静默失效
这个文件不是可选配置,而是强制生效前提:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 文件名必须是
.php-cs-fixer.php(开头带点,不是php-cs-fixer.php,也不是.php-cs-fixer.dist.php) - 内容必须返回
PhpCsFixer\Config实例,不能是数组或 JSON 字符串 -
setFinder()必须显式调用,否则只扫描当前目录,src/、tests/全被忽略 - 必须写
exclude('vendor')和ignoreVCS(true),否则扫描.git目录可能卡死 - 规则键名大小写敏感:
'@PSR12' => true有效,'psr12' => true会被跳过且不报错
为什么 composer validate 不能替代 php-cs-fixer 校验 PHP 代码
这是常见误解:composer validate 只检查 composer.json 本身,和你的 PHP 文件完全无关:
-
composer validate --strict会校验 JSON 语法、字段语义(如name格式、autoload路径是否存在),但对src/Controller.php里的空格、括号、命名零感知 -
php-cs-fixer专治 PHP 代码格式问题(缩进、空格、数组语法),但它不查语义错误(比如变量名是否符合 PSR-1) - 真要卡住不合规提交,得两者共存:
pre-commit先跑composer validate --strict --no-check-publish,再跑composer run cs-fix --dry-run -
--dry-run是关键——它不改文件,只报错并返回非零退出码,Git 钩子才能中止提交
CI 中 composer run 默认吞掉子命令退出码,导致校验形同虚设
这是最隐蔽也最致命的问题:哪怕 php-cs-fixer --dry-run 找出 20 处格式错误,composer run cs-check 仍可能返回 0,CI 就算通过了:
- 根本原因:Composer 脚本默认不透传子进程退出码,错误被“吃掉”
- 修复方式:脚本定义必须加
@php前缀,例如"cs-check": "@php vendor/bin/php-cs-fixer fix --dry-run --diff" - Windows 用户注意:
$@不生效,得用%*,跨平台项目建议统一用 shell 包装脚本(如bin/cs-check) - CI 配置里务必加
set -e(Bash)或启用fail-fast: true(GitHub Actions),否则后续步骤照常执行
真正难的不是让工具跑起来,而是确保 .php-cs-fixer.php 的 setFinder() 没漏目录、composer.json 里脚本命令前加了 @php、CI 的 shell 环境里开了 set -e——这三个点任一遗漏,规范就只是文档里的一行字。

















