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()
4 Answers 4
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
Comments
$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.
Comments
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);
...
}
4 Comments
just use :
echo defined("\App\Enums\OrderStatus::CREATED") ? 'Case exists' : 'Case does not exist';