How to get all values of an enum in PHP?
Asked Answered
I

9

66

PHP 8.1 is almost getting released, including support for Enumerations. I was testing some of the enum functionality and couldn't find much documentation about it. Hence my question: how do I get all values of an enum?

Infancy answered 1/11, 2021 at 7:2 Comment(0)
R
157

For basic enums:

$suits = array_column(Suit::cases(), 'name');

For backed enums where you want the values:

$suits = array_column(Suit::cases(), 'value');

You could then do something like this:

trait EnumToArray
{

  public static function names(): array
  {
    return array_column(self::cases(), 'name');
  }

  public static function values(): array
  {
    return array_column(self::cases(), 'value');
  }

  public static function array(): array
  {
    return array_combine(self::values(), self::names());
  }

}

enum Suit: string
{

  use EnumToArray;

  case Hearts = 'H';
  case Diamonds = 'D';
  case Clubs = 'C';
  case Spades = 'S';

}

Suit::array() will return:

Array
(
    [H] => Hearts
    [D] => Diamonds
    [C] => Clubs
    [S] => Spades
)
Rhyne answered 30/3, 2022 at 15:25 Comment(4)
Thanks for this. I flipped array_combine(self::names(), self::values()). Having the names as array keys feels more natural to me.Hilaire
Thx, I added a containsValue() function return \in_array($value, self::values(), true);Oriole
@Oriole You can just use tryFrom for that: php.net/manual/en/backedenum.tryfrom.phpRhyne
Awesome! that was really helpful! The array() method can also be written with array_column and the 3rd param for index_key column, like this: array_column(self::cases(), 'value', 'name') and will result in an assoc array with names as keys.Weltpolitik
I
44

After some research I found the answer. You can use the static method: cases().

enum Status
{
    case PAID;
    case Cancelled;
}

Status::cases();

The cases method will return an array with an enum (UnitEnum interface) for each value.

Infancy answered 1/11, 2021 at 7:2 Comment(1)
you can also read about enum methods for PHP 8.1 at the linkMidyear
M
6

Need the values and not Enum instances?

I've written a Composer package for this, othyn/php-enum-enhancements, as the UnitEnum::cases() method wasn't what I was looking for, as that returns an array of MySuperCoolEnum instances instead of the underlying values as their raw type, which is what I wanted.

Its a trait that can be easily added to any enum that does the following:

  • Adds a new static UnitEnum::valueArray(): array method that returns all values within an Enum as an equally typed array of Enum values

  • Adds a new static UnitEnum::valueList(string $separator = ', '): string method that returns all values within an Enum as a comma separated list string

In which produces the following for normal Enum's:

<?php

namespace App\Enums;

use Othyn\PhpEnumEnhancements\Traits\EnumEnhancements;

enum TestEnum
{
    use EnumEnhancements;

    case Alpha;
    case Bravo;
    case Charlie;
    case Delta;
    case Echo;
}

var_dump(TestEnum::valueArray());

// Results in the following being printed:
// array(5) {
//   [0]=>
//   string(5) "Alpha"
//   [1]=>
//   string(5) "Bravo"
//   [2]=>
//   string(7) "Charlie"
//   [3]=>
//   string(5) "Delta"
//   [4]=>
//   string(4) "Echo"
// }

var_dump(TestEnum::valueList());

// Results in the following being printed:
// string(34) "Alpha, Bravo, Charlie, Delta, Echo"

var_dump(TestEnum::valueList(separator: ':'));

// Results in the following being printed:
// string(30) "Alpha:Bravo:Charlie:Delta:Echo"

... and the following for Backed Enum's, the following being a string example:

<?php

namespace App\Enums;

use Othyn\PhpEnumEnhancements\Traits\EnumEnhancements;

enum TestStringBackedEnum: string
{
    use EnumEnhancements;

    case Alpha   = 'alpha';
    case Bravo   = 'bravo';
    case Charlie = 'charlie';
    case Delta   = 'delta';
    case Echo    = 'echo';
}

var_dump(TestStringBackedEnum::valueArray());

// Results in the following being printed:
// array(5) {
//   [0]=>
//   string(5) "alpha"
//   [1]=>
//   string(5) "bravo"
//   [2]=>
//   string(7) "charlie"
//   [3]=>
//   string(5) "delta"
//   [4]=>
//   string(4) "echo"
// }

var_dump(TestStringBackedEnum::valueList());

// Results in the following being printed:
// string(34) "alpha, bravo, charlie, delta, echo"

var_dump(TestStringBackedEnum::valueList(separator: ':'));

