《PHP工业化研发交付标准体系:从代码规范、接口契约到上线验收的全链路工业级基准》
·
PHP 工业化研发交付标准体系
下面这套是我按"工业化"思路整理的——目标不是"能跑就行",而是任何一个新人接手任何一个项目,都能用同一套规矩、同一套工具、──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
同一套验收标准交付。每节都给完整代码 + 大白话。
---
0. 全景图(先把"工业化"拆清楚)
需求 设计 编码 接口 构建 测试 发布 验收 运行
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
PRD →ADR/RFC →PSR/Lint →OpenAPI →CI/CD →单/集/E2E →灰度 →DoD/UAT →SLO
↑ │
└── Schema 即契约,前后端 / 服务间共同遵守 ┘
人话:每一格都有"输入物 + 产出物 + 谁验收",不靠人盯靠工具盯。下面一格一格落地。
---
1. 项目骨架:所有项目长一个样
acme-service/
├── app/ # 业务代码(领域分层)
│ ├── Domain/ # 领域模型(纯 PHP,无框架)
│ ├── Application/ # 用例 / Service
│ ├── Infrastructure/ # DB / HTTP / MQ / Cache 适配
│ └── Interface/ # Http / Cli / Rpc 入口
├── config/ # 配置(按环境分文件)
├── database/migrations/ # 数据库变更(不可逆操作单独标记)
├── docs/
│ ├── adr/ # 架构决策记录
│ ├── api/openapi.yaml # 接口契约(唯一真源)
│ └── runbook/ # 运维手册
├── tests/{Unit,Feature,Contract,E2E}/
├── .github/workflows/ # CI
├── deploy/ # Dockerfile / k8s / helm
├── tools/ # 一次性脚本、生成器
├── composer.json
├── phpstan.neon psalm.xml .php-cs-fixer.php rector.php
├── Makefile # 统一入口
└── README.md
人话:骨架统一以后,每个新仓库 git clone 下来 make up 就能跑、make ci 就能验收。下面给 Makefile:
.PHONY: up down ci lint stan psalm test cs fix migrate seed openapi
up: ; docker compose up -d --wait
down: ; docker compose down -v
install: ; composer install --prefer-dist --no-interaction
cs: ; vendor/bin/php-cs-fixer fix --dry-run --diff
fix: ; vendor/bin/php-cs-fixer fix && vendor/bin/rector process
stan: ; vendor/bin/phpstan analyse --memory-limit=1G
psalm: ; vendor/bin/psalm --no-cache
test: ; vendor/bin/phpunit --testdox
contract: ; vendor/bin/phpunit --testsuite=Contract
openapi: ; vendor/bin/openapi app -o docs/api/openapi.yaml && npx @stoplight/spectral-cli lint docs/api/openapi.yaml
migrate: ; php artisan migrate --force
ci: cs stan psalm test contract openapi
---
2. 编码规范:PSR + Lint + 自动修复
2.1 composer.json(标准依赖与脚本)
{
"name": "acme/service",
"type": "project",
"require": { "php": "^8.3" },
"require-dev": {
"phpunit/phpunit": "^11",
"phpstan/phpstan": "^1.11",
"phpstan/phpstan-strict-rules": "^1.5",
"vimeo/psalm": "^5",
"friendsofphp/php-cs-fixer": "^3.59",
"rector/rector": "^1.2",
"infection/infection": "^0.29",
"roave/security-advisories": "dev-latest",
"zircote/swagger-php": "^4",
"pestphp/pest": "^2"
},
"scripts": {
"ci": ["@cs","@stan","@psalm","@test","@contract"],
"cs": "php-cs-fixer fix --dry-run --diff",
"stan": "phpstan analyse",
"psalm":"psalm",
"test": "phpunit",
"contract":"phpunit --testsuite=Contract"
},
"config": { "sort-packages": true, "allow-plugins": { "*": true } }
}
2.2 .php-cs-fixer.php(PSR-12 + 团队约定)
<?php
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'@PHP83Migration' => true,
'declare_strict_types' => true,
'array_syntax' => ['syntax' => 'short'],
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'no_unused_imports' => true,
'single_quote' => true,
'native_function_invocation' => ['include' => ['@all']],
'global_namespace_import' => ['import_classes' => true, 'import_functions' => false],
])
->setFinder(PhpCsFixer\Finder::create()->in([__DIR__.'/app', __DIR__.'/tests']));
2.3 phpstan.neon(最严级别 9)
parameters:
level: 9
paths: [app, tests]
treatPhpDocTypesAsCertain: false
checkUninitializedProperties: true
checkMissingIterableValueType: true
reportUnmatchedIgnoredErrors: true
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
人话:@PSR12 + level 9 + strict_types + Psalm 是 PHP 工业化的"四件套"。CI
里这四样不绿,代码不准合并。这条规矩立住,整个团队的代码风格就齐了。
---
3. 分层架构:六边形(端口适配器)
<?php
// app/Domain/Order/Order.php ——纯领域,无框架依赖
declare(strict_types=1);
namespace App\Domain\Order;
final class Order
{
public function __construct(
public readonly OrderId $id,
public readonly UserId $userId,
public Money $amount,
public OrderStatus $status,
) {}
public function pay(Money $paid): void
{
if ($this->status !== OrderStatus::Pending) {
throw new DomainException('only pending order can be paid');
}
if ($paid->lt($this->amount)) {
throw new DomainException('insufficient payment');
}
$this->status = OrderStatus::Paid;
}
}
<?php
// app/Application/Order/PayOrderUseCase.php ——用例:编排
final class PayOrderUseCase
{
public function __construct(
private OrderRepository $repo, // 端口(接口)
private EventBus $bus,
private TransactionRunner $tx,
) {}
public function execute(PayOrderCommand $cmd): OrderId
{
return $this->tx->run(function () use ($cmd) {
$order = $this->repo->findOrFail($cmd->orderId);
$order->pay($cmd->amount);
$this->repo->save($order);
$this->bus->dispatch(new OrderPaid($order->id));
return $order->id;
});
}
}
<?php
// app/Infrastructure/Persistence/PdoOrderRepository.php ——适配器
final class PdoOrderRepository implements OrderRepository
{
public function __construct(private \PDO $db) {}
public function save(Order $o): void { /* PDO 预编译 */ }
public function findOrFail(OrderId $id): Order { /* ... */ }
}
人话:领域不知道数据库存在,用例不知道 HTTP 存在。换 MySQL 换 PG、换 HTTP 换
gRPC,业务代码一行不动。这是工业化最值钱的一条架构纪律。
---
4. 接口契约:OpenAPI 是唯一真源
4.1 用注解写,自动生成 openapi.yaml
<?php
// app/Interface/Http/OrderController.php
use OpenApi\Attributes as OA;
#[OA\Info(version: '1.0.0', title: 'Order API')]
final class OrderController
{
#[OA\Post(
path: '/api/v1/orders/{id}/pay',
summary: '支付订单',
tags: ['Order'],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(ref: '#/components/schemas/PayOrderRequest')
),
responses: [
new OA\Response(response: 200, description: 'OK',
content: new OA\JsonContent(ref: '#/components/schemas/OrderView')),
new OA\Response(response: 409, description: 'Conflict',
content: new OA\JsonContent(ref: '#/components/schemas/Problem')),
]
)]
public function pay(string $id, PayOrderRequest $req): OrderView { /* ... */ }
}
#[OA\Schema()]
final class PayOrderRequest {
#[OA\Property(format: 'decimal', example: '99.00')] public string $amount;
#[OA\Property(example: 'CNY')] public string $currency;
}
更多推荐


所有评论(0)