### [PHP_CodeSniffer 定制团队规则并集成 CI:从 ruleset.xml 到 GitHub Actions / GitLab CI 的完整落地](https://www.huociguo.com/article/180) **Published:** 2026-07-18T14:31:26 **Author:** 米了 **Excerpt:** PHP_CodeSniffer(下称 PHPCS)是 PHP 生态里事实标准的代码风格校验工具,内置 PSR-12、PSR-2、PEAR、Squiz 等规范。但在团队项目中,直接套 PSR-12 往往太严(旧代码报一堆 MissingNam PHP\_CodeSniffer(下称 PHPCS)是 PHP 生态里事实标准的代码风格校验工具,内置 PSR-12、PSR-2、PEAR、Squiz 等规范。但在团队项目中,直接套 PSR-12 往往太严(旧代码报一堆 `MissingNamespace`、`MultiLineFunctionDeclaration`),太松又失去约束意义。**可行的做法是:以 PSR-12 为底座,用** `ruleset.xml` **做减法 + 微调参数,再把** `phpcs.xml` **纳入仓库、接入 CI 让它成为合门禁。**​ 下面按这条线走一遍可复用的流程。 ![](https://api.huociguo.com/wp-content/uploads/2026/07/d3bbeeb139afe-1814873996-1.png "d3bbeeb139afe-1814873996-1") ## 一、安装与基础命令 推荐**项目级局部安装**,避免全局版本冲突: ```bash composer require --dev squizlabs/php_codesniffer ``` 安装后二进制位于 `vendor/bin/phpcs`(Linux/macOS)与 `vendor/bin/phpcbf`(自动修复)。快速验证: ```bash ./vendor/bin/phpcs --version ./vendor/bin/phpcs --standard=PSR12 src/ ``` `phpcbf` 是同包附带的自动修复工具,能修掉 `phpcs` 输出中标 `[x]` 的那类问题(缩进、换行、空格等格式级违规)。 ## 二、phpcs.xml 与 ruleset.xml 的关系(关键点) PHPCS 启动时**会自动在当前目录及向上递归查找**​ `phpcs.xml` 或 `phpcs.xml.dist`,找到就用它当 `--standard`,无需再手动指定。因此团队项目的常规做法是: - `phpcs.xml`​ —— 放仓库里,提交,包含所有路径、排除、参数,**CI 和本地都直接用** - `phpcs.xml.dist`​ —— 作为”分发模板”,个人可复制成 `phpcs.xml` 覆写局部路径,不改 `.dist` 原版 两者语法完全一致,都是 ruleset 格式。`ruleset.xml` 这个名字更多出现在**自定义标准包**(比如你自己写一个 `MyStandard/ruleset.xml` 然后通过 `installed_paths` 注册)的场景。 > 💡 很多团队踩过的坑:命令行写了一长串 `--ignore=*/vendor/* --standard=PSR12`,换个人机器就忘了参数。把规则固化成 `phpcs.xml` 进版本库是唯一可持续的做法。 ## 三、定制 ruleset:在 PSR-12 上做”减法 + 调参” 下面是一份**可直接落地的团队规则样例**,兼顾新项目约束与老项目迁移: ```xml 团队 PHP 规范,基于 PSR-12 裁剪 0 */vendor/* */node_modules/* */tests/* */storage/* ``` 这套样例中几个决策点: - `0`​ 等价于禁用该 rule,比 `` 更灵活(exclude 是按 name 剔子项,severity=0 是整条规则静音) - **property 调参**​ 是 PHPCS 定制最被低估的能力——同一条 `ScopeIndent`,4 空格团队和 2 空格团队用的就是 `indent` 这一个值 - `` 在 ruleset 层生效,比命令行 `--ignore` 更稳定,因为 CI 不会因为某人忘了传 `--ignore` 而扫 vendor 把上述内容存为项目根目录的 `phpcs.xml`,之后本地直接: ```bash ./vendor/bin/phpcs src/ ./vendor/bin/phpcbf src/ # 能自动修的部分直接修 ``` ## 四、Composer 脚本再包一层(可选但推荐) 在 `composer.json` 里加两段脚本,让团队成员用统一入口: ```json { "scripts": { "cs:check": "phpcs --extensions=php --report=full src/ tests/", "cs:fix": "phpcbf --extensions=php src/ tests/" } } ``` 之后 `composer cs:check` / `composer cs:fix` 即可,新人不用记路径。 ## 五、集成 GitHub Actions **推荐走”裸跑 vendor/bin/phpcs”而不是第三方 action**——少一个依赖,行为更可控。工作流文件 `.github/workflows/phpcs.yml`: ```yaml name: PHPCS Check on: push: branches: [main] pull_request: branches: [main] jobs: phpcs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' tools: composer - name: Install dependencies run: composer install --no-progress --prefer-dist --optimize-autoloader - name: Run PHPCS run: ./vendor/bin/phpcs ``` 要点: - 根目录已有 `phpcs.xml`,所以 `./vendor/bin/phpcs` 后面**不必再写** `--standard`,它会自动读取 - 如果想只在 PR 里跑**变更文件**,可以在 `checkout` 加 `fetch-depth: 0`,然后用 `git diff --name-only ... | grep '\.php$' | xargs ./vendor/bin/phpcs`,或改用 `navarr/phpcs-action@v3` 配 `only_changed_files: true` - 报错即 `exit code 1` → PR 红,天然形成门禁 * * * ## 六、集成 GitLab CI `.gitlab-ci.yml` 里加一段 `php_cs` job 即可: ```yaml php_cs: stage: test image: php:8.1-cli script: - composer install --no-progress --prefer-dist - ./vendor/bin/phpcs rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH == "main"' ``` 如果项目是 Drupal / WordPress 这类已有专属标准的,把 `--standard` 换成 `Drupal,DrupalPractice` 或 `WordPress` 即可,ruleset 仍可通过 `phpcs.xml` 覆写。 ## 七、常见 | | | | | --- | --- | --- | | 现象 | 原因 | 处理 | | 自定义 standard 报”not found” | `installed_paths` 没注册 | `./vendor/bin/phpcs --config-set installed_paths /path/to/MyStandard` 或在 composer.json 里引 `dealerdirect/phpcodesniffer-composer-installer` 自动处理 | | ruleset 里 property 不生效 | 拼错 sniff 名 / property 名 | 用 `./vendor/bin/phpcs -s` 看每条报错归属的 sniff 全称再对 | | CI 过本地不过 / 反之 | 两端 PHPCS 版本不一致 | composer.lock 锁版本,CI 里走 `composer install` 而非全局 phpcs | | 老项目一次性全量修不动 | 规则太激进 | 先用 severity=0 静音,分模块逐个开启;或先用 `phpcbf` 修格式类,再补语义类 | ## 落地节奏建议 1. **第一天**:仓库里丢一份 `phpcs.xml`,继承 PSR-12,exclude-pattern 把 vendor/tests 挡掉,全量扫一次看基线 2. **第一周**:按报错 Top 10 决定哪些 rule 用 severity=0 静音、哪些 property 要调(缩进/数组语法/方法签名换行最常见) 3. **第二周**:GitHub Actions / GitLab CI 挂上,仅 `main` 分支 + MR 触发,失败不阻塞(观察期) 4. **一个月后**:规则稳定,MR 门禁切为 `fail on error`,新代码强制合规,老代码渐进修 > 📌 规则文件本身也是代码,建议每半年由一两人 review 一次 `phpcs.xml`——团队规模变了、PHP 版本升了(比如上 8.2/8.3 的新语法),规则也得跟着动。 **Tags:** PHP **Categories:** PHP教程 ---