为什么“Enumerations on PHP”是一个价值百万的问题?
\n\n如果你曾经搜索过“enumerations on PHP”,你就会知道:在PHP 8.1发布之前,这个话题简直是一场冒险。开发者们用常量、抽象类和巧妙的trait发明了各种“轮子”。Stack Overflow上充斥着诸如“如何在PHP中模拟Enum?”之类的问题,而答案则收获了数百个赞。
\n\n但时代变了。从PHP 8.1开始,枚举(Enum)成为了语言的原生部分。这不仅仅是语法糖——它是一个用于编写干净、安全且自文档化代码的强大工具。
\n\n在本文中,我们将全面解析:从经典的常量方法到现代的Enum,并附有真实示例和最佳实践。开始吧!
\n\n问题:PHP 8.1之前的开发者是如何生存的
\n\n在原生枚举出现之前,我们主要有两种方法:类常量和带有抽象类的“权宜之计”。我们来看看这两种方法。
\n\n方法#1:类常量(最流行)
\n\nclass OrderStatus {\n const PENDING = 'pending';\n const PROCESSING = 'processing';\n const SHIPPED = 'shipped';\n const DELIVERED = 'delivered';\n const CANCELLED = 'cancelled';\n}\n\n// 使用\n$status = OrderStatus::PENDING;\nif ($status === OrderStatus::PROCESSING) {\n echo '订单正在处理';\n}\n\n优点:简单、易懂、IDE自动补全。
\n缺点:缺乏类型检查。任何人都可以传递字符串'invalid_status'——而PHP不会报错。
\n\n方法#2:抽象类 + 私有构造函数
\n\n高级开发者更进一步:
\n\nabstract class OrderStatus {\n private function __construct() {}\n \n public static function pending(): self {\n return new class extends OrderStatus {};\n }\n public static function processing(): self {\n return new class extends OrderStatus {};\n }\n // ... 其余状态\n}\n\n这虽然可行,但代码变得臃肿。而且这仍然是模拟,而不是真正的语言支持。
\n\nPHP 8.1中的原生Enum:一场革命
\n\n随着PHP 8.1的发布,“enumerations on PHP”的问题被一劳永逸地解决了。现在,枚举是完整的类型,它们:
\n\n- \n
- 支持严格类型检查 \n
- 拥有内置方法(
name、value、cases()) \n - 可以实现接口 \n
- 支持trait \n
- 与
match和switch集成 \n
PHP中Enum的基本语法
\n\nenum OrderStatus {\n case Pending;\n case Processing;\n case Shipped;\n case Delivered;\n case Cancelled;\n}\n\n// 使用\n$status = OrderStatus::Pending;\necho $status->name; // 'Pending'\n\n简单而优雅。但这只是开始。
\n\nEnum的类型:纯枚举和带值的枚举
\n\nPHP支持两种类型的枚举:
\n\n1. Pure Enum(纯枚举)
\n不绑定到特定值。非常适合标志、状态、类型。
\n\nenum UserRole {\n case Admin;\n case Editor;\n case Viewer;\n}\n\nfunction checkAccess(UserRole $role): bool {\n return match($role) {\n UserRole::Admin => true,\n UserRole::Editor => true,\n UserRole::Viewer => false,\n };\n}\n\n2. Backed Enum(带值的枚举)
\n当需要将枚举与特定值(字符串或整数)关联时使用。
\n\nenum OrderStatus: string {\n case Pending = 'pending';\n case Processing = 'processing';\n case Shipped = 'shipped';\n case Delivered = 'delivered';\n case Cancelled = 'cancelled';\n}\n\n// 获取值\n$status = OrderStatus::Shipped;\necho $status->value; // 'shipped'\n\n// 从值创建\n$