代码风格工具
代码风格工具能够自动化执行编码标准检查和格式化,确保团队所有成员提交的代码风格一致。PHP 生态中主流的代码风格工具包括 PHP-CS-Fixer、PHP_CodeSniffer 和 IDE 内置格式化功能。本节将详细介绍这些工具的配置、使用方法以及 CI 集成方案。
前置知识
阅读本节前,建议先了解:命名规范、PSR-12 编码标准
基础概念
为什么需要代码风格工具
- 一致性:消除团队成员之间的风格差异
- 自动化:减少 Code Review 中关于格式的讨论
- 质量保障:在 CI 中自动检查,防止不符合规范的代码合并
- 可维护性:统一的代码风格降低维护成本
PHP 代码风格工具生态
| 工具 | 用途 | 特点 |
|---|---|---|
| PHP-CS-Fixer | 自动格式化代码 | 基于 Symfony 团队维护,规则丰富 |
| PHP_CodeSniffer (phpcs) | 检查代码规范 | 支持自定义 sniff,广泛使用 |
| PHP_CodeSniffer + PHP_CBF | 检查并自动修复 | phpcs 的修复工具 |
| PHPStorm | IDE 内置格式化 | 可视化配置,实时格式化 |
| Pint | Laravel 专用格式化 | 基于 PHP-CS-Fixer,开箱即用 |
PHP-CS-Fixer
安装与基本使用
bash
# 全局安装
composer global require friendsofphp/php-cs-fixer
# 项目安装(推荐)
composer require --dev friendsofphp/php-cs-fixer
# 验证安装
php-cs-fixer --version基本命令
bash
# 查看当前可用的规则集
php-cs-fixer describe
# 查看特定规则的详情
php-cs-fixer describe single_class_insert_newline_before_brace
# 查看所有可用的规则
php-cs-fixer describe --list
# 干运行:仅显示会做哪些修改,不实际修改文件
php-cs-fixer fix --dry-run --diff
# 格式化指定文件
php-cs-fixer fix src/Service/UserService.php
# 格式化指定目录
php-cs-fixer fix src/
# 格式化并显示修改详情
php-cs-fixer fix src/ --diff --verbose
# 使用配置文件
php-cs-fixer fix --config=.php-cs-fixer.php配置文件详解
PHP-CS-Fixer v3.x 使用 PHP 配置文件 .php-cs-fixer.php(位于项目根目录):
php
<?php
declare(strict_types=1);
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$finder = Finder::create()
->in([
__DIR__ . '/src',
__DIR__ . '/tests',
])
->name('*.php')
->exclude([
'vendor',
'storage',
'cache',
'bootstrap/cache',
])
->notName('*.blade.php') // 排除 Blade 模板
->ignoreDotFiles(true)
->ignoreVCS(true);
return (new Config())
->setRiskyAllowed(true)
->setRules([
// ============================
// PSR-12 基础规则
// ============================
'@PSR12' => true,
'@PSR12:risky' => true,
// ============================
// 数组语法
// ============================
'array_syntax' => ['syntax' => 'short'], // 使用 [] 而非 array()
// ============================
// 导入排序
// ============================
'ordered_imports' => [
'sort_algorithm' => 'alpha',
'imports_order' => ['class', 'function', 'const'],
],
'no_unused_imports' => true, // 移除未使用的导入
// ============================
// 类型声明
// ============================
'declare_strict_types' => true, // 强制 declare(strict_types=1)
'fully_qualified_strict_types' => true, // 未使用的 use 导入自动移除
'no_superfluous_phpdoc_tags' => false, // 保留 PHPDoc 类型标签
// ============================
// 空白与格式
// ============================
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => ['return', 'throw', 'try'],
],
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_extra_blank_lines' => [
'tokens' => [
'extra',
'throw',
'use',
],
],
'single_blank_line_at_eof' => true,
// ============================
// 空格与缩进
// ============================
'method_chaining_indentation' => true,
'array_indentation' => true,
'indentation_type' => 'spaces',
'no_spaces_around_offset' => true,
// ============================
// 运算符与赋值
// ============================
'binary_operator_spaces' => [
'default' => 'single_space',
'operators' => [
'=>' => 'align',
'=' => 'align',
],
],
'concat_space' => ['spacing' => 'one'], // 字符串连接符前后各一个空格
'ternary_operator_spaces' => true,
'unary_operator_spaces' => true,
// ============================
// 命名空间与 use
// ============================
'blank_lines_before_namespace' => true,
'single_blank_line_before_namespace' => true,
'clean_namespace' => true,
'no_leading_namespace_slash' => true,
// ============================
// 控制结构
// ============================
'control_structure_braces' => true,
'control_structure_continuation_position' => [
'position' => 'next_line',
],
'elseif' => true, // 使用 elseif 而非 else if
'no_alternative_syntax' => true, // 禁止替代语法
'no_unneeded_control_parentheses' => true,
'no_unneeded_curly_braces' => true,
'simplified_if_return' => true,
// ============================
// 函数与方法
// ============================
'function_declaration' => [
'closure_function_spacing' => 'one',
],
'method_argument_space' => [
'on_multiline' => 'ensure_fully_multiline',
],
'no_trailing_comma_in_singleline_function_call' => true,
'trailing_comma_in_multiline' => [
'elements' => ['arrays', 'parameters', 'arguments', 'match'],
],
'return_type_declaration' => [
'space_before' => 'one',
],
'void_return' => false,
// ============================
// 类与接口
// ============================
'class_attributes_order' => [
'order' => [
'use_trait',
'case',
'constant_public',
'constant_protected',
'constant_private',
'property_public',
'property_protected',
'property_private',
'constructor',
'method_public',
'method_protected',
'method_private',
'magic_method',
],
],
'no_null_property_initialization' => true,
'self_static_accessor' => true,
// ============================
// 现代化 PHP
// ============================
'modernize_strpos' => true, // strpos() === 0 → str_starts_with()
'modernize_types_casting' => true, // (string) → strval()
'no_alias_functions' => true, // sizeof() → count()
'pow_to_exponentiation' => true, // pow() → ** 运算符
// ============================
// 注释
// ============================
'single_line_comment_spacing' => true,
'multiline_comment_opening_closing' => true,
'phpdoc_add_missing_param_annotation' => false,
'phpdoc_order' => true, // PHPDoc 标签排序
'phpdoc_separation' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => true, // PHPDoc 类型标准化
'phpdoc_var_without_name' => true,
'no_empty_phpdoc' => true,
])
->setFinder($finder)
->setLineEnding("\n")
->setIndent(' '); // 4 空格缩进逐行格式化示例
php
<?php
// ===== 格式化前 =====
namespace App\Service;
use App\Model\User;
use App\Repository\UserRepository;
use function count;
class UserService{
private $repository;
public function __construct(UserRepository $repository){
$this->repository=$repository;
}
public function findActiveUsers($limit=null){
$users=$this->repository->findBy(['isActive'=>true],['createdAt'=>'DESC'],$limit);
$count=count($users);
if($count==0){return [];}
return $users;
}
public function updateUser($id,$data){
$user=$this->repository->find($id);
if(!$user){throw new \Exception("User not found");}
$user->setName($data['name']??'Unknown');
$user->setEmail($data['email']);
$this->repository->save($user);
return $user;
}
}
// ===== 格式化后 =====
<?php
declare(strict_types=1);
namespace App\Service;
use App\Model\User;
use App\Repository\UserRepository;
class UserService
{
private UserRepository $repository;
public function __construct(UserRepository $repository)
{
$this->repository = $repository;
}
public function findActiveUsers(?int $limit = null): array
{
$users = $this->repository->findBy(
['isActive' => true],
['createdAt' => 'DESC'],
$limit,
);
$count = count($users);
if ($count === 0) {
return [];
}
return $users;
}
public function updateUser(int $id, array $data): User
{
$user = $this->repository->find($id);
if (!$user) {
throw new \Exception('User not found');
}
$user->setName($data['name'] ?? 'Unknown');
$user->setEmail($data['email']);
$this->repository->save($user);
return $user;
}
}PHP_CodeSniffer (phpcs)
安装与基本使用
bash
# 全局安装
composer global require squizlabs/php_codesniffer
# 项目安装
composer require --dev squizlabs/php_codesniffer
# 验证安装
phpcs --version
phpcbf --version # Code Beautifier and Fixer
# 列出内置标准
phpcs -i
# 查看特定标准的规则详情
phpcs --standard=PSR12 --report=full src/基本命令
bash
# 使用 PSR-12 标准检查
phpcs --standard=PSR12 src/
# 使用自定义标准检查
phpcs --standard=phpcs.xml src/
# 检查指定文件
phpcs --standard=PSR12 src/Service/UserService.php
# 仅显示错误摘要
phpcs --standard=PSR12 --report=summary src/
# 生成 XML 报告(适用于 CI)
phpcs --standard=PSR12 --report=checkstyle --report-file=checkstyle.xml src/
# 自动修复可修复的违规
phpcbf --standard=PSR12 src/
# 显示每个违规的行列号和修复建议
phpcs --standard=PSR12 -s src/自定义规则集 (phpcs.xml)
在项目根目录创建 phpcs.xml:
xml
<?xml version="1.0"?>
<ruleset name="MyProject Coding Standard">
<description>
MyProject 编码标准
基于 PSR-12,添加自定义规则
</description>
<!-- 继承 PSR-12 标准 -->
<rule ref="PSR12"/>
<!-- 扫描的文件和目录 -->
<file>./src</file>
<file>./tests</file>
<!-- 排除的目录 -->
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/cache/*</exclude-pattern>
<exclude-pattern>*/storage/*</exclude-pattern>
<exclude-pattern>*.blade.php</exclude-pattern>
<!-- 文件扩展名 -->
<arg name="extensions" value="php"/>
<!-- 显示进度 -->
<arg value="ps"/>
<!-- 颜色输出 -->
<arg name="colors"/>
<!-- ==================== -->
<!-- 安全性相关规则 -->
<!-- ==================== -->
<!-- 禁止使用 eval() -->
<rule ref="Generic.PHP.ForbiddenFunctions">
<properties>
<property name="forbidden_functions" type="array"
value="eval,assert,system,exec,passthru,shell_exec,proc_open,popen"
/>
</properties>
</rule>
<!-- 禁止使用 var 关键字声明属性 -->
<rule ref="Generic.PHP.NoSilencedErrors"/>
<!-- ==================== -->
<!-- 代码质量规则 -->
<!-- ==================== -->
<!-- 代码行长度限制 -->
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="120"/>
<property name="absoluteLineLimit" value="150"/>
</properties>
</rule>
<!-- 函数参数数量限制 -->
<rule ref="Generic.CodeAnalysis.MetricNComplexity">
<properties>
<property name="complexity" value="10"/>
</properties>
</rule>
<!-- 类方法数量限制 -->
<rule ref="Generic.CodeAnalysis.TooManyPublicMethods">
<properties>
<property name="maxMethods" value="20"/>
</properties>
</rule>
<!-- 禁止超长函数 -->
<rule ref="Generic.CodeAnalysis.TooManyPublicMethods">
<properties>
<property name="maxMethods" value="20"/>
</properties>
</rule>
<!-- ==================== -->
<!-- 命名规范检查 -->
<!-- ==================== -->
<!-- 类名必须是 PascalCase -->
<rule ref="PEAR.NamingConventions.ValidClassName">
<properties>
<property name="allowed" value="A-Za-z0-9_"/>
</properties>
</rule>
<!-- 函数/方法名必须是 camelCase -->
<rule ref="PSR2.Methods.MethodDeclaration">
<properties>
<property name="requireMultiple" value="true"/>
</properties>
</rule>
<!-- 常量必须是 UPPER_SNAKE_CASE -->
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
<!-- 变量名检查 -->
<rule ref="Generic.NamingConventions.CamelCapsVariableName">
<properties>
<property name="strict" value="true"/>
</properties>
</rule>
<!-- ==================== -->
<!-- 文档注释检查 -->
<!-- ==================== -->
<!-- 类必须有 PHPDoc 注释 -->
<rule ref="PEAR.Commenting.ClassComment"/>
<!-- 文件必须有头部注释 -->
<rule ref="PEAR.Commenting.FileComment"/>
<!-- 函数必须有 PHPDoc 注释 -->
<rule ref="Squiz.Commenting.FunctionComment">
<properties>
<property name="minimumLinesBetweenTags" value="1"/>
</properties>
</rule>
<!-- ==================== -->
<!-- 安全相关额外检查 -->
<!-- ==================== -->
<!-- SQL 注入防护提醒 -->
<rule ref="Generic.PHP.BacktickOperator"/>
<!-- 禁止直接使用 $_GET/$_POST/$_REQUEST -->
<rule ref="MySource.PHP.GetRequestAsString"/>
</ruleset>自定义 Sniff
php
<?php
declare(strict_types=1);
namespace MyProject\Sniffs\Commenting;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
/**
* 检查类属性是否有类型声明(PHP 7.4+)
*/
class TypedPropertySniff implements Sniff
{
/**
* 注册监听的 token
*/
public function register(): array
{
return [T_PRIVATE, T_PROTECTED, T_PUBLIC];
}
/**
* 处理发现的 token
*/
public function process(File $phpcsFile, $stackPtr): void
{
$tokens = $phpcsFile->getTokens();
// 跳过非属性声明(如方法)
$next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true);
if ($next === false) {
return;
}
// 如果下一个是 function,说明是方法声明
if ($tokens[$next]['code'] === T_FUNCTION) {
return;
}
// 如果下一个是 static,继续查找
if ($tokens[$next]['code'] === T_STATIC) {
$next = $phpcsFile->findNext(T_WHITESPACE, $next + 1, null, true);
}
// 检查是否是 $ 符号开头(变量声明)
if ($next === false || $tokens[$next]['code'] !== T_VARIABLE) {
return;
}
// 检查变量名前是否有类型声明
$prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true);
if ($prev === false || $tokens[$prev]['code'] !== T_STRING) {
// 没有类型声明,报告警告
$phpcsFile->addWarning(
'Property "%s" should have a type declaration (PHP 7.4+)',
$next,
'MissingTypedProperty',
[$tokens[$next]['content']],
);
}
}
}注册自定义 Sniff:
xml
<?xml version="1.0"?>
<ruleset name="MyProject Coding Standard">
<description>MyProject 自定义规则</description>
<!-- 引入自定义 Sniff -->
<rule ref="MyProject.Commenting.TypedPropertySniff">
<exclude name="MyProject.Commenting.TypedPropertySniff.MissingTypedProperty"/>
</rule>
</ruleset>PHPStorm 格式化配置
代码风格设置
在 PHPStorm 中设置代码风格(Settings/Preferences > Editor > Code Style > PHP):
PSR-12 基础设置:
├── Tabs and Indents
│ ├── Use tab character: false
│ ├── Tab size: 4
│ ├── Indent: 4
│ └── Continuation indent: 8
├── Spaces
│ ├── Before parentheses (declaration): false
│ ├── Within parentheses (declaration): false
│ ├── Before parentheses (call): false
│ ├── Within parentheses (call): false
│ ├── Around operators: true
│ ├── Before keywords: true
│ └── Within: true
├── Wrapping and Braces
│ ├── Braces position: Next line
│ ├── Array initializer: 每个元素一行
│ └── Method call arguments: 每个参数一行(超长时)
├── Blank Lines
│ ├── Before class: 1
│ ├── After class: 1
│ ├── Before method: 1
│ ├── After method: 1
│ └── Keep maximum: 2
└── PHPDoc
├── Method params alignment: by name
├── Blank line before description: true
└── Blank line before tags: true导入与导出代码风格
xml
<!-- PHPStorm 代码风格方案文件 (ProjectSettings/Project.xml) -->
<!-- 可以通过 File > Manage schemes > Export 导出 -->保存时自动格式化
设置路径:Settings/Preferences > Tools > Actions on Save
☑ Reformat code
☑ Optimize imports
☑ Rearrange code
☑ Run code cleanup与 PHP-CS-Fixer 集成
在 PHPStorm 中配置外部工具(Settings > Tools > External Tools):
Program: $ProjectFileDir$/vendor/bin/php-cs-fixer
Arguments: fix $FilePath$ --config=.php-cs-fixer.php
Working directory: $ProjectFileDir$然后配置 File Watcher(Settings > Tools > File Watchers):
File type: PHP
Program: $ProjectFileDir$/vendor/bin/php-cs-fixer
Arguments: fix $FilePath$ --config=.php-cs-fixer.php --quiet
Working directory: $ProjectFileDir$
☑ Auto-save edited files to trigger the watcherLaravel Pint
Laravel Pint 是基于 PHP-CS-Fixer 的零配置代码格式化工具:
bash
# 安装(Laravel 项目中)
composer require laravel/pint --dev
# 格式化所有文件
./vendor/bin/pint
# 格式化指定文件或目录
./vendor/bin/pint src/Service/
# 仅测试(不修改文件)
./vendor/bin/pint --test
# 使用预设规则集
./vendor/bin/pint --preset laravel
./vendor/bin/pint --preset psr12
./vendor/bin/pint --preset symfony
./vendor/bin/pint --preset django
# 显示详细输出
./vendor/bin/pint -v自定义 Pint 配置 (pint.json):
json
{
"preset": "laravel",
"rules": {
"declare_strict_types": true,
"fully_qualified_strict_types": true,
"no_unused_imports": true,
"array_syntax": {
"syntax": "short"
}
},
"exclude": [
"vendor",
"storage",
"database/migrations"
],
"notName": [
"*.blade.php"
]
}CI 集成
GitHub Actions 配置
yaml
# .github/workflows/php-coding-style.yml
name: PHP Coding Style
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
php-cs-fixer:
name: PHP-CS-Fixer (Dry Run)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none
tools: composer:v2
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Run PHP-CS-Fixer (Dry Run)
run: vendor/bin/php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.php
phpcs:
name: PHP CodeSniffer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Run PHP CodeSniffer
run: vendor/bin/phpcs --standard=phpcs.xml --report=full src/ tests/
pint:
name: Laravel Pint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Run Pint
run: vendor/bin/pint --test -vGitLab CI 配置
yaml
# .gitlab-ci.yml
php-coding-style:
stage: test
image: composer:latest
before_script:
- composer install --prefer-dist --no-progress --no-interaction
script:
- vendor/bin/php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.php
- vendor/bin/phpcs --standard=phpcs.xml --report=full src/ tests/
artifacts:
reports:
codequality: checkstyle.xml
when: on_failure
paths:
- checkstyle.xmlGit Pre-commit Hook
bash
#!/bin/bash
# .git/hooks/pre-commit 或使用 composer script
# PHP-CS-Fixer 检查
echo "Running PHP-CS-Fixer..."
./vendor/bin/php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.php
if [ $? -ne 0 ]; then
echo ""
echo "❌ PHP-CS-Fixer found style issues."
echo "Run 'vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php' to fix them."
exit 1
fi
# PHP CodeSniffer 检查
echo "Running PHP CodeSniffer..."
./vendor/bin/phpcs --standard=phpcs.xml --report=full src/ tests/
if [ $? -ne 0 ]; then
echo ""
echo "❌ PHP CodeSniffer found violations."
echo "Run 'vendor/bin/phpcbf --standard=phpcs.xml src/ tests/' to fix them."
exit 1
fi
echo "✅ All code style checks passed."
exit 0使用 Composer 安装 pre-commit hook:
json
{
"scripts": {
"cs-check": "php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.php",
"cs-fix": "php-cs-fixer fix --config=.php-cs-fixer.php",
"phpcs": "phpcs --standard=phpcs.xml src/ tests/",
"phpcbf": "phpcbf --standard=phpcs.xml src/ tests/",
"style-check": [
"@cs-check",
"@phpcs"
],
"style-fix": [
"@cs-fix",
"@phpcbf"
],
"pre-commit": [
"@style-check"
]
}
}实战示例
从零搭建代码风格工具链
bash
# 1. 创建项目
composer init -n
# 2. 安装开发依赖
composer require --dev friendsofphp/php-cs-fixer squizlabs/php_codesniffer
# 3. 创建 PHP-CS-Fixer 配置文件
cat > .php-cs-fixer.php << 'EOF'
<?php
declare(strict_types=1);
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$finder = Finder::create()
->in(__DIR__ . '/src')
->name('*.php');
return (new Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'declare_strict_types' => true,
'ordered_imports' => true,
'no_unused_imports' => true,
'array_syntax' => ['syntax' => 'short'],
'trailing_comma_in_multiline' => ['elements' => ['arrays', 'parameters', 'arguments']],
])
->setFinder($finder)
->setLineEnding("\n")
->setIndent(' ');
EOF
# 4. 创建 PHP_CodeSniffer 配置文件
cat > phpcs.xml << 'EOF'
<?xml version="1.0"?>
<ruleset name="Project Standard">
<rule ref="PSR12"/>
<file>./src</file>
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="120"/>
</properties>
</rule>
</ruleset>
EOF
# 5. 添加 Composer 脚本
composer config scripts.cs-check "php-cs-fixer fix --dry-run --diff"
composer config scripts.cs-fix "php-cs-fixer fix"
composer config scripts.phpcs "phpcs --standard=phpcs.xml src/"
composer config scripts.style-check "@cs-check && @phpcs"
composer config scripts.style-fix "@cs-fix && vendor/bin/phpcbf --standard=phpcs.xml src/"
# 6. 运行检查
composer style-check
# 7. 自动修复
composer style-fix注意事项
工具选择建议
PHP-CS-Fixer vs PHP_CodeSniffer
- PHP-CS-Fixer:更侧重代码格式化和自动修复,适合初学者和快速统一风格
- PHP_CodeSniffer:更侧重规范检查和自定义规则,适合需要精细控制的团队
- 推荐组合:同时使用两者,PHP-CS-Fixer 负责自动格式化,PHP_CodeSniffer 负责补充检查
常见陷阱
php
<?php
declare(strict_types=1);
// 注意:格式化工具可能改变代码逻辑,务必在格式化后运行测试
// 1. 对齐赋值可能改变
$name = 'John';
$email = 'john@example.com'; // 格式化工具可能重新对齐
// 2. 数组格式变化
$data = [
'key1' => 'value1',
'key2' => 'value2',
];
// 格式化工具可能重新排列为每个元素一行或多行
// 3. 注释格式变化
// 格式化工具可能调整注释中的空格和缩进始终在 CI 中运行测试
代码格式化可能意外改变代码行为。在 CI 中,代码风格检查应与测试套件并行运行,确保格式化不会引入错误。
最佳实践
- 配置文件纳入版本控制:将
.php-cs-fixer.php和phpcs.xml提交到 Git - 使用 pre-commit hook:在提交前自动检查代码风格
- CI 中并行运行:代码风格检查与单元测试同时运行
- 渐进式引入:对已有项目使用
.php-cs-fixer.cache和 baseline 机制 - 团队统一工具版本:在
composer.json中锁定工具版本 - 定期更新规则:跟踪 PHP-CS-Fixer 和 PHP_CodeSniffer 的更新
下一节
继续学习:静态分析