本文旨在深入探讨在 PHP 中如何通过字符串名称或值获取枚举(Enum)成员的实用策略。我们将详细介绍利用支持枚举(Backed Enums)的 `tryFrom` 或 `from` 方法,以及为纯枚举(Pure Enums)实现自定义静态查找功能,旨在解决在不重复定义字符串值的情况下进行高效查找的需求。
在 PHP 8.1 及更高版本中引入的枚举(Enums)为定义一组有限的常量值提供了强大的类型安全机制。在实际开发中,我们经常需要根据一个字符串(例如,从用户输入、API 请求或数据库中获取)来查找并获取对应的枚举成员。本文将详细介绍两种主要的方法来解决这一常见需求。
PHP 枚举分为两种类型:纯枚举(Pure Enums)和支持枚举(Backed Enums)。支持枚举允许每个枚举成员关联一个标量值(字符串或整数),这为通过这些值进行查找提供了便利的内置机制。
要创建一个支持枚举,你需要为它指定一个类型(string 或 int),并为每个成员提供一个相应类型的值。
在这个例子中,Status 枚举的每个成员都关联了一个字符串值。值得注意的是,为了通过成员的名称(例如 "OK")进行查找,我们通常会将成员的名称作为其关联值,尽管这正是用户最初试图避免的“重复定义”。
2. 使用 tryFrom 和 from 方法
支持枚举提供了两个静态方法来根据其关联值进行查找:
示例代码:
getMessage() . "\n"; } // 获取枚举成员的名称和值 echo "Status::OK 的名称: " . Status::OK->name . "\n"; // 输出: OK echo "Status::OK 的值: " . Status::OK->value . "\n"; // 输出: OK
优点:
局限性:
当你不希望为每个枚举成员重复定义一个与其名称相同的字符串值时,纯枚举结合自定义静态方法是一个更灵活的选择。纯枚举不关联任何标量值,但每个枚举成员都隐式地拥有一个 name 属性,其值为该成员的声明名称。
纯枚举的定义不指定任何类型或关联值:
2. 实现自定义静态查找方法
我们可以为纯枚举添加一个自定义的静态方法,该方法遍历所有枚举成员,并将其 name 属性与输入的字符串进行比较。
示例代码:
name) === $cleanedName) { return $status; } } // 如果遍历结束后仍未找到匹配项,则返回 null return null; } } // 使用自定义的 get 方法进行查找 $status1 = Status::get("OK"); // 返回 Status::OK $status2 = Status::get("failed"); // 返回 Status::FAILED (由于内部转换为大写) $status3 = Status::get(" pending "); // 返回 Status::PENDING (去除空格并转换为大写) $status4 = Status::get("UNKNOWN"); // 返回 null $status5 = Status::get(""); // 返回 null // 获取纯枚举成员的名称 echo "Status::OK 的名称: " . Status::OK->name . "\n"; // 输出: OK实现原理:
- Status::cases(): 这是一个内置的静态方法,它返回一个包含所有枚举成员的数组。
- $status->name: 每个枚举成员(无论是纯枚举还是支持枚举)都有一个 name 属性,它返回该成员的声明名称(例如,Status::OK->name 返回 "OK")。
- 循环比较: 代码遍历 Status::cases() 返回的数组,将每个成员的 name 属性与传入的 $name 参数进行比较。
- 清理和标准化: 示例中的 get 方法还包含了 strtoupper(trim($name)),这使得查找更加健壮,可以处理输入字符串的大小写不一致和前后空格问题。
优点:
注意事项:
在决定使用哪种方法时,请考虑以下因素:
是否有业务关联值?
是否仅通过成员名称查找,且不希望重复定义值?
代码简洁性与可维护性:
在 PHP 中通过字符串获取枚举成员,主要有两种策略:
根据你的具体需求和对代码简洁性、灵活性以及数据冗余的权衡,选择最适合你的方法。在大多数情况下,如果枚举的名称本身就是你想要查找的字符串,自定义的 g
et 方法可以提供一个更“纯粹”的解决方案,避免了 Backed Enum 中名称与值重复的问题。