### [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 让它成为合门禁。** 下面按这条线走一遍可复用的流程。

## 一、安装与基础命令
推荐**项目级局部安装**,避免全局版本冲突:
```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教程
---