CQRS和事件溯源在PHP中的应用:复杂项目的架构

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么当项目增长时,普通的CRUD会失效



想象一下:你正在用PHP编写一个在线商店。一开始一切都很简单——添加商品、修改价格、删除商品。但半年过去了,新的需求出现了:所有变更的审计、按特定日期恢复数据、复杂的折扣逻辑。普通的CRUD(创建、读取、更新、删除)开始捉襟见肘。数据库变得一团糟,而客户的每一个新请求都要求重写一半的系统。



熟悉吗?那么你一定会需要CQRS(命令查询职责分离)和事件溯源——这两个强大的模式改变了开发方式。在本文中,我们将通过真实的PHP示例来解析它们,以便你可以在自己的项目中应用它们。



用简单的话说,什么是CQRS和事件溯源



CQRS:命令与查询的分离



CQRS是一种架构模式,它将操作分为两种类型:命令(改变状态)和查询(读取状态)。在经典的MVC中,控制器和模型都处理相同的实体。CQRS建议将这些职责分开。



想象一个图书馆:有一个专门用于登记书籍的桌子(命令),另一个专门用于阅读的桌子(查询)。它们互不干扰,并且各自针对自己的任务进行了优化。



事件溯源:变更历史而非当前状态



事件溯源是一种数据存储方式,你保存的不是对象的当前状态,而是导致该状态的一系列事件。不是存储一行“订单#123:状态 = 已送达”,而是存储:“订单已创建 → 已付款 → 已发货 → 已送达”。



这就像视频记录而不是照片:你总是可以回放,查看任何时刻发生了什么。



何时在PHP中应用CQRS和事件溯源



这些模式并非银弹。对于简单的博客来说,它们过于复杂。但以下场景中,它们不可或缺:



  • 复杂的领域逻辑(金融、预订、物流)
  • 审计要求——需要知道谁在何时更改了数据
  • 按任意日期恢复状态
  • 微服务架构——事件可以轻松在服务间传递
  • 高读取负载——可以创建独立的、针对查询优化的读取模型


如果你的项目是一个拥有数千个订单的在线商店、CRM系统或银行应用程序——CQRS和事件溯源绝对会派上用场。



在PHP中实践CQRS的实现



让我们进入代码部分。我们将实现一个简单的订单管理系统。先从CQRS开始。



步骤1:定义命令和查询



命令是一个DTO(数据传输对象),包含执行操作所需的所有数据。命令从不返回数据——只改变状态。



<?php// src/Application/Command/CreateOrderCommand.phpnamespace App\\Application\\Command;

class CreateOrderCommand{ public function __construct( public readonly string $orderId, public readonly string $customerId, public readonly array $items, // [['productId' => '...', 'quantity' => 2], ...] public readonly \\DateTimeImmutable $createdAt ) {}}


查询也是一个DTO,但用于读取。它可以包含过滤器并返回数据。



<?php// src/Application/Query/GetOrderQuery.phpnamespace App\\Application\\Query;

class GetOrderQuery{ public function __construct( public readonly string $orderId ) {}}


步骤2:创建命令处理器



命令处理器是一个执行业务逻辑的服务。它接收命令并改变状态

博客

书籍推荐