// Results in the following being printed:
// string(30) "alpha:bravo:charlie:delta:echo"

... and yes it works on int's too!

There are more examples in the Usage part of the package's README.

Morvin answered 16/2, 2022 at 10:30 Comment(0)
D
5

In addition to UnitEnum::cases() you can use ReflectionEnum with this

$reflection = new ReflectionEnum(Status::class);

$reflection->getCases();

note that in both cases you will not be able to get the enum methods. but as long as the ReflectionEnum is extending the ReflectionClass so you can use the rest of ReflectionClass methods such as getMethods

Dunne answered 1/11, 2021 at 7:57 Comment(2)
This is a lot better than the accepted answer. I prefer Reflection for all things classes, interfaces, enums..Phobos
How is this better than just Status::cases()?Express
I
4

I have used the following in my project;

public static function toAssociativeArray(): array
{
    foreach(self::cases() as $case) {
        $array[$case->value] = $case->name;
    }
    return $array;
}

Which results in an associative array like this;

using strings as values

enum DiaryRole: string
{
    case DANGER  = 'red';
    case WARNING = 'yellow';
    case SAFE    = 'green';
}

$array = [
    'red'    => 'DANGER',
    'yellow' => 'WARNING',
    'green'  => 'SAFE'
];

or when using integers as values

enum DiaryRole: int
{
    case DANGER  = 1;
    case WARNING = 2;
    case SAFE    = 3;
}

$array = [
    1 => 'DANGER',
    2 => 'WARNING',
    3 => 'SAFE'
];

You can now use the array to get any information you need, and you can get only the columns or values using array_keys() or array_values()

I have used this code to easily foreach through them in a form select

Infliction answered 7/11, 2022 at 10:20 Comment(0)
N
2

I think the best options is using a trait for that.

For example: EnumsToArray.php

<?php

namespace App\Traits;

trait EnumsToArray {
    public static function toArray(): array {
        return array_map(
            fn(self $enum) => $enum->value, 
            self::cases()
        );
    }
}

And later, in you enum you should have:

use App\Traits\EnumsToArray;

Enum Currency: string {
    use EnumsToArray;
    
    case DOLLAR = "usd";
    case EURO = "eur";
}
Nonet answered 19/10, 2022 at 3:23 Comment(0)
S
2

Another way to get just the values of the enum is by following this approach:


<?php namespace JCKCon\Enums;

enum UsersPermissions: string
{
    case CREATE = "create";
    case UPDATE = "update";
    case DELETE = "delete";
    case VIEW = "view";
    case PUBLISH = "publish";

    public static function toArray()
    {
        $values = [];

        foreach (self::cases() as $props) {
            array_push($values, $props->value);
        }

        return $values;
    }
}


dd(UsersPermissions::toArray());

/**
array:5 [
  0 => "create"
  1 => "update"
  2 => "delete"
  3 => "view"
  4 => "publish"
]
**/
Stipendiary answered 12/7, 2023 at 22:22 Comment(3)
value is not a defined property in this case. You should use $props->name. Also, I would rewrite the the toArray method to this: return array_map(fn($case) => $case->name, self::cases());.Correa
Ignore this part value is not a defined property in this case. You should use $props->name. I didn't pay attention to it to see it's a backed enum. WhoopsCorrea
Okay great!. You can vote the answer to help others then.Stipendiary
L
1

I wrapped a slitly changed approach from @Michael up in a small package, cause I needed it in multiple projects:

https://github.com/laracraft-tech/laravel-useful-traits#usefulenums

Install via composer:

composer require laracraft-tech/laravel-useful-traits

This is how it is working:

use LaracraftTech\LaravelUsefulTraits\UsefulEnums;

enum PaymentType: int
{
    use UsefulEnums;

    case Pending = 1;
    case Failed = 2;
    case Success = 3;
}

PaymentType::names();   // return ['Pending', 'Failed', 'Success']
PaymentType::values();  // return [1, 2, 3]
PaymentType::array();   // return ['Pending' => 1, 'Failed' => 2, 'Success' => 3]
Linzy answered 3/2, 2023 at 15:35 Comment(0)
B
0

The simplest one-liner:

enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}
array_column(Suit::cases(), 'name', 'value');

It would return:

[
    "H" => "Hearts",
    "D" => "Diamonds",
    "C" => "Clubs",
    "S" => "Spades"
]

If you need to swap keys and values:

array_column(Suit::cases(), 'value', 'name');
[
    "Hearts" => "H",
    "Diamonds" => "D",
    "Clubs" => "C",
    "Spades" => "S"
]
Brassard answered 4/7 at 2:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.