composer cs-fix —— 代码风格修复工具 PHP-CS-Fixer

1. 什么是 PHP-CS-Fixer?

PHP-CS-Fixer 是由 Symfony 创始人 Fabien Potencier 发起的代码风格自动修复工具,是 PHP 生态中最主流的代码风格工具。

这个工具的核心价值在于:不仅检测代码风格问题,还能自动修复它们。在团队协作中,它能有效消除因个人编码习惯差异导致的风格冲突,让开发者把精力集中在业务逻辑而非格式调整上。

PHP-CS-Fixer 内置了丰富的规则集,包括:

  • @PSR12:PHP-FIG 官方推荐的最新编码标准
  • @Symfony:Symfony 框架代码风格
  • @PhpCsFixer:工具自身使用的严格规范
  • @PER-CS:现代化 PHP 编码标准
  • @PHP82Migration:PHP 8.2 迁移规则

2. 适用场景

场景说明
Git Pre-commit Hook提交前自动格式化暂存文件,阻止风格不合规的代码进入仓库
CI/CD 流水线在 Pull Request 中自动检查代码风格,不通过则阻止合并
团队协作统一团队成员的编码风格,消除无意义的格式争论
遗留项目格式化一键格式化整个代码库,快速建立统一标准
IDE 集成在 PhpStorm 等 IDE 中实现保存即格式化

最佳实践:配置分为两个层级——composer cs-check(仅检查,不修改)用于 CI 流程;composer cs-fix(实际修复)用于本地开发。

3. 安装与初始化

3.1 通过 Composer 安装(推荐)

composer require --dev friendsofphp/php-cs-fixer

如果遇到依赖冲突,可以使用官方提供的 Shim 包:

composer require --dev php-cs-fixer/shim

3.2 快速初始化配置

PHP-CS-Fixer 提供了初始化命令,可快速生成基础配置文件:

./vendor/bin/php-cs-fixer init

执行后会生成 .php-cs-fixer.dist.php 文件,包含基础规则和路径配置。

3.3 在 composer.json 中定义脚本

{
    "scripts": {
        "cs-check": "php-cs-fixer check --dry-run",
        "cs-fix": "php-cs-fixer fix"
    }
}

注意:如果选择 Shim 包安装,命令前缀为 php-cs-fixer;如果通过普通 composer 包安装,命令路径为 vendor/bin/php-cs-fixer。建议统一在 composer.json 的 scripts 中封装。

4. 配置文件深度解析

在项目根目录创建 .php-cs-fixer.dist.php 文件,这是推荐的项目级配置,应纳入版本控制。同时可创建 .php-cs-fixer.php 作为本地个性化配置,建议加入 .gitignore。

4.1 基础配置模板

<?php
// .php-cs-fixer.dist.php
declare(strict_types=1);

use PhpCsFixer\Config;
use PhpCsFixer\Finder;

$finder = Finder::create()
    ->in(__DIR__)
    ->exclude(['vendor', 'storage', 'bootstrap/cache', 'node_modules'])
    ->notPath('*.blade.php')
    ->notPath('_ide_*.php');

return (new Config())
    ->setFinder($finder)
    ->setRules([
        // 使用 PSR-12 作为基础标准
        '@PSR12' => true,
        
        // 数组使用短语法 []
        'array_syntax' => ['syntax' => 'short'],
        
        // 移除未使用的 use 语句
        'no_unused_imports' => true,
        
        // 优先使用单引号
        'single_quote' => true,
        
        // 多行数组/参数尾部逗号
        'trailing_comma_in_multiline' => true,
        
        // 类属性按顺序排列(public, protected, private)
        'ordered_class_elements' => true,
        
        // import 语句按字母排序
        'ordered_imports' => ['sort_algorithm' => 'alpha'],
        
        // 严格的类型比较(===)
        'strict_comparison' => true,
    ])
    ->setRiskyAllowed(true)  // 允许可能改变代码行为的规则
    ->setIndent("    ")       // 4个空格缩进
    ->setLineEnding("\n");    // Unix 换行符

4.2 路径精确控制

