























PHP 8.1+ 引入的 枚举(Enum) 类型,用于定义订单的各种状态,并实现了一个简单的状态机(State Machine),控制订单状态只能按照合理的业务流程进行变更。
case PendingPayment = 1; // 待支付
case Paid = 2; // 已支付
case Shipped = 3; // 已发货
case Completed = 4; // 已完成
case Cancelled = 5; // 已取消
这是在定义一个名为 OrderStatus 的枚举(enum),它有 5 个可能的值:
OrderStatus::PendingPayment → 值是 1,代表“待支付”OrderStatus::Paid → 值是 2,代表“已支付”OrderStatus::Shipped → 值是 3,代表“已发货”OrderStatus::Completed → 值是 4,代表“已完成”OrderStatus::Cancelled → 值是 5,代表“已取消”这些值通常对应数据库里 status 字段存储的数字(比如 1、2、3...),这样既节省空间,又方便查询。
使用枚举的好处是:代码里不会出现魔法数字(magic number),写 OrderStatus::Paid 比直接写 2 更清晰、更安全。
public function canTransitionTo(self $newStatus): bool
{
return match ($this) {
self::PendingPayment => in_array($newStatus, [self::Paid, self::Cancelled]),
self::Paid => in_array($newStatus, [self::Shipped, self::Cancelled]),
self::Shipped => $newStatus === self::Completed,
self::Completed => false,
self::Cancelled => false,
default => false,
};
}
这个方法是枚举上的一个实例方法,意思是:当前状态($this)能不能合法地变成某个新状态($newStatus)?
它返回 true 表示“允许变更”,返回 false 表示“不允许,禁止变更”。
我们用大白话 + 图表来解释每一种情况:
| 当前状态($this) | 允许变成的新状态($newStatus) | 不允许变成的状态(会返回 false) | 业务含义解释 |
|---|---|---|---|
| 待支付 (PendingPayment) | 已支付 (Paid) 已取消 (Cancelled) |
不能直接变成 已发货、已完成 | 用户还没付钱,只能支付成功或取消订单 |
| 已支付 (Paid) | 已发货 (Shipped) 已取消 (Cancelled) |
不能变成 待支付、已完成 | 钱已收到,可以发货,或者用户退款取消 |
| 已发货 (Shipped) | 已完成 (Completed) | 不能变成其他任何状态 | 货物在路上,只能等用户签收后完成 |
| 已完成 (Completed) | 不允许变成任何状态 | 所有变更都不允许 | 订单结束了,不能再改 |
| 已取消 (Cancelled) | 不允许变成任何状态 | 所有变更都不允许 | 订单已取消,不能再改 |
假设当前订单状态是 待支付(1):
$current = OrderStatus::PendingPayment;
$current->canTransitionTo(OrderStatus::Paid); // 返回 true → 允许变成“已支付”
$current->canTransitionTo(OrderStatus::Cancelled); // 返回 true → 允许变成“已取消”
$current->canTransitionTo(OrderStatus::Shipped); // 返回 false → 不允许直接变成“已发货”(没付钱怎么发货?)
假设当前是 已支付(2):
$current = OrderStatus::Paid;
$current->canTransitionTo(OrderStatus::Shipped); // true → 可以发货
$current->canTransitionTo(OrderStatus::Cancelled); // true → 可以退款取消
$current->canTransitionTo(OrderStatus::PendingPayment); // false → 不能退回“待支付”
假设当前是 已完成(4):
$current = OrderStatus::Completed;
$current->canTransitionTo(任何状态); // 都返回 false → 彻底锁死,不能再改
这正是你之前提到的规则:核心字段只允许状态驱动修改。
在代码的其他地方(比如订单服务),修改状态前一定会先检查:
if (!$order->getStatus()->canTransitionTo($newStatus)) {
throw new Exception("非法状态变更!");
}
这样就强制保证了:
待支付 (1)
├──→ 已支付 (2)
│ ├──→ 已发货 (3)
│ │ └──→ 已完成 (4) (结束)
│ └──→ 已取消 (5) (结束)
└──→ 已取消 (5) (结束)
已完成 (4) 和 已取消 (5) 不能再变到任何状态
这就是一个典型的电商订单状态机。是生产环境中保护订单数据一致性的核心机制。

Don’t reinvent the wheel, library code is there to help.
欢迎关注公-众-号【TaonyDaily】、留言、评论,一起学习。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。