《PHP企业级研发治理体系:从代码规范到组织协作的全链路落地手册》
·
PHP企业级研发治理体系:从代码规范到组织协作的全链路落地手册
下面把整套体系拆成 8 层,每一层都给你「干什么用」+「怎么落地」+「完整代码」+「大白话」。直接照抄就能跑。
---
一、整体地图(先看全景再动手)
┌─────────────────────────────────────────────┐
│ 第8层:组织协作(OKR / Code Review / 知识库)│
│ 第7层:监控告警(Sentry / Prometheus) │
│ 第6层:CI/CD(GitLab CI / GitHub Actions) │
│ 第5层:Git 工作流(Git Flow + 提交规范) │
│ 第4层:安全审计(Composer Audit / Enlightn) │
│ 第3层:自动化测试(PHPUnit / Pest) │
│ 第2层:静态分析(PHPStan / Psalm / Rector) │
│ 第1层:代码规范(PSR-12 / PHP-CS-Fixer) │
└─────────────────────────────────────────────┘
大白话:底层是「写得对不对」,中层是「跑得稳不稳」,上层是「人协作得顺不顺」。一层都不能少。
---
二、第1层:代码规范(PSR-12 + PHP-CS-Fixer)
1. 安装
composer require --dev friendsofphp/php-cs-fixer squizlabs/php_codesniffer
2. .php-cs-fixer.dist.php
<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/src')
->in(__DIR__ . '/tests')
->exclude('vendor');
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'@PHP82Migration' => true,
'array_syntax' => ['syntax' => 'short'],
'declare_strict_types' => true,
'no_unused_imports' => true,
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'single_quote' => true,
'trailing_comma_in_multiline' => true,
'phpdoc_align' => ['align' => 'vertical'],
])
->setFinder($finder);
3. 一键修复
vendor/bin/php-cs-fixer fix --diff --verbose
大白话:这一层管「代码长得好不好看」。缩进、引号、空行这种鸡毛蒜皮的事,交给工具自动改,人不要花脑子去吵。
---
三、第2层:静态分析(PHPStan)
1. 安装
composer require --dev phpstan/phpstan phpstan/extension-installer
composer require --dev phpstan/phpstan-strict-rules
2. phpstan.neon
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
parameters:
level: 8 # 0~9,9 最严,企业建议 8 起步
paths:
- src
- tests
excludePaths:
- src/Legacy/*
checkMissingIterableValueType: true
treatPhpDocTypesAsCertain: false
ignoreErrors:
- '#Call to an undefined method.*::scopeWhere.*#'
3. 跑
vendor/bin/phpstan analyse --memory-limit=2G
大白话:这一层管「代码逻辑有没有埋雷」。比如你 $user->getName() 但 $user 可能是 null,PHPStan
在你提交前就喊出来,不用等线上崩了才发现。
---
四、第3层:自动化测试(Pest,比 PHPUnit 更顺手)
1. 安装
composer require --dev pestphp/pest pestphp/pest-plugin-laravel
./vendor/bin/pest --init
2. tests/Unit/UserServiceTest.php
<?php
declare(strict_types=1);
use App\Services\UserService;
use App\Repositories\UserRepository;
beforeEach(function () {
$this->repo = Mockery::mock(UserRepository::class);
$this->service = new UserService($this->repo);
});
it('创建用户时邮箱必须唯一', function () {
$this->repo->shouldReceive('existsByEmail')
->with('a@b.com')->once()->andReturnTrue();
expect(fn () => $this->service->create('张三', 'a@b.com'))
->toThrow(DomainException::class, '邮箱已存在');
});
it('创建用户成功返回ID', function () {
$this->repo->shouldReceive('existsByEmail')->andReturnFalse();
$this->repo->shouldReceive('insert')->andReturn(1001);
expect($this->service->create('张三', 'a@b.com'))->toBe(1001);
});
3. 覆盖率门槛(写进 phpunit.xml)
<coverage>
<report>
<clover outputFile="coverage.xml"/>
<html outputDirectory="coverage-html"/>
</report>
</coverage>
vendor/bin/pest --coverage --min=80
大白话:测试不是写给 QA 看的,是写给「半年后改代码的自己」看的。覆盖率 80% 不达标就不让合并,强制养成习惯。
---
五、第4层:安全审计
# 检查依赖有没有已知漏洞
composer audit
# 更专业的安全扫描(Laravel)
composer require --dev enlightn/enlightn
php artisan enlightn
.gitleaks.toml(防止 AK/SK 提交):
[allowlist]
paths = ['''.*\.lock$''']
[[rules]]
id = "aws-key"
regex = '''AKIA[0-9A-Z]{16}'''
大白话:依赖里有漏洞、代码里漏了 AccessKey,这种事一旦发生就是大事故。让工具每天扫,比靠人记靠谱一万倍。
---
六、第5层:Git 工作流 + 提交规范
1. 分支模型(Git Flow 简化版)
main ←线上,只接受 release/hotfix 合并
develop ←集成分支
feature/* ←功能分支(从 develop 切)
release/* ←发版分支
hotfix/* ←紧急修复(从 main 切)
2. Conventional Commits(用 commitlint 强制)
commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert'
]],
'subject-max-length': [2, 'always', 72],
},
};
3. Husky 钩子 package.json
{
"scripts": { "prepare": "husky install" },
"devDependencies": {
"husky": "^9.0.0",
"@commitlint/cli": "^19.0.0",
"@commitlint/config-conventional": "^19.0.0"
}
}
.husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
vendor/bin/php-cs-fixer fix --dry-run --diff || exit 1
vendor/bin/phpstan analyse --no-progress || exit 1
vendor/bin/pest --parallel || exit 1
.husky/commit-msg:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit $1
大白话:提交信息长成 feat(user): 增加邮箱校验,半年后看 git log 一目了然。乱写一句 fix bug 直接拒。
---
七、第6层:CI/CD(GitHub Actions 完整版)
.github/workflows/ci.yml:
name: CI
on:
push: { branches: [main, develop] }
pull_request: { branches: [main, develop] }
jobs:
quality:
runs-on: ubuntu-latest
strategy:
matrix: { php: ['8.2', '8.3'] }
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
tools: composer:v2
- name: Cache Composer
uses: actions/cache@v4
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
- run: composer install --prefer-dist --no-progress
- run: vendor/bin/php-cs-fixer fix --dry-run --diff
- run: vendor/bin/phpstan analyse --error-format=github
- run: vendor/bin/pest --coverage --min=80
- run: composer audit
- name: Upload coverage
uses: codecov/codecov-action@v4
with: { files: ./coverage.xml }
deploy-staging:
needs: quality
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.STAGING_HOST }}
username: ${{ secrets.STAGING_USER }}
key: ${{ secrets.STAGING_KEY }}
script: |
cd /var/www/app
git pull origin develop
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
php artisan queue:restart
大白话:本地钩子是「软拦截」,CI 是「硬关卡」。本地能绕过,CI 必须过;过不了 CI,PR 按钮直接灰着。
---
八、第7层:监控告警
1. Sentry 接入
// config/sentry.php
return [
'dsn' => env('SENTRY_LARAVEL_DSN'),
'traces_sample_rate' => 0.2,
'profiles_sample_rate' => 0.1,
'send_default_pii' => false,
'environment' => env('APP_ENV'),
];
2. Prometheus 指标埋点
use Prometheus\CollectorRegistry;
class MetricsMiddleware
{
public function __construct(private CollectorRegistry $registry) {}
public function handle($request, Closure $next)
{
$start = microtime(true);
$response = $next($request);
$histogram = $this->registry->getOrRegisterHistogram(
'app', 'http_request_duration_seconds',
'HTTP 请求耗时', ['method', 'route', 'status'],
[0.05, 0.1, 0.3, 1, 3]
);
$histogram->observe(
microtime(true) - $start,
[$request->method(), $request->route()?->getName() ?? 'unknown', (string)$response->status()]
);
return $response;
}
}
大白话:线上必须做到「错了立刻知道、慢了立刻知道、谁错的立刻知道」。Sentry 抓异常,Prometheus + Grafana
看趋势,缺一不可。
---
九、第8层:组织协作
1. Code Review Checklist(贴 PR 模板)
.github/pull_request_template.md:
## 改了什么
<!-- 一句话讲清楚 -->
## 为什么改
<!-- 关联需求/Bug 单 -->
## 自检清单
- [ ] PHPStan level 8 通过
- [ ] 单元测试覆盖率 ≥80%
- [ ] 接口变更已更新 OpenAPI 文档
- [ ] 数据库变更有可回滚的 migration
- [ ] 没有提交 .env / 密钥 / 调试代码
- [ ] 关键逻辑加了注释和日志
## 影响范围
<!-- 涉及哪些模块、是否需要灰度 -->
2. Review 三原则
┌─────────────┬────────────────────────────────────────────────────────┐
│ 原则 │ 大白话 │
├─────────────┼────────────────────────────────────────────────────────┤
│ 对事不对人 │ 说「这段如果输入为空会 NPE」,不说「你怎么连这都不写」 │
├─────────────┼────────────────────────────────────────────────────────┤
│ 24 小时响应 │ PR 挂超过一天没人看,整个团队都在等 │
├─────────────┼────────────────────────────────────────────────────────┤
│ 小 PR 优先 │ 500 行以上拆,否则评审等于走过场 │
└─────────────┴────────────────────────────────────────────────────────┘
3. 文档与知识沉淀
docs/
├── adr/ # 架构决策记录(Architecture Decision Records)
│ └── 0001-用-laravel-octane-提性能.md
├── runbook/ # 线上故障应对手册
│ └── 数据库主从延迟.md
├── onboarding.md # 新人三天上手
└── api/openapi.yaml # 接口契约
ADR 模板:
# ADR-0001:使用 Octane 替代 PHP-FPM
- 状态:已采纳
- 日期:2026-06-16
- 决策者:架构组
## 背景
QPS 峰值 3000,PHP-FPM 冷启动开销大
## 决策
切换到 Laravel Octane + Swoole
## 后果
+ 性能提升 5 倍
- 内存泄漏风险,需引入定期 reload
大白话:ADR 是「为什么这么做」的备忘录。三年后新人来了,不用再问「这破设计到底谁拍的」,翻文档就懂。
---
十、落地节奏(最佳推进方式)
┌────────────┬────────┬──────────────────────────────────────────────────┐
│ 阶段 │ 时间 │ 做什么 │
├────────────┼────────┼──────────────────────────────────────────────────┤
│ 第 1 周 │ 立规矩 │ 装 PHP-CS-Fixer + PHPStan level 5,本地能跑 │
├────────────┼────────┼──────────────────────────────────────────────────┤
│ 第 2~3 周 │ 上 CI │ GitHub Actions 跑通,PR 卡红线 │
├────────────┼────────┼──────────────────────────────────────────────────┤
│ 第 4~6 周 │ 补测试 │ 核心模块覆盖率拉到 60%,逐步爬到 80% │
├────────────┼────────┼──────────────────────────────────────────────────┤
│ 第 7~8 周 │ 提级别 │ PHPStan 升到 level 8,老代码标 baseline 慢慢还债 │
├────────────┼────────┼──────────────────────────────────────────────────┤
│ 第 9 周 │ 上监控 │ Sentry + Prometheus 接入,建告警群 │
├────────────┼────────┼──────────────────────────────────────────────────┤
│ 第 10 周起 │ 抓协作 │ 推 ADR、Runbook、PR 模板,固化 Review 文化 │
└────────────┴────────┴──────────────────────────────────────────────────┘
---
十一、最关键的三句话
1. 工具能解决的问题,绝不靠人盯——风格、漏洞、覆盖率全部自动化。
2. CI 是底线,不是上限——过了CI 只代表「没明显错」,不代表「写得好」,Code Review 才是真把关。
3. 治理不是一次性运动,是持续的肌肉记忆——每周花10% 的时间还技术债,比每年来一次大重构划算 100 倍。
照这套抄完,半年内代码质量会肉眼可见地变好,新人上手时间能从两周缩到三天。需要我针对某一层(比如 Octane 部署、Sentry
告警分级、ADR 推广话术)再深挖,随时说。
更多推荐
所有评论(0)