philsak
philsak

Reputation: 73

Get Case from enum by string

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?

Upvotes: 7

Views: 13712

Answers (4)

Tofandel
Tofandel

Reputation: 3565

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

Upvotes: 3

SomeOne_1
SomeOne_1

Reputation: 1002

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.

Upvotes: 0

oikodomo
oikodomo

Reputation: 74

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

Upvotes: 5

joeb
joeb

Reputation: 877

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

Upvotes: 10

Related Questions