7

I have basic enum

enum Fruit
{
  case APPLE;
  case ORANGE;
  case BANANA;
}

and some function that uses typing with that enum:

function eatFruit (Fruit $fruit)
{
  // do stuff
}

and variable with unknown content

$fruit = $_POST['fruit']; // user choosed "MILK"
if (?????) { // how to check if it's fruit?
  eatFruit($fruit); // this should not be executed
}

I cannot find in documentation simple way to check if enum contains specific case.

It is possible with backed enums like that

enum Fruit
{
  case APPLE = 'APPLE';
  case ORANGE = 'ORANGE';
  case BANANA = 'BANANA';
}

Fruit::from('');
Fruit::tryFrom('');

This will work, but from does not exist on non-backed enums form my first example.

Fatal error: Uncaught Error: Call to undefined method Fruit::from()
norr
  • 1,725
  • 1
  • 20
  • 33

4 Answers4

7

You can use the static method cases() for this. This returns an array of all values in the enum. The values have a "name" property that is a string representation you can check against (backed enums also have a "value" property that contains the string value you defined in the enum).

So an example implementation could be something like:

enum Fruit {
    case APPLE;
    case ORANGE;
    case BANANA;
}

// String from user input
$fruit = $_POST['fruit'];

// Find matching fruit in all enum cases
$fruits = Fruit::cases();
$matchingFruitIndex = array_search($fruit, array_column($fruits, "name"));

// If found, eat it
if ($matchingFruitIndex !== false) {
    $matchingFruit = $fruits[$matchingFruitIndex];
    eatFruit($matchingFruit);
} else {
    echo $fruit . " is not a valid Fruit";
}

function eatFruit(Fruit $fruit): void {
    if ($fruit === Fruit::APPLE) {
        echo "An apple a day keeps the doctor away";
    } elseif ($fruit === Fruit::ORANGE) {
        echo "When life gives you oranges, make orange juice";
    } elseif ($fruit === Fruit::BANANA) {
        echo "Banana for scale";
    }
}

Working version with sample data: https://3v4l.org/ObD3s

If you want to do this more often with different enums, you could write a helper function for this:

function getEnumValue($value, $enumClass) {
    $cases = $enumClass::cases();
    $index = array_search($value, array_column($cases, "name"));
    if ($index !== false) {
        return $cases[$index];
    }
    
    return null;
}

$fruit = getEnumValue($_POST['fruit'], Fruit::class);
if ($fruit !== null) {
    eatFruit($fruit);
} else {
    echo $_POST['fruit'] . " is not a valid Fruit";
}

Example with the same sample data: https://3v4l.org/bL8Wa

rickdenhaan
  • 10,857
  • 28
  • 37
2
$fruitFromPost = current(array_filter(
    Fruit::cases(),
    fn(Fruit $fruitCase) => $fruitCase->name === $_POST['fruit']
)) ?: Fruit::APPLE;

We filter Fruit::cases with anonymous call on each case, where we check, if case name is same, as provided in POST. Then we get current value from filtered, and if it's false (not found in cases by name) we assign APPLE as default (or you can stay with false or maybe null, as you wish). Please note, that it's case sensitive.

yaroslavche
  • 383
  • 1
  • 9
0

If you need from or tryFrom, use https://packagist.org/packages/henzeb/enumhancer. It will give you that and so much more.

SomeOne_1
  • 808
  • 10
  • 10
-1

Today it works great!

I assume that this might e some sort of early version bug.

This is with PHP 8.2:

enum Fruit: string
{
    case APPLE = 'apple';
    case ORANGE = 'orange';
    case BANANA = 'banana';
}

$input = 'orange';
$fruit = Fruit::tryFrom($input);
var_dump($fruit); // enum Fruit::ORANGE : string("orange");

$input = 'strawberry';
$fruit = Fruit::tryFrom($input);
var_dump($fruit); // null

In case of from method with not valid backend value for enum is used (for example Fruit::from('strawberry'), then you'll get a ValueError:

Fatal error: Uncaught ValueError: "strawberry" is not a valid backing value for enum Fruit.

Rozkalns
  • 510
  • 2
  • 6
  • 26
  • I've provided my answer to address the previous concern, as previous answers seemed to deter me from delving deeper into the subject matter and presented over complicated examples. – Rozkalns Aug 07 '23 at 12:51