$finder = Finder::create()
    // 指定要检查的目录
    ->in([
        __DIR__ . '/src',
        __DIR__ . '/tests',
        __DIR__ . '/app',
        __DIR__ . '/config',
        __DIR__ . '/routes',
    ])
    // 排除目录(仅对目录有效)
    ->exclude([
        'src/Legacy',
        'tests/Fixtures',
        'app/Console/Commands/Deprecated'
    ])
    // 排除具体文件(用 notPath)
    ->notPath([
        'src/Config/constants.php',
        'tests/bootstrap.php'
    ])
    // 只检查 .php 文件(默认行为)
    ->name('*.php');

关键点:exclude 只对目录生效,排除单个文件必须使用 notPath,且路径是相对于 in() 设置的路径。

4.3 规则集的组合与覆盖

->setRules([
    // 基础规则集
    '@PSR12' => true,
    '@Symfony' => true,
    
    // 覆盖规则集中的某个规则
    'binary_operator_spaces' => [
        'operators' => [
            '=>' => 'single_space',
            '=' => 'single_space',
        ]
    ],
    'concat_space' => ['spacing' => 'one'],
    
    // 关闭某个规则(即使它在规则集中被启用)
    'align_multiline_comment' => false,
    
    // 开启高风险规则(需 setRiskyAllowed(true))
    'strict_comparison' => true,
    'declare_strict_types' => true,
])
->setRiskyAllowed(true);

常用规则速查表:

规则名作用风险等级
@PSR12PSR-12 全部规则安全
array_syntax短数组语法安全
no_unused_imports移除未使用的 use安全
single_quote单引号优先安全
strict_comparison严格比较 ===/!==中风险
declare_strict_types添加 declare(strict_types=1)中风险
native_function_invocation用原生函数替换高风险
void_return添加 void 返回类型高风险

4.4 使用共享配置

对于多项目团队,可以将配置抽取为独立的 Composer 包,实现统一管理:

composer require --dev your-team/php-coding-standard

然后在项目中引用:

// .php-cs-fixer.dist.php
use YourTeam\CodingStandard\PhpCsFixer\Config;

return Config::get($finder, $customRules);

4.5 自定义缩进和换行符

return (new Config())
    ->setIndent("\t")      // 使用 Tab 缩进
    ->setLineEnding("\r\n") // Windows 换行符
    // ... 其他配置

5. 使用方法

5.1 基础命令

# 检查(仅报告,不修改)
./vendor/bin/php-cs-fixer check --dry-run

# 执行修复
./vendor/bin/php-cs-fixer fix

# 指定配置文件(默认自动检测)
./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php

# 修复特定目录
./vendor/bin/php-cs-fixer fix src/Controller/

5.2 输出示例

执行 ./vendor/bin/php-cs-fixer check --dry-run 的输出:

PHP CS Fixer 3.89.1 Folding Bike by Fabien Potencier, Dariusz Ruminski and contributors.
PHP runtime: 8.4.2
Running analysis on 1 core sequentially.
You can enable parallel runner and speed up the analysis! Please see usage docs for more information.
Loaded config default from "/project/.php-cs-fixer.dist.php".
Using cache file ".php-cs-fixer.cache".
20/20 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

1) tests/Feature/Email/DomainIsNotTest.php
2) src/Email.php

Found 2 of 20 files that can be fixed in 0.026 seconds, 20.00 MB memory used

5.3 并行模式加速

对于大型项目,PHP-CS-Fixer 支持并行执行以显著提升速度:

// 在配置文件中启用
use PhpCsFixer\Runner\Parallel\ParallelConfig;

return (new Config())
    ->setParallelConfig(new ParallelConfig(4, 20))  // 4进程,每进程20文件
    // ...

5.4 在 PhpStorm 中集成

PhpStorm 提供了原生支持:

  1. 进入 Settings → PHP → Quality Tools → PHP CS Fixer
  2. 工具会自动检测 vendor/bin/php-cs-fixer 路径
  3. 点击 Validate 验证配置
  4. 配置 Run mode:
    • On the fly:输入时自动检查并高亮问题
    • On idle:停止输入后延迟执行
    • On save:仅在保存文件时触发
  5. 勾选 Allow risky rules(如需要)

