惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The GitHub Blog
The GitHub Blog
爱范儿
爱范儿
T
The Blog of Author Tim Ferriss
T
Tailwind CSS Blog
美团技术团队
WordPress大学
WordPress大学
F
Fortinet All Blogs
IT之家
IT之家
阮一峰的网络日志
阮一峰的网络日志
云风的 BLOG
云风的 BLOG
F
Full Disclosure
博客园 - 三生石上(FineUI控件)
Microsoft Azure Blog
Microsoft Azure Blog
U
Unit 42
博客园 - 【当耐特】
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Blog — PlanetScale
Blog — PlanetScale
V
Visual Studio Blog
P
Proofpoint News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
LangChain Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Secure Thoughts
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Heimdal Security Blog
W
WeLiveSecurity
Cloudbric
Cloudbric
N
News and Events Feed by Topic
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
G
Google Developers Blog
Attack and Defense Labs
Attack and Defense Labs
Google Online Security Blog
Google Online Security Blog
S
Security Affairs
S
Security @ Cisco Blogs
雷峰网
雷峰网
有赞技术团队
有赞技术团队
Webroot Blog
Webroot Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cyber Attacks, Cyber Crime and Cyber Security
Spread Privacy
Spread Privacy
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Engineering at Meta
Engineering at Meta
P
Palo Alto Networks Blog
D
DataBreaches.Net
Application and Cybersecurity Blog
Application and Cybersecurity Blog

博客园 - 刘俊涛的博客

qoder-体验分享 50+专家角色+多代理框架,一个人就能建起一支AI 公司 小米突然放大招!2亿 Token 免费领,最后几天冲刺! 这个项目把浏览器“干了30年的事”干掉了:Pretext 为什么突然爆火? 通用商品打标模块实现方案(基于位运算,适配多框架多语言) 后端工程中使用 Model + Trait 设计可复用的数据模型(完整实现示例) 最小阻力之路 U盘打不开 : 文件损坏 : 提示需要格式化?用CHKDSK轻松修复教程 祂看顧麻雀(His Eye Is on the Sparrow)鄭漢良 别再把一切都变成数组了:用迭代器让 JavaScript 既快又省心 Spark性能调优实战笔记 Spark神操作:轻松拿捏公司“历史烂数据”,一人干翻十年脏表 特定血型血液生成的研究进展:化学合成与微生物生产技术路线 禁止直接 update 业务关键字段 非暴力沟通 PHP 8.5 新特性速览:管道操作符、clone with、闭包增强与更多实用功能 从错误中学习 产品拆解到底怎么做?8步框架,新手产品经理必学干货! 《创作与爱:托芙·扬松传》读书笔记 MongoDB 端口安全加固方案 为什么软件反应特别慢?一次因版本架构错误导致的性能问题排查记录 【Go 语言神器】iota 到底是什么?为什么高手都爱用它?
PHP 8.1+ 引入的 枚举(Enum) 类型
刘俊涛的博客 · 2026-02-09 · via 博客园 - 刘俊涛的博客

PHP 8.1+ 引入的 枚举(Enum) 类型

PHP 8.1+ 引入的 枚举(Enum) 类型,用于定义订单的各种状态,并实现了一个简单的状态机(State Machine),控制订单状态只能按照合理的业务流程进行变更。

1. 枚举定义部分(5 个订单状态)

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 更清晰、更安全。

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("非法状态变更!");
}

这样就强制保证了:

  • 不会出现业务上不可能的状态跳转
  • 所有状态变更都是合法、可控的
  • 防止程序 bug 或恶意操作导致数据混乱

总结成一张状态流转图

待支付 (1)
   ├──→ 已支付 (2)
   │      ├──→ 已发货 (3)
   │      │      └──→ 已完成 (4)  (结束)
   │      └──→ 已取消 (5)  (结束)
   └──→ 已取消 (5)  (结束)

已完成 (4) 和 已取消 (5) 不能再变到任何状态

这就是一个典型的电商订单状态机。是生产环境中保护订单数据一致性的核心机制。

Don’t reinvent the wheel, library code is there to help.

欢迎关注公-众-号【TaonyDaily】、留言、评论,一起学习。