在 PHP 8.1 中,BackedEnum提供了fromandtryFrom方法来从值获取枚举。如何通过无支持的枚举来实现相同的效果?
支持枚举示例:
enum MainType: string
{
case Full = 'a';
case Major = 'b';
case Minor = 'c';
}
var_dump(MainType::tryFrom('a')); // MainType::Full
var_dump(MainType::tryFrom('d')); // null
Run Code Online (Sandbox Code Playgroud)
然而,这对于常规枚举来说并不存在。
我如何按名称检索“正常”枚举,例如:
enum MainType
{
case Full;
case Major;
case Minor;
}
$name = (MainType::Full)->name
var_dump(name); // (string) Full
Run Code Online (Sandbox Code Playgroud)
我发现的一个选择是简单地添加一个tryFromName函数,接受一个字符串并循环遍历所有情况,如下所示:
enum MainType
{
case Full;
case Major;
case Minor;
public static function tryFromName(string $name): ?static
{
foreach (static::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}
return null;
}
}
$name = (MainType::Full)->name
var_dump(name); // (string) Full
var_dump(MainType::tryFromName($name)); // MainType::Full
Run Code Online (Sandbox Code Playgroud)
这是可行的,但是让 foreach 循环遍历所有可能性只是为了创建一个枚举是违反直觉的。
因此问题是,在 PHP 中从名称获取 Enum 的正确方法是什么。
hej*_*dav 10
您可以使用反射:
trait Enum {
public static function tryFromName(string $name): ?static
{
$reflection = new ReflectionEnum(static::class);
return $reflection->hasCase($name)
? $reflection->getCase($name)->getValue()
: null;
}
}
enum Foo {
use Enum;
case ONE;
case TWO;
}
var_dump( Foo::tryFromName('TWO') ); // enum(Foo::TWO)
var_dump( Foo::tryFromName('THREE') ); // null
Run Code Online (Sandbox Code Playgroud)
也适用于支持枚举。
ReflectionEnum我喜欢在@hejdav 的答案中使用,它适用于 PHP8.1+,这将是我的偏好。
不幸的是,它失败了 Phpstan 测试Method EnumClass::tryFromName() should return EnumClass|null but returns UnitEnum|null.,所以我求助于使用以下内容:
trait EnumFromName
{
/**
* To mirror backed enums tryFrom - returns null on failed match.
*/
public static function tryFromName(string $name): ?static
{
foreach (self::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}
return null;
}
/**
* To mirror backed enums from - throws ValueError on failed match.
*/
public static function fromName(string $name): static
{
$case = self::tryFromName($name);
if (! $case) {
throw new ValueError($name.' is not a valid case for enum '.self::class);
}
return $case;
}
}
Run Code Online (Sandbox Code Playgroud)