在PHP中通过存储在字符串中的名称获取枚举值

9

我想通过名字在PHP中获取枚举的值。 我的枚举如下:

enum Status : int
{
    case ACTIVE = 1;
    case REVIEWED = 2;
    // ...
}

Status::from(2) 可以用来获取 "REVIEWED",但是如何从存储在字符串中的名称解析出值呢?


建议阅读:枚举类型的后备 - berend
不是简单地回显 Status::REVIEWED 吗?- 抱歉我对 PHP 中的 Enums 不熟悉… - Simon K
9个回答

17

好的,似乎在PHP中没有任何内置的解决方案。我用一个自定义函数来解决这个问题:

enum Status : int
{
    case ACTIVE = 1;
    case REVIEWED = 2;
    // ...

    public static function fromName(string $name): string
    {
        foreach (self::cases() as $status) {
            if( $name === $status->name ){
                return $status->value;
            }
        }
        throw new \ValueError("$name is not a valid backing value for enum " . self::class );
    }

}

那么,我只需使用 Status::fromName('ACTIVE') 就能得到 1

如果要模仿枚举函数中的fromtryFrom,也可以添加:

public static function tryFromName(string $name): string|null
{
    try {
        return self::fromName($name);
    } catch (\ValueError $error) {
        return null;
    }
}

1
请注意,from 返回 self,而此函数返回 string - shamaseen
我很困惑为什么这会返回一个字符串。它是将一个字符串转化为另一个字符串吗?它不应该以某种方式返回自身吗? - undefined

8

您可以使用反射来处理后端情况:

$reflection = new ReflectionEnumBackedCase(Status::class, 'REVIEWED');
$reflection->getBackingValue(); // 2
$reflection->getValue() // Status::REVIEWED if you need case object

或枚举反射:

$reflection = new ReflectionEnum(Status::class);
$reflection->getCase('REVIEWED')->getValue()->value // 2

请参阅ReflectionEnumUnitCase。


7
constant() 函数可以使用字符串变量返回常量的值。
这同样适用于枚举类常量,正如 PHP 手册中 基本枚举部分 中所述。
$name = 'REVIEWED';
$status = constant("Status::{$name}");

这应该是正确的答案! - undefined

2

我也使用自定义方法,但是我返回一个枚举类型。

from 方法返回一个枚举类型,而不是一个值。我认为 fromName 方法也应该返回一个枚举类型。这样你就可以访问枚举的所有方法了。你不需要再使用另一个方法 - from

public static function fromName(string $name): self
{
    foreach (self::cases() as $status) {
        if( $name === $status->name ){
            return $status;
        }
    }
    throw new \ValueError("$name is not a valid backing value for enum " . self::class );
}

public static function tryFromName(string $name): self|null
{
    try {
        return self::fromName($name);
    } catch (\ValueError $error) {
        return null;
    }
}

2

如果有人在意,我已经围绕它创建了一个库。

https://github.com/henzeb/enumhancer

只需将特征添加到您的枚举中

enum Status : int
{
    use Henzeb\Enumhancer\Enhancers;
    
    case ACTIVE = 1;
    case REVIEWED = 2;
    // ...
}

Status::get('ACTIVE');
Status::tryGet('ACTIVE');

那么你就不必使用任何值了。在这种情况下,你也可以简单地使用 from。

enum Status
{
    use Henzeb\Enumhancer\Enhancers;
    
    case ACTIVE;
    case REVIEWED;
    // ...
}

Status::from('ACTIVE')->key(); // returns 0
Status::tryFrom('Reviewed')->key(); // returns 1

它能做的远不止这些,但可以避免复制和粘贴代码片段。


1

获取名称的值:

enum Status : int
{
   case ACTIVE = 1;
   case REVIEWED = 2;
   // ...
}

print(Status::REVIEWED->value);

枚举文档


1
我已经将名称存储在一个字符串中,我编辑了我的问题以使其更具体。感谢您的回答! - Diego Garcia

1
你还可以使用constant()函数来获取枚举,然后从中获取值。个人而言,我会使用trait,这样你就不必为每个你想要使用此功能的枚举创建函数。
trait EnumFromName
{
    public static function valueFromName(string $name): self
    {
        return constant("self::$name");
    }
}

枚举类:
enum Status : int
{
    use EnumFromName;

    case ACTIVE = 1;
    case REVIEWED = 2;
    // ...
}

呼叫:

Status::valueFromName('REVIEWED')->value;

1
你需要使用tryFromfrom

枚举的示例:

enum Fruits: string
{
    case APPLE = 'Apple';
    case PEAR = 'Pear';
    case ORANGE = 'Orange';

    public function getDescription(): string
    {
        return match ($this) {
            Fruits::APPLE => 'X',
            Fruits::PEAR => 'Y',
            Fruits::ORANGE => 'Z',
        };
    }

}

tryFrom: 从字符串获取枚举实例或null

将标量映射到枚举实例或null
$stringValue = 'Pear';

$fruit = Fruits::tryFrom($stringValue);

if ($fruit !== null) {
   echo $fruit->getDescription(); // "Z"
   echo $fruit->value; // "Pear"
}

文档: https://www.php.net/manual/zh/backedenum.tryfrom.php

from: 通过字符串获取枚举实例或抛出ValueError异常

将标量映射为枚举实例或抛出ValueError异常
$stringValue = 'Pear';

try { 
   $fruit = Fruits::from($stringValue);

   echo $fruit->getDescription(); // "Z"
   echo $fruit->value; // "Pear"
} catch (\ValueError $exception) { 
   echo $exception->getMessage(); // Fatal error: Uncaught ValueError: "X" is not a valid backing value for enum "Fruit"
}

文档: https://www.php.net/manual/zh/backedenum.from.php


0
这就是我所做的 - https://3v4l.org/8R2fP#v8.2.10
<?php

enum Gender
{
    case UNKNOWN;
    case MALE;
    case FEMALE;
}

/**
 * @template T as BackedEnum|UnitEnum
 * @param class-string<T> $enumClass
 * @param string $name
 * @return T|null
 */
function tryFromName(string $enumClass, string $name)
{
    $constName = $enumClass . '::' . $name;

    return is_subclass_of($enumClass, UnitEnum::class) && defined($constName)
        ? constant($constName)
        : null;
}

// enum(Gender::UNKNOWN)
var_dump(tryFromName(Gender::class, 'UNKNOWN'));

// enum(Gender::MALE)
var_dump(tryFromName(Gender::class, 'MALE'));

// enum(Gender::FEMALE)
var_dump(tryFromName(Gender::class, 'FEMALE'));

// NULL
var_dump(tryFromName(Gender::class, 'null'));


嗨,请不要只发布代码,还要解释为什么你认为这是最佳解决方案。人们应该从你的答案中学习,如果他们只是复制粘贴代码而不知道为什么要使用它,那么学习就无法发生。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接