9

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()
Dharman
34k27 gold badges106 silver badges158 bronze badges
asked Jan 9, 2022 at 20:25
0

4 Answers 4

10

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

answered Jan 9, 2022 at 21:08
Sign up to request clarification or add additional context in comments.

Comments

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.

answered Jul 7, 2022 at 18:03

Comments

2

You could also write a method fromName in your Fruit Enum like this:

enum Fruit
{
 case APPLE;
 case ORANGE;
 case BANANA;
 public static function fromName($name)
 {
 return defined("self::$name") ? constant("self::$name") : false;
 } 
}

Then you can simply check like this:

$fruit = Fruit::fromName($_POST['fruit']);
if ($fruit) {
 eatFruit($fruit);
 ...
}
answered Aug 9, 2024 at 16:26

4 Comments

this is backed enum
Thank you @norr. I've corrected my answer.
Hey this led me in the right direction for our Typescript PHP pattern ;)
Also, put the method into a trait that all your enums implement.
1

just use :

echo defined("\App\Enums\OrderStatus::CREATED") ? 'Case exists' : 'Case does not exist';

answered Dec 26, 2023 at 16:03

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.