滚动新闻 →
显卡显示正常但游戏一启动就崩溃,硬件维修应该重点关注哪些方面 四川甘孜营地惊险一幕 牦牛突然闯入顶飞男子 Windows 11 程序无响应怎么处理?不要急着强制关机,可以先这样检查 PHP 枚举 Enum 怎么使用?用更清晰的方式管理固定状态和类型 命大!贵州3岁男童从10楼坠下 被雨棚接住仅受轻伤 屈原为什么成为中国文学史上的重要人物 华佗与传统医学史中的传说与记载 Anthropic或感恩节前挂牌 估值上看2兆美元 山东女游客钢索上被蜂蛰180针休克 赔偿陷僵局 围棋中的官子是什么意思 内塔尼亚胡讲话 以航取消迪拜特别航班 美国9月非农就业新增2.9万人 失业率微升 泰国男驾车冲入观音庙致3人伤 观音像完好无损 中国柔道女将咬日本对手 遭取消资格 美军向中东增兵九千 部署罗斯福号航母 尹登珍狱中身体健康恶化 家属担忧生命安危 培养孩子感恩意识不能只靠说教 卢比奥“十一”贺词 将“繁荣”换成“友善” 自动白平衡和手动白平衡有什么区别 飓风Polo重创墨西哥 小狗示警救一家五口 美F-16V战机今抵台湾 年底还会有新战机交付 中国多地猪瘟 养殖户陷生存困境 史无前例 中国男足主场0-5败给巴勒斯坦 亚历山大大帝的帝国为何迅速扩张又迅速分裂 川普派第三艘航母赴中东 警告伊朗涉劫机案后果 主人摔倒在家 狗狗上街求助把警察带回家 救人超越国籍 沙特医护救以色列乘客画面热传 揭露共产暴行 首届“反共影展”华府登场 广东拟清理101家高新企业 追税风险浮现 中国渔船侵入 台湾水炮驱离 人道救援送热食 印度机长与莫迪通话:我不能让任何人离世 “十一”门面撑不住 从政府到高校过紧日子 走私AI芯片到中国 加州科技老板被捕起诉 中国十一长假疫情扩大 青壮年猝死激增 厨房电器越来越多应该如何合理安排位置 中国人的节庆食品为什么讲究“寓意” 长途自驾旅行最容易遇到哪些问题 G20贸易部长会议聚焦产能过剩 中国成焦点 10月2日维权动态 深圳水疗会拖欠工资 员工罢工讨薪 迪拜航班劫持案 以色列查幕后黑手

PHP 枚举 Enum 怎么使用?用更清晰的方式管理固定状态和类型

发布时间: 2026-10-02 14:24:01    最后更新: 2026-10-02 15:13:41    阅读:2  约15 分钟阅读     

