10

I´m trying to create an php 8.1 enum from a dynamic name. Seems not to be possible. So given an enum

enum Foo {
    case bar;
}

The following works of course: Foo::bar While this doesn´t:

$name = "bar";
Foo::${$name}

This results in: Access to undeclared static property App\Console\Commands\Foo::$bar

I tried various tricks here, to no avail. It seems not to be possible to get an enum instance from a dynamic name. My custom and quick workaround looks like this, a static factory:

/**
 * @throws \Exception
 */
public static function fromName(string $name) : self {

    foreach(Foo::cases() as $enum){
        if($enum->name === $name){
            return $enum;
        }
    }
    throw new \Exception("Not a valid enum name");
}

I could put this in a trait and inherit this in all my enums, yes, problem solved.

My question is: am I missing something here? Is it really not possible to instantiate an enum with native php methods? Or am I thinking in the wrong direction?

The pre php8.1 class-as-enum composer packages used to have those convenience methods, see https://github.com/bensampo/laravel-enum So why is this pretty common case not part of the specification (just curious)?

1
  • i think your answer lies here. There is a diff list of what you cannot do and what you can do. Moreover there are plenty examples both in comments and in the list of related enum articles. Btw, in your method, change foreach(Foo::cases() as $enum) to this foreach(static::cases() as $enum) so it will be more universal for your multiple enums. Commented Feb 7, 2022 at 12:32

5 Answers 5

17

The most simple way for that is using the constant() function:

<?php namespace App\Enums;


enum FooEnum: int
{
    case FOO = 123;
    case BAR = 456;
   
    public static function fromName(string $name){
        
        return constant("self::$name");
    }
}

Usage:


$name = "FOO";
dump(App\Enums\FooEnum::fromName($name));

/*
return 
App\Enums\FooEnum {
  +name: "FOO"
  +value: 123
}
*/
Sign up to request clarification or add additional context in comments.

2 Comments

this is php 8.1+ please use return value for fromName
@Toskan do you mean return type?
6

PHP 8.3+

Following syntax is supported since PHP 8.3:

<?php

$enumName = 'Something';
SomeEnum::{$enumName};
SomeEnum::{$enumName}->value;

This works for both constants and enum cases. It was basically done for constants as "dynamic class constant fetch": https://www.php.net/releases/8.3/en.php#dynamic_class_constant_fetch as since enums are basically implemented as a special case of class with special contants (cases) - it works for them too.

PHP 8.1 & 8.2

You can use constant() as you would use for a constant, but be aware of namespaces! by the way this is the same issue as with defined & const definition - even when inside the namespace, you have to specify it in the reference string!

Namespace example

namespace SomeNamespace;
enum MyEnum: int {
    case SomeName = 42;
}

$name ='SomeName';
echo constant("SomeNamespace\MyEnum::$name")->value;

Simple example (without namespace)

enum MyEnum: int {
    case SomeName = 42;
}

$name ='SomeName';
echo constant("\MyEnum::$name")->value;

Comments

4

Alternatively, you could make your enum backed and use the ::from method.

// note: type-hinting required
enum Status: int
{
    case OK = 200;
    case ERROR = 500;
}

$statusValue = 200;
$status = Status::from($statusValue);

(returns Status::OK)

If you're using Laravel casting, I believe it requires you to use a backed enum anyway. And in your model you just need to add that cast on your model

...
protected $casts = [
    'status' => \App\Emums\Status::class,
];

Comments

2

Could you maybe do something like this?


enum Status {
  case OK;
  case DENIED;
}

$name = "OK";
$reflection = new \ReflectionEnum(Status::class);
if ( $reflection->hasConstant( $name ) ) {
  var_dump($reflection->getConstant( $name ));
}

Output: enum(Status::OK)

3 Comments

Thank you! This is an alternative option to the method I came up with.
It's really unfortunate that there isn't a helper method for selecting an enum case by a string value.
@JacobThomson, maybe github.com/henzeb/enumhancer something for you?
1

One-liner:

$name = 'bar';
$enum = array_column(Foo::cases(), null, 'name')[$name] ?? null;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.