6. Git Pre-commit Hook 实战

在 Git 提交前自动检查代码风格,可以阻止不合规的代码进入仓库。

6.1 使用现成的 Hook 脚本

推荐的 gerardroche/php-cs-fixer-pre-commit-hook:

# 安装
git clone https://github.com/gerardroche/php-cs-fixer-pre-commit-hook.git
cd php-cs-fixer-pre-commit-hook
./install

该 Hook 的特点:

  • 仅检查本次变更的文件(非全量扫描)
  • 发现问题时阻止提交并输出报告
  • 可通过 git commit --no-verify 绕过

6.2 自定义 Pre-commit Hook

#!/bin/sh
# .git/hooks/pre-commit

PROJECT_ROOT=$(git rev-parse --show-toplevel)
cd "$PROJECT_ROOT" || exit 1

# 获取本次变更的 PHP 文件
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$' | tr '\n' ' ')

if [ -n "$CHANGED_FILES" ]; then
    echo "Running PHP CS Fixer on staged files..."
    ./vendor/bin/php-cs-fixer fix --dry-run --format=txt $CHANGED_FILES
    if [ $? -ne 0 ]; then
        echo "❌ Coding standards violations found. Please run:"
        echo "   ./vendor/bin/php-cs-fixer fix $CHANGED_FILES"
        echo "   and then git add the fixed files."
        exit 1
    fi
fi

7. CI/CD 集成(GitHub Actions)

在 Pull Request 中自动检查代码风格:

# .github/workflows/cs.yml
name: Code Style Check

on:
  pull_request:
  push:
    branches: [main, develop]

jobs:
  cs-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
          tools: composer
      
      - name: Install dependencies
        run: composer install --no-progress
      
      - name: Run CS Fixer Check
        run: composer cs-check

如果检查失败,PR 将显示 ❌ 状态,阻止合并。

8. 完整案例:为新项目建立代码风格规范

场景

你有一个新启动的 PHP 项目,需要建立统一的代码风格规范并集成到开发流程中。

步骤一:安装并生成配置

composer require --dev friendsofphp/php-cs-fixer
./vendor/bin/php-cs-fixer init

步骤二:完善配置文件

创建 .php-cs-fixer.dist.php,配置团队选定的规则(参考第 4 节的模板)。

步骤三:添加 Composer 脚本

{
    "scripts": {
        "cs-check": "php-cs-fixer check --dry-run",
        "cs-fix": "php-cs-fixer fix",
        "test": "phpunit",
        "analyse": "phpstan analyse"
    }
}

步骤四:在开发文档中记录工作流

在 README.md 中添加:

## 代码风格

本项目使用 PHP-CS-Fixer 统一代码风格。

### 本地开发
- 提交前执行:`composer cs-fix`
- 仅检查:`composer cs-check`

### CI 检查
PR 会自动运行 `composer cs-check`,不通过则无法合并。

步骤五:配置 Pre-commit Hook

参考第 6 节设置 Git Hook,确保提交时自动检查。

步骤六:设置 IDE(PhpStorm)

参考第 5.4 节,让团队成员在保存时自动格式化,从源头减少风格问题。

9. 常见问题与故障排查

问题解决方案
Command "check" is not defined检查 PHP-CS-Fixer 版本,check 命令在 v3.0+ 引入
规则不生效确认配置文件名为 .php-cs-fixer.dist.php 或 .php-cs-fixer.php,且位于项目根目录
CI 中报错但本地正常检查 CI 环境的 PHP 版本与本地是否一致
执行 fix 后代码逻辑被改变检查是否启用了 risky 规则,通常应避免在生产代码中使用高风险规则
并行模式报错降低 ParallelConfig 的进程数或禁用并行模式

通过上述配置和实践,你的团队可以建立起一套高效、自动化的代码风格管理流程,让 PHP-CS-Fixer 成为代码质量的坚实防线。