在企业软件、SaaS、后台系统和API开发中,有一类数据看起来只是几个固定值,实际上却直接参与业务逻辑。例如用户可能处于active、inactive、disabled几种状态,订单可能处于pending、paid、cancelled等阶段,权限可能分为read、write、admin。传统PHP项目经常使用整数常量、字符串常量或者数据库字段直接保存这些值,代码能够运行,但随着项目规模扩大,状态值会逐渐散落在控制器、Model、Service和数据库查询中。 PHP 8.1引入Enum以后,这类固定集合可以被建模成真正的类型。枚举不仅可以表达“有哪些合法状态”,还可以让函数参数、返回值、match分支和业务方法围绕这个类型工作,从而减少字符串和整数在系统各处自由流动的问题。 PHP Enum从哪个版本开始支持 原稿中“PHP 7.1引入Enum”这一点是错误的。PHP原生枚举是在PHP 8.1正式加入的,因此使用enum语法的项目最低需要PHP 8.1。 最基本的枚举可以这样定义: enum UserStatus { case Active; case Inactive; case Disabled; } 这里的Active、Inactive和Disabled不是普通字符串,也不是整数常量,而是UserStatus类型的枚举Case。 使用时: $status = UserStatus::Active; 此时$status是一个UserStatus对象实例,而不是字符串"active"。 因此下面的类型声明是有意义的: function updateUserStatus(UserStatus $status): void { // ... } 调用者必须传入UserStatus的Case。如果错误地传入一个普通字符串或整数,在严格的类型检查环境下就会暴露类型问题。 这也是Enum与传统常量最大的区别之一:传统常量主要提供一个名字和值,而Enum首先建立的是一个独立的类型。 Backed Enum适合数据库中的状态字段 实际SaaS系统通常需要把状态保存到MySQL、PostgreSQL等数据库中,因此单纯的Unit Enum还不够方便。 PHP提供了Backed Enum,可以让每个Case关联一个字符串或整数值。 例如: enum UserStatus: string { case Active = 'active'; case Inactive = 'inactive'; case Disabled = 'disabled'; } 现在: $status = UserStatus::Active; echo $status->value; 结果是: active 这里需要区分两个概念。 UserStatus::Active是Enum Case,也就是一个UserStatus对象;$status->value才是与数据库、API或者其他外部系统交互时使用的底层字符串。 因此数据库字段可以保存active,PHP业务层则可以使用: UserStatus::Active 这样可以把数据库中的原始值和业务代码中的类型区分开。 from和tryFrom解决外部值转换问题 Backed Enum还有两个非常实用的方法:from()和tryFrom()。 如果确定外部值一定合法,可以使用: $status = UserStatus::from('active'); 它会得到: UserStatus::Active 如果传入不存在的值,例如: $status = UserStatus::from('unknown'); 则会抛出ValueError。 对于来自用户输入、数据库旧数据或者第三方API的数据,通常更适合: $status = UserStatus::tryFrom('unknown'); 找不到对应Case时,tryFrom()返回null,而不是直接抛出异常。 例如: $status = UserStatus::tryFrom($input); if ($status === null) { // 非法状态值 } 这在API参数验证和旧系统数据迁移中尤其有用。 Enum与match组合后业务逻辑会更加清晰 Enum最适合与PHP 8.0加入的match表达式结合。 正确写法应该是: $message = match ($status) { UserStatus::Active => '用户已激活', UserStatus::Inactive => '用户未激活', UserStatus::Disabled => '用户已禁用', }; 这里不能写成: UserStatus::Active => echo '用户已激活' 因为match的每个分支需要产生一个表达式结果,而echo不是这种用法下的返回表达式。 Enum和match结合还有一个非常重要的工程价值:状态集合发生变化时,业务代码更容易发现遗漏。 例如以后新增: case Pending; 那么原来的match如果没有处理Pending,在运行时就可能出现未匹配分支的问题。 相比散落在代码中的: if ($status === 'active') { ... } elseif ($status === 'inactive') { ... } Enum能够让状态集合拥有更加明确的边界。 Enum可以定义自己的方法 Enum并不是只能存储几个Case。 它可以定义方法: enum UserStatus: string { case Active = 'active'; case Inactive = 'inactive'; case Disabled = 'disabled'; public function label(): string { return match ($this) { self::Active => '已激活', self::Inactive => '未激活', self::Disabled => '已禁用', }; } } 调用: $status = UserStatus::Active; echo $status->label(); 这样与状态相关的显示逻辑就可以集中在Enum内部,而不是在几十个Controller中重复写。 当然,也不能把所有业务逻辑都塞进Enum。简单的状态描述、状态分类、是否允许某种操作等与状态本身高度相关的逻辑适合放进去;如果涉及数据库查询、外部API、复杂工作流或者多个领域对象,则应该继续放在Service等业务层。 Enum可以遍历所有Case 如果需要获取一个枚举的所有Case,可以使用: foreach (UserStatus::cases() as $status) { echo $status->value; } cases()会返回这个Enum定义的所有Case。 这对于后台管理页面生成状态选项、API文档、验证逻辑或者测试数据都很方便。 例如: foreach (UserStatus::cases() as $status) { echo ''; } 这样新增一个状态以后,前端选项可以通过统一逻辑自动生成,而不需要手工维护一组字符串。 Enum也可以实现接口 如果多个Enum需要提供统一能力,可以让它们实现接口。 例如: interface HasLabel { public function label(): string; } 然后: enum UserStatus: string implements HasLabel { case Active = 'active'; case Disabled = 'disabled'; public function label(): string { return match ($this) { self::Active => '已激活', self::Disabled => '已禁用', }; } } 这样其他代码就可以依赖接口,而不是依赖某一个具体Enum。 这也是Enum逐渐从“固定值列表”变成业务类型的重要原因。 Enum与数据库设计不能混为一谈 PHP Enum并不意味着数据库一定要使用MySQL的ENUM字段。 例如PHP可以使用: enum OrderStatus: string { case Pending = 'pending'; case Paid = 'paid'; case Cancelled = 'cancelled'; } 数据库完全可以使用: status VARCHAR(20) NOT NULL 然后在应用层将数据库值转换为OrderStatus。 对于很多SaaS系统,这种设计比把业务状态完全绑定到数据库原生ENUM更加灵活。 如果业务状态变化频繁,数据库CHECK约束、外键字典表或者应用层Enum也可以根据具体需求组合使用。 关键不是“必须使用哪一种”,而是要明确哪一层负责约束什么。 数据库负责数据完整性,PHP Enum负责应用程序类型和业务代码中的状态表达,两者并不是互相替代的关系。 Enum比常量好在哪里 传统代码可能这样定义: class UserStatus { public const ACTIVE = 'active'; public const INACTIVE = 'inactive'; public const DISABLED = 'disabled'; } 然后: $status = UserStatus::ACTIVE; 这种方式当然仍然有效,而且在旧版本PHP项目中非常常见。 问题在于UserStatus::ACTIVE本身不是一个UserStatus类型。数据库查询、HTTP请求、数组和业务逻辑之间仍然可能到处传递字符串。 Enum则可以直接写: function suspendUser(UserStatus $status): void { ... } 这让函数接口本身表达了“这里接受的是哪一种状态”。 静态分析工具、IDE自动补全以及代码重构工具也能够更准确地理解这种关系。 因此Enum的价值并不是“代码更短”,而是让固定集合成为代码中的类型边界。 Enum也不是所有固定值都应该使用 Enum同样不能滥用。 如果一个值本身没有固定集合,例如用户昵称、商品名称、电话号码、金额,就不应该因为想要“类型安全”而建立Enum。 如果状态来自动态配置,而且管理员可以随时增加新的类型,那么Enum也未必适合,因为Enum的Case属于代码的一部分,需要经过代码部署才能增加。 还有一种常见误区,是把Enum当成数据库业务规则的全部实现。 例如订单状态从pending变成paid,并不意味着只要Enum里存在这两个Case,就允许任何地方随意修改。 真正的订单状态转换规则可能是: pending → paid pending → cancelled paid → refunded 而: cancelled → paid 可能根本不允许。 Enum负责描述“有哪些状态”,状态机或者业务Service负责描述“状态之间允许怎样转换”。这两个概念需要分开。 在现代PHP项目中,Enum更适合放在领域模型附近 对于一个SaaS项目,可以把类似用户状态、订阅状态、订单状态、支付状态、权限类型等稳定的固定集合定义成Enum。 例如: enum SubscriptionStatus: string { case Trialing = 'trialing'; case Active = 'active'; case PastDue = 'past_due'; case Cancelled = 'cancelled'; } Service层接收: function changeSubscriptionStatus( SubscriptionStatus $status ): void { // ... } 数据库层保存: $status->value 从数据库读取以后: $status = SubscriptionStatus::from($row['status']); 这样数据库、Repository、Service和Controller之间就形成了清晰的类型边界。 如果项目使用ORM,例如Laravel、Symfony生态中的相关组件,也可以进一步利用框架对Backed Enum的支持,让数据库字段与PHP Enum之间进行自动转换,但具体方式应该按照所使用的ORM版本实现,而不是把所有框架都当成同一种行为。 PHP Enum真正有价值的地方,不是把1、2、3换成几个漂亮的名字,而是把原本散落在程序里的“允许值集合”提升成一个明确的类型。对于大型PHP项目,这种边界能够让IDE、静态分析器、测试代码以及开发人员共同理解同一套业务状态。 从传统常量到Enum,变化的也不只是语法。以前程序员需要记住“这个字符串到底可以写什么”,现在可以让类型系统直接参与约束。数据库仍然保存外部值,API仍然需要验证输入,Service仍然负责业务规则,而Enum负责把固定状态集合表达清楚。对于PHP 8.1及以上的新项目,只要业务确实存在稳定的固定值集合,Enum通常比散落的字符串和整数常量更值得优先考虑。

喜欢这篇报道?

使用下面的功能,方便以后继续阅读和分享 MNewsTV

设为 Google 新闻首选来源 让 Google 新闻优先显示 MNewsTV 的最新报道 ›
★ 我的收藏 查看已经收藏的文章
关于文章收藏 收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。 删除收藏请进入「我的收藏」进行管理。
分享这篇报道

捐助(Paypal): https://www.paypal.me/observeccp
订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP