PHP枚举核心在于类型安全:仅当值集合代表不可混用的离散业务状态时才使用;外部输入须用tryFrom()安全转换;持久化必须用BackedEnum的->value而非->name。

enum 不是语法糖,它是类型系统的一部分——用错地方反而会引入隐性 bug。
什么时候该用 enum 而不是 const 或数组?
核心判断标准:这个值集合是否代表「业务上不可混用的离散状态」,且你希望 PHP 在编译/运行时帮你拦住非法赋值。
- ✅ 适合:
Status::Approved(审批状态)、HttpMethod::POST(HTTP 方法)、PaymentStatus::Paid(支付状态)——这些值之间逻辑互斥,且后续可能要加方法或映射数据库字段 - ❌ 不适合:
['admin', 'user', 'guest']这类纯配置列表;或者需要动态增删的选项(枚举 case 数量固定,不能 runtime 添加) - ⚠️ 注意:如果只是存几个常量、不参与类型约束、也不需要
->name或->value,用class+const更轻量
tryFrom() 是处理用户输入的唯一安全入口
从表单、API 请求、数据库查出来的字符串/数字,绝不能直接强转或用 constant() 拼接调用——那会抛 ValueError 或返回 null 导致静默失败。
- 对
BackedEnum(带: string或: int的枚举),必须用::tryFrom($input),它返回?self - 检查结果不能为空:
if ($status = Status::tryFrom($_GET['status'])) { ... },不能跳过判空 - 不要用
::from()处理不可信输入——它在找不到时直接 throwValueError,没 catch 就崩 - 对纯枚举(无 backing value),
tryFrom()不存在,得自己写静态方法遍历cases()匹配->name
别把 ->name 当成可序列化的值用
Status::Pending->name 返回字符串 "Pending",但它只是调试用的标识符,不是设计用来存库或传 API 的。
- 需要持久化或跨系统通信,必须用
BackedEnum,比如enum Status: string { case Pending = "pending"; },然后存$status->value - 纯枚举的
->name大小写敏感、不可重构(改名就断),一旦用在数据库字段或 JSON key 里,后期维护成本极高 -
->name不能用于match的键(match($status->name)是错的),应该直接match($status)
想批量导出枚举列表?用 cases() + array_column()
前端下拉、管理后台选项渲染、Swagger 文档生成,都需要枚举所有合法值。PHP 原生提供了 cases() 方法,别手写数组。
立即学习“PHP免费学习笔记(深入)”;
-
array_column(Status::cases(), 'name')→['Pending', 'Approved', 'Rejected'] -
array_column(Status::cases(), 'value', 'name')(仅 BackedEnum)→['Pending' => 'pending', ...] - 注意:
cases()返回的是对象数组,不是键值对,不能直接json_encode()出结构化数据,得先映射 - 如果要带 label,就在枚举里加方法:
public function label(): string { return match($this) { ... };,再用array_map(fn($c) => ['value' => $c->value, 'label' => $c->label()], Status::cases())
Status::Pending 很简单,但真正起作用的是当你把 function handle(Status $s) { ... } 写进签名后,PHP 会拒绝任何非 Status 实例的传参——这种保护,只有枚举能给你。



















