到底为什么PHP要有领域实体 (Entity)?
它的本质是**领域实体 (Entity) 是为了在代码中锚定“我是谁” (Identity)而不仅仅是“我有什么” (Attributes)。核心定义Entity 是一个通过唯一标识符 (ID)来区分的对象。即使它的所有属性都变了只要 ID 不变它依然是同一个实体。对比值对象 (Value Object)值对象由属性值定义。两个地址如果街道、城市一样它们就是相等的 ($addr1 $addr2)。没有独立身份。实体由ID定义。两个用户即使名字、年龄完全一样只要 ID 不同他们就是不同的人 ($user1 ! $user2)。存在理由追踪变化 (Change Tracking)因为实体有唯一身份系统可以记录“张三”从“单身”变成了“已婚”。如果没有实体概念这只是两条不同的记录无法体现演变过程。承载行为 (Behavior Carrier)实体不仅是数据容器更是业务规则的守护者。它知道如何修改自己的状态才合法如User::changeEmail()内部校验格式。长期持久化 (Long-term Persistence)实体通常对应数据库中的一行需要在多次请求、甚至数年间保持身份一致。核心逻辑别把 Entity 当成数据库表的简单映射。它是业务世界中有生命、有历史、有身份的核心角色。数组和 DTO 是死的快照Entity 是活的参与者。如果把业务系统比作户籍管理系统值对象 (VO)是家庭住址。“北京市朝阳区xx路1号”。如果两个人住这里这个地址是一样的。地址本身没有“身份证”它依附于人。领域实体 (Entity)是公民本人。每个人有唯一的身份证号 (ID)。即使他改了名字、换了住址、长了皱纹属性变化他的身份证号不变他依然是同一个人。警察系统通过身份证号追踪他的犯罪记录、婚姻状况状态历史。核心逻辑Entity 提供了时间的连续性。它让系统记得“过去的那个他”和“现在的他是同一个”。一、身份与连续性为什么 ID 如此重要1. 唯一性约束 (Uniqueness Constraint)机制Entity 必须有一个全局或聚合内唯一的 ID。价值在分布式系统中ID 是跨服务引用同一事物的唯一依据。在数据库中ID 是主键确保数据不重复。代码体现if ($user1-getId() $user2-getId()) { ... }2. 状态演变 (State Evolution)场景订单状态流转Created - Paid - Shipped - Completed。Entity 作用订单实体持有当前状态。它提供方法pay()内部检查是否处于Created状态然后转为Paid。价值保证了状态变更的合法性和可追溯性。如果是纯数据数组任何人都可以把状态改成Completed而跳过Paid导致业务漏洞。3. 相等性判断 (Equality Check)规则实体的相等性只比较 ID不比较其他属性。publicfunctionequals(self$other):bool{return$this-id$other-id;}价值即使两个用户对象是从不同查询加载的属性略有差异如一个加载了详情一个没加载只要 ID 相同业务上就视为同一人。 核心洞察Entity 是时间轴上的一个点。它连接了过去、现在和未来。ID 是那条贯穿时间的线。二、行为封装Entity 不是数据结构1. 保护不变量 (Protecting Invariants)原则Entity 的任何公共方法执行后对象必须处于合法状态。示例classOrder{publicfunctionaddItem(Product$product):void{if($this-status!OrderStatus::CREATED){thrownewLogicException(Cannot add items to a completed order.);}$this-items[]$product;$this-recalculateTotal();// 自动维护一致性}}价值将业务规则内聚在实体内部防止外部代码破坏业务逻辑。2. 领域事件发布 (Domain Event Publishing)场景用户注册成功后需要发送欢迎邮件、增加积分。Entity 作用publicfunctionregister():void{// ... 逻辑$this-recordEvent(newUserRegistered($this-id));}价值实体不仅改变自身状态还通知外界“我发生了变化”实现解耦。3. 延迟加载与关联管理场景获取用户时不立即加载其所有订单。Entity 作用内部持有代理对象只有在访问$user-getOrders()时才触发查询。价值优化性能同时保持对象模型的完整性。三、与 ORM 模型的区别为什么不能直接用 Eloquent/Doctrine很多开发者混淆了ORM 模型和领域实体。维度ORM 模型 (Active Record/Data Mapper)领域实体 (Domain Entity)主要职责数据持久化 (CRUD)业务逻辑与规则依赖依赖数据库连接/框架无外部依赖 (Pure PHP)关注点怎么存 (How to Save)是什么 (What it Is)方法save(),delete(),find()changePassword(),activate()测试需集成测试 (连库)单元测试 (内存中)最佳实践作为基础设施层作为领域层核心现代架构建议分离领域实体应该是纯粹的 PHP 对象不包含 SQL 逻辑。映射使用 Repository 模式将 ORM 模型的数据转换为领域实体或在实体上使用 Trait 辅助持久化但尽量保持实体纯净。价值这样即使更换数据库或 ORM 框架核心业务逻辑实体无需修改。四、认知牢笼常见误区1. 误区“Entity 就是数据库表的一行。”真相表是存储结构Entity 是业务概念。一个 Entity 可能映射到多张表如继承策略或多张表组成一个 Entity。对策从业务语言命名 Entity而非数据库表名。2. 误区“所有对象都是 Entity。”真相如果对象没有唯一身份且由其属性定义相等性它是值对象 (Value Object)如金钱、颜色、坐标。对策区分 Entity 和 VO。VO 更轻量不可变适合计算。3. 误区“Entity 应该包含所有业务逻辑。”真相涉及多个实体交互的逻辑如转账从 A 扣钱给 B 加钱应放在领域服务 (Domain Service)中。对策Entity 处理单个个体的规则Service 处理群体协作。4. 误区“Entity 必须有 Getter/Setter。”真相过度暴露 Getter/Setter 会导致贫血模型。对策提供意图明确的方法如promoteToAdmin()而非setRole(admin)。5. 误区“PHP 性能差不适合搞复杂的 Entity。”真相现代 PHP OPcache 性能足够支撑大多数业务。清晰的 Entity 模型能减少 Bug降低维护成本这比微小的 CPU 节省更有价值。对策合理设计聚合根避免加载过大的对象图。 总结原子化“领域实体”全景图维度关键点本质通过唯一 ID 标识的业务对象具有连续性和状态核心价值身份追踪、业务规则封装、状态合法性保障关键特征唯一 ID、基于 ID 的相等性、可变状态、行为方法与 VO 区别Entity 看 IDVO 看值与 ORM 区别Entity 关注业务ORM 关注持久化PHP 隐喻Citizen with ID Card (Entity) vs. Home Address (VO)公式Identity (Unique_ID × State_History) ^ Business_Rules终极心法领域实体的本质是“业务世界的锚点”。它在流动的数据中确立了不变的自我。它让系统拥有了记忆让逻辑拥有了归属。于身份中见连续于行为中见规则以实体为尺解离散之牛于领域建模中求真实之真。行动指令识别实体在你的项目中找出哪些对象有唯一 ID 且状态会变如 User, Order, Product。提取行为检查这些对象的 Setter看能否将其重构为更具语义的方法如cancel()替代setStatus(cancelled)。区分 VO找出哪些对象只是值的组合如 Money, DateRange将其改为不可变的值对象。思维升级记住Entity 是你业务核心的代言人。保护好它的不变量就是保护好业务的底线。