
本文旨在探讨在 PHP 中如何根据字符串值获取枚举(Enum)的对应案例。我们将重点介绍 `BackedEnum` 的原生 `tryFrom()` 方法,以及针对纯枚举(Pure Enum)没有显式字符串值时,如何通过自定义静态方法遍历枚举案例并匹配其名称来实现这一功能,并提供详细代码示例。
在 PHP 8.1 及更高版本中引入的枚举(Enums)为定义一组有限的、命名常量集合提供了一种强大且类型安全的方式。在实际应用中,我们经常需要根据一个字符串(例如,来自用户输入或数据库)来获取对应的枚举案例(Enum Case)。这在处理不同类型的枚举时,其实现方式有所不同。
1. 使用 Backed Enums 的原生方法:tryFrom() 和 from()
如果您的枚举是“支持枚举”(Backed Enum),即每个枚举案例都关联了一个显式的标量值(字符串或整数),那么 PHP 提供了一个非常方便的原生方法来根据这些值获取枚举案例。
什么是 Backed Enum? Backed Enum 的每个案例都必须声明一个唯一的标量值。例如:
获取枚举案例 对于 Backed Enum,可以使用 tryFrom() 或 from() 方法根据其关联的字符串或整数值来获取对应的枚举案例。
- tryFrom(string|int $value): ?self: 尝试从给定的值获取枚举案例。如果找不到匹配的案例,它将返回 null,而不会抛出错误。
- from(string|int $value): self: 从给定的值获取枚举案例。如果找不到匹配的案例,它将抛出 ValueError 异常。
示例代码:
立即学习“PHP免费学习笔记(深入)”;
getMessage() . "\n"; } ?>
这种方式是获取 Backed Enum 案例的首选方法,因为它简洁、高效且是 PHP 原生支持的。
2. 纯枚举(Pure Enums)的挑战与自定义解决方案
什么是 Pure Enum? 纯枚举(Pure Enum)的案例没有显式关联的标量值。它们仅仅是命名常量。例如:
对于纯枚举,tryFrom() 和 from() 方法是不可用的,因为它们没有底层值可供匹配。然而,每个枚举案例都有一个内部的名称(name)属性,它是一个字符串,与声明的案例名称完全一致。例如,Action::CREATE->name 将返回字符串 "CREATE"。
问题: 如何根据一个字符串(例如 "CREATE")来获取 Action::CREATE 这个枚举案例?
解决方案: 由于没有原生方法,我们需要编写一个自定义的静态方法来遍历所有可用的枚举案例,并将其 name 属性与输入的字符串进行比较。
实现自定义 get() 方法
我们可以在枚举内部添加一个静态方法,例如 get(),来封装这个逻辑:
name === $normalizedName) {
return $status;
}
}
return null; // 未找到匹配的案例
}
}
// 使用自定义的 get() 方法
$statusOk = Status::get("OK"); // 返回 Status::OK
$statusFailed = Status::get("failed"); // 返回 Status::FAILED (由于 strtoupper)
$statusPending = Status::get(" PENDING "); // 返回 Status::PENDING (由于 trim)
$statusInvalid = Status::get("UNKNOWN"); // 返回 null
var_dump($statusOk);
var_dump($statusFailed);
var_dump($statusPending);
var_dump($statusInvalid);
// 访问枚举案例的名称属性
echo "Status::OK 的名称是: " . Status::OK->name . "\n"; // 输出 "OK"
?>代码解析:
- self::cases(): 这是一个 PHP 枚举的内置静态方法,它返回一个包含所有枚举案例的数组。
- strtoupper(trim($name)): 这行代码对输入的字符串进行了预处理。trim() 去除了字符串两端的空白字符,strtoupper() 将字符串转换为大写。这样做可以使查找功能更健壮,允许用户输入大小写不敏感或带有额外空格的名称。
- $status->name: 每个枚举案例都有一个只读的 name 属性,它返回该案例的字符串名称(例如,对于 case OK;,name 就是 "OK")。
- 循环比较: 代码遍历 self::cases() 返回的数组,将每个案例的 name 属性与预处理后的输入字符串进行严格比较(===)。
- 返回结果: 如果找到匹配项,则返回对应的枚举案例;如果遍历完所有案例仍未找到,则返回 null。
3. 注意事项与总结
- 选择合适的枚举类型: 如果你的枚举案例需要关联一个唯一的、可用于查找的字符串或整数值,优先考虑使用 Backed Enum。这将允许你利用原生的 tryFrom() 方法,代码更简洁且性能更优。
- 纯枚举的灵活性: 纯枚举适用于只需要一组命名常量,而无需额外底层值的情况。当需要根据字符串名称获取纯枚举案例时,自定义的静态 get() 方法是最佳实践。
-
错误处理:
- 对于 BackedEnum::from(),如果匹配失败会抛出 ValueError,因此在使用时应考虑 try-catch 块。
- BackedEnum::tryFrom() 和自定义的 get() 方法在匹配失败时返回 null,这使得错误处理更加平滑,你可以通过检查返回值是否为 null 来判断是否成功获取到案例。
- 性能考量: 自定义的 get() 方法涉及遍历所有枚举案例。对于拥有大量案例的枚举,这可能会有轻微的性能开销,但对于大多数实际应用场景,这种开销通常可以忽略不计。如果性能成为瓶颈,可以考虑在 get() 方法内部维护一个静态缓存映射(例如 ['OK' => Status::OK, ...]),但通常不必要。
通过理解 Backed Enums 的原生 tryFrom() 方法和为纯枚举实现自定义 get() 方法,你可以在 PHP 中灵活高效地根据字符串值获取所需的枚举案例,从而提高代码的可读性和健壮性。










