4

I search for a simple solution to get the case of an enum by a string. There are BackedEnums. For example:

<?php
enum Status: string
{
    case OK = "OK";
    case FAILED = "FAILED";
    ...
}
$status = Status::tryFrom("OK"); // or from("OK");

But I don't want to write the same word twice for getting that result. Is there a native way to get the case without having BackedEnums? I want something like:

<?php
enum Status
{
    case OK;
    case FAILED;
    ...
}
$status = Status::get("OK"); //returns Status::OK;

Or do I need to write my own funcionality for that? For example:

enum Status
{
    case OK;
    case FAILED;    
    public static function get(string $name): null|Status
    {
        $name = strtoupper(trim($name));
        if(empty($name))
            return null;

        foreach(Status::cases() as $status)
        {
            if($status->name == $name)
                return $status;
        }
        return null;
    }
}

Status::get("OK"); // -> Status::OK

Is there a better way to achieve the same?

philsak
  • 43
  • 1
  • 3

4 Answers4

7

There is an internal name getter like this.

Status::OK->name;

This will return Ok

Status::OK->value;

This will return the value

To get the case from the value. Use this

$case = Status::tryFrom('Ok')

https://www.php.net/manual/en/backedenum.tryfrom.php

joeb
  • 777
  • 8
  • 28
  • A slightly more verbose answer - https://stackoverflow.com/a/66208862/296555 – waterloomatt Dec 17 '21 at 14:30
  • my situation is different. I will try to make clear what I mean. I don't know the case in this example Status::OK What i have is a string with the name of the case: "OK" And now I try to find the simplest generic way to get the case for the string "OK" – philsak Dec 17 '21 at 15:40
  • Look at the last line of code i wrote: `Status::get("OK")`. lets suggest that i have a variabel `$test = "OK"` and now I want the matching case from status to that. Is it clear what I mean? – philsak Dec 17 '21 at 15:45
  • @philsak, I edited my original response. – joeb Dec 18 '21 at 02:08
  • `tryFrom` is not available in a non backed enum and op actually wants to simplify writing his `enums` without values (So non backed) – Tofandel Jun 22 '23 at 15:19
4

ReflectionEnum is the answer. In the rfc for enums in php8.1 is a chapter Reflection

There you have the method getCase(string $name) and in combination with getValue() you get the enum. With that function you can get the case via a string value.

Your Example would look like this:

$status = (new ReflectionEnum("Status"))->getCase("OK")->getValue();

Best used with an ExceptionHandler since the transmitted string, if not found, could end up in a ReflectionException

oikodomo
  • 64
  • 2
2

Only a BackedEnum has the from and tryFrom methods available sadly, but they can easily be polyfilled, here is how you could write your own from and tryFrom in a trait for reusability

<?php

trait LazyEnum
{
    public static function tryFrom($caseName): ?self
    {
        $rc = new ReflectionEnum(self::class);
        return $rc->hasCase($caseName) ? $rc->getConstant($caseName) : null;
    }

    /**
     * @throws Exception
     */
    public static function from($caseName): self
    {
        return self::tryFrom($caseName) ?? throw new Exception('Enum '. $caseName . ' not found in ' . self::class);
    }

}


enum Test
{
    use LazyEnum;
    
    case FOO;
    case BAR;
}
var_dump(Test::tryFrom('FOO')); //enum(Test::FOO)
var_dump(Test::tryFrom('BAZ')); //NULL
Tofandel
  • 3,006
  • 1
  • 29
  • 48
0

Instead of writing your own, you could use https://packagist.org/packages/henzeb/enumhancer

This will do for you what you need, and so much more.

SomeOne_1
  • 808
  • 10
  • 10
  • IMHO, it does really too much in the context of this question for a small feature, remember folks, each dependency you add means more maintenance down the road – Tofandel Jun 22 '23 at 15:17