ECC 规则库中的 PHP 架构模式:薄控制器、DTO 与依赖边界工程实践
发布时间:2026/9/11 20:53:57 作者:尧图编辑部 阅读量:1,286

ECC 规则库中的 PHP 架构模式薄控制器、DTO 与依赖边界工程实践【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC本篇技术指南以仓库 rules/php/patterns.md 为核心骨架系统讲解 PHP 应用含 Laravel、Symfony 等框架的架构分层规范如何把控制器压缩为纯传输层、如何用 DTO 与值对象替代臃肿的关联数组、如何通过构造器注入与接口契约隔离框架依赖以及如何在模型层与第三方 SDK 之间建立清晰的边界。文中不仅完整继承原规则的所有要点还结合 rules/php/ 下的编码风格、测试、安全规则以及 skills/laravel-patterns/SKILL.md、skills/api-design/SKILL.md 技能补充可复制、可运行的 PHP 代码示例与底层原理帮助你写出可测试、可维护、可演进的 PHP 业务代码。规则文件在 ECC 体系中的定位在 ECCAgent Harness Performance Optimization System中rules/目录按技术栈组织了一系列规则文件供 Claude Code、Codex 等 Agent 在生成或审查代码时引用。rules/php/patterns.md是 PHP 语言族的架构模式规则其 frontmatter 声明了匹配范围paths: - **/*.php - **/composer.json也就是说只要 Agent 触碰.php源文件或composer.json该模式规则即被激活。规则文件开篇声明它是对通用模式 rules/common/patterns.md 的 PHP 专属扩展而同一目录下的 rules/php/coding-style.md、rules/php/testing.md、rules/php/security.md、rules/php/hooks.md 则分别覆盖风格、测试、安全与钩子配置共同构成一份完整的 PHP 工程约束。本篇聚焦其中最具架构指导意义的四条核心模式薄控制器与显式服务、DTO 与值对象、依赖注入、边界划分。薄控制器Thin Controllers与显式服务Explicit Services原规则第一条即要求控制器只负责传输transport不承载业务。具体而言控制器关注四类横切事务认证authentication确认谁在调用校验validation确认输入是否合法序列化serialization决定以什么形状返回数据状态码status codes用 HTTP 语义表达结果而业务规则必须下沉到应用层/领域层服务中这些服务不依赖 HTTP 启动上下文因此可以在没有 Web 服务器、没有请求/响应对象的环境下直接做单元测试。参考实现Controllers → Services → Actionsskills/laravel-patterns/SKILL.md 给出了 Laravel 中的推荐分层Controllers - Services - Actions——控制器保持单薄编排逻辑放在服务中单一职责的用例逻辑放在 Action 类中final class CreateOrderAction { public function __construct(private OrderRepository $orders) {} public function handle(CreateOrderData $data): Order { return $this-orders-create($data); } } final class OrdersController extends Controller { public function __construct(private CreateOrderAction $createOrder) {} public function store(StoreOrderRequest $request): JsonResponse { $order $this-createOrder-handle($request-toDto()); return response()-json([ success true, data OrderResource::make($order), error null, meta null, ], 201); } }这段代码展示了薄控制器的完整形态控制器只做三件事——接收已校验的请求、调用 Action、序列化并返回响应。CreateOrderAction不知道Request、Response的存在其构造函数通过类型声明注入OrderRepository业务逻辑因此可以在 PHPUnit/Pest 中脱离 HTTP 层直接验证。与此呼应rules/php/testing.md 要求HTTP/控制器测试聚焦传输与校验业务规则下沉到服务级测试vendor/bin/phpunit --coverage-text # 或 vendor/bin/pest --coverage这正是薄控制器模式的验证闭环控制器层测试验证路由、校验与状态码服务层测试验证真实业务逻辑两者互不干扰。响应信封与通用模式对齐薄控制器产出的响应形状并非随意设计。rules/common/patterns.md 定义了统一的 API 响应信封包含成功/状态指示符如success包含数据负载data出错时为 null包含错误信息字段error成功时为 null分页响应附带元数据total、page、limitskills/api-design/SKILL.md 进一步给出了错误响应的机器可读结构codemessage 字段级details并强调用 HTTP 状态码表达语义而不是一律返回 200。例如创建资源应返回201 Created并附带Location头return response()-json( [data OrderResource::make($order)], 201, [Location /api/v1/orders/ . $order-id], );DTO 与值对象取代形状沉重的关联数组原规则第二条针对 PHP 开发中常见的关联数组滥用问题用 DTO 取代形状沉重的关联数组应用于请求、命令、外部 API 负载等场景用值对象承载金额、标识符、日期范围等带约束的概念。关联数组的问题在于键名拼写错误只能在运行时暴露、无法携带类型、没有行为约束。而 DTO 提供编译期/静态分析期的形状校验配合 PHPStan/Psalm值对象则把业务约束内聚到类型本身。请求 DTO 的落地方式skills/laravel-patterns/SKILL.md 推荐在 FormRequest 中完成校验后立即转换为 DTO让 DTO 成为进入领域层的唯一入口final class StoreOrderRequest extends FormRequest { public function authorize(): bool { return $this-user()?-can(create, Order::class) ?? false; } public function rules(): array { return [ customer_id [required, integer, exists:customers,id], items [required, array, min:1], items.*.sku [required, string], items.*.quantity [required, integer, min:1], ]; } public function toDto(): CreateOrderData { return new CreateOrderData( customerId: (int) $this-validated(customer_id), items: $this-validated(items), ); } }这样框架输入在触达领域逻辑之前就被净化为已验证的 DTO正是 rules/php/coding-style.md 中在框架/请求输入进入领域逻辑之前转换为已验证 DTO的落地。该文件还要求优先为跨服务边界的数据使用不可变 DTO 与值对象尽可能用readonly属性或不可变构造器承载请求/响应负载数组仅用于简单映射业务关键结构必须提升为显式类。final readonly class CreateOrderData { public function __construct( public int $customerId, public array $items, ) {} }值对象把约束装进类型以金额为例与其到处传递单位不明的整数不如封装Money值对象。skills/laravel-patterns/SKILL.md 展示了如何用 Eloquent 的自定义属性转换Attribute让模型层自动完成值对象与存储标量之间的互转protected function budgetCents(): Attribute { return Attribute::make( get: fn (int $value) Money::fromCents($value), set: fn (Money $money) $money-toCents(), ); }同理标识符UserId、日期范围DateRange等有约束概念都应以值对象呈现构造时校验、行为内聚、不可变共享。这与 rules/php/security.md 中绝不信任未经校验的查询参数、Cookie、请求头与上传文件元数据的原则相辅相成——值对象把校验前置到了类型系统层面。依赖注入面向接口而非框架全局原规则第三条依赖接口或狭窄的服务契约而不是框架全局如 Laravel 门面Facade、服务定位器Service Locator通过构造函数传入协作者对象使代码无需服务定位器查找即可测试。依赖注入DI的核心收益是可测试性当依赖通过构造器显式传入时测试可以用 mock 或内存实现替换真实依赖无需初始化整个框架容器。接口绑定到实现skills/laravel-patterns/SKILL.md 展示了在服务提供者中把接口绑定到具体实现final class AppServiceProvider extends ServiceProvider { public function register(): void { $this-app-bind(OrderRepository::class, EloquentOrderRepository::class); } }业务代码只依赖OrderRepository接口EloquentOrderRepository基于 Eloquent或InMemoryOrderRepository测试用可以在不修改调用方的前提下自由替换。这与 rules/common/patterns.md 中的**仓储模式Repository Pattern**一脉相承将数据访问封装在统一接口之后定义findAll、findById、create、update、delete等标准操作具体实现负责存储细节数据库、API、文件业务逻辑只依赖抽象接口从而轻松切换数据源、简化 mock 测试。服务容器与测试依赖注入使得无 HTTP 启动上下文测试业务服务成为可能测试中手工构造服务并注入内存仓储即可$orders new OrderService(new InMemoryOrderRepository()); $order $orders-create($dto); // 纯 PHP 环境无需 Web 服务器边界Boundaries模型层与第三方 SDK 的隔离原规则第四条提出两道边界当模型层承担的职责超出持久化时将 ORM 模型与领域判断分离——不要让 Eloquent/Doctrine 实体既当数据库映射又当领域决策中心用小型适配器adapter包裹第三方 SDK让代码库其余部分依赖自己的契约而非SDK 的契约。第一道边界的反面教材是胖模型在Model里写满业务规则、支付回调、邮件发送。一旦如此模型同时耦合了数据库、HTTP 与外部服务任何一环变化都会波及全部。正解是让 ORM 模型保持持久化载体的单纯职责业务规则移至服务/Action/领域对象。第二道边界对应经典的**防腐层Anti-Corruption Layer**思想定义自己的接口如PaymentGateway再写一个实现内部调用 Stripe SDK。这样升级 SDK 或更换供应商时改动被限制在适配器内部不会扩散到整个代码库。路由边界的补充skills/laravel-patterns/SKILL.md 还从路由层补充了边界意识嵌套路由使用**作用域绑定scoped bindings**防止跨租户访问Route::scopeBindings()-group(function () { Route::get(/accounts/{account}/projects/{project}, [ProjectController::class, show]); });scopeBindings保证{project}必须在{account}的范围内解析这本质上是把资源归属边界声明进了路由契约与模型层不越界做领域判断同属边界治理的不同侧面。与风格、测试、安全规则的协同patterns.md不是孤立的架构口号它与 rules/php/ 其他规则构成完整闭环维度规则文件与模式规则的协同点编码风格rules/php/coding-style.mddeclare(strict_types1)、PSR-12、readonly属性让 DTO/值对象模式真正落地测试rules/php/testing.md服务级测试验证业务规则、控制器测试验证传输层印证薄控制器分层安全rules/php/security.md框架边界统一校验输入、预处理语句、password_hash()与 DTO 前置校验互为表里钩子rules/php/hooks.md编辑后自动运行 Pint/PHPStan/PHPUnit把模式违规拦截在提交之前其中 rules/php/hooks.md 描述的PostToolUse钩子尤其值得实践配置在~/.claude/settings.json中对编辑过的.php文件自动执行 Pint/PHP-CS-Fixer 格式化、PHPStan/Psalm 静态分析、PHPUnit/Pest 定向测试并对遗留的var_dump、dd、dump、die()以及绕过 CSRF/会话保护的行为给出告警。这意味着架构模式不仅写在规则里还通过工具链在每次编辑后强制执行。静态分析与 Composer 脚本rules/php/coding-style.md 要求把 Composer 脚本纳入版本控制使本地与 CI 执行完全一致的命令{ scripts: { format: vendor/bin/pint, analyse: vendor/bin/phpstan analyse --memory-limit1G, test: vendor/bin/phpunit } }静态分析PHPStan/Psalm是 DTO 与值对象模式的守门员关联数组无法被静态分析追踪形状而显式类 类型声明可以在不运行任何测试的情况下暴露类型错误。参考资源速查本篇主骨架rules/php/patterns.mdPHP 专属模式规则通用模式仓储模式、API 响应信封rules/common/patterns.md编码风格与不可变性rules/php/coding-style.md测试框架与分层rules/php/testing.md安全边界与依赖治理rules/php/security.md编辑后自动执行的工具链rules/php/hooks.mdLaravel 专属架构Action、FormRequest、Eloquent 模式、作用域绑定skills/laravel-patterns/SKILL.mdAPI 端点约定与响应形状资源命名、状态码、分页、错误结构skills/api-design/SKILL.md小结四条模式如何组成一个自洽体系将原规则的四个要点串联起来可以看到一套完整的架构方法论薄控制器 显式服务解决了职责放哪的问题——HTTP 只管传输业务逻辑独立可测DTO 值对象解决了数据怎么传的问题——用显式类型承载请求、命令与外部负载把约束前置到类型层依赖注入解决了依赖怎么给的问题——面向接口、构造器注入让可测试性成为默认边界划分解决了变更影响面多大的问题——ORM 模型与领域判断分离、第三方 SDK 收敛进适配器把架构腐化的风险隔离在最小范围。这四条模式相互支撑、缺一不可配合 rules/php/ 家族规则与 skills/laravel-patterns/SKILL.md、skills/api-design/SKILL.md 技能共同构成一份从写代码到守边界的完整 PHP 工程约束。无论你正在新建一个 Laravel API、重构遗留的胖控制器还是评估第三方 SDK 的接入方式都可以直接以本规则为清单逐条对照落地。【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考