A PHP enum (PHP 8.1+) defines a type with a fixed set of possible values, its cases: enum Status { case Active; case Banned; }. You use a case as Status::Active, and a parameter typed Status accepts nothing else. A backed enum, enum Status: string, also gives each case a value you can store and convert back with Status::from().
Before enums, the same thing was a list of string constants, and nothing stopped a typo like 'actve' from reaching the database. With Status as the parameter type, only the three cases can be passed in.
Pure enums and backed enums
A pure enum has cases that are only names. A backed enum declares a type after the name, int or string, and every case must then have a unique value of that type. Every case has ->name; only backed cases have ->value.
Pick a backed enum whenever the value leaves the program: a database column, a URL, a form field, JSON. Pick a pure enum for values that only exist inside the code, such as the state of a parser.
Convert a value with from() and tryFrom()
Backed enums get two static methods for turning a stored value back into a case. from() throws a ValueError for an unknown value; tryFrom() returns null, which pairs well with ?? for a default:
Use tryFrom() on anything a user sent you, and from() on values your own code wrote, where an unknown value means a bug you want to hear about. The argument follows the normal parameter type rules: on an int enum, Priority::from('5') returns Priority::Normal in the default mode because '5' is converted to 5 first, Priority::from('5x') is a TypeError, and under declare(strict_types=1) any string is a TypeError. That includes tryFrom(): Priority::tryFrom('abc') throws instead of returning null, so check form input for an int enum with filter_var($raw, FILTER_VALIDATE_INT) first.
List all cases with cases()
Enum::cases() returns an array of every case, in the order they are declared. That is how you build a dropdown, validate a list, or get all values with array_column:
Run it, pick a plan and press Choose: the same script runs again with $_POST['plan'] filled in, and tryFrom() turns the submitted string back into a Plan case. A forged value such as plan=gold gives null, and no option is selected.
Enum methods, constants and interfaces
Enums can have methods, static methods and constants, and can implement interfaces. Inside a method, $this is the current case, which makes match ($this) the natural way to attach data to each case. What an enum cannot have is properties: per-case data comes from methods.
Enums in match
match compares with ===, and an enum case is identical only to itself, so match and enums fit together. If you forget a case and that case reaches the match, PHP throws an UnhandledMatchError instead of silently returning nothing:
See match for how match differs from switch.
Enums in JSON and as strings
json_encode() writes a backed case as its value. A pure enum cannot be encoded, and echo of any case fails, because an enum is an object, not a string. Print ->value or ->name instead:
echo Role::Admin; throws an Error ("Object of class Role could not be converted to string"), and enums cannot implement __toString(). On the way back in, JSON gives a plain string, so convert it with from() or tryFrom() as shown. More on encoding in json_encode.
Common enum mistakes
Three errors come up again and again. A case is never equal to its value, a case cannot be an array key, and new does not work on an enum:
If you need a map keyed by the cases themselves, use SplObjectStorage or WeakMap, which accept objects as keys.
Frequently Asked Questions
How do I get the value of an enum in PHP?
On a backed enum, read ->value: Status::Active->value is 'active'. Every case also has ->name, the case name as a string ('Active'). A pure enum (no : string or : int) has only ->name.
What is the difference between from() and tryFrom() in PHP enums?
Both turn a value into a case of a backed enum. Status::from('active') returns the case or throws a ValueError when no case has that value; Status::tryFrom('nope') returns null instead. Use tryFrom() for user input and from() when a bad value is a bug.
How do I get all values of an enum in PHP?
Status::cases() returns every case in declaration order. For the values of a backed enum use array_column(Status::cases(), 'value'), and for the names array_column(Status::cases(), 'name').
What is the difference between a pure enum and a backed enum?
A pure enum (enum Suit { case Hearts; }) has cases that are only names. A backed enum (enum Suit: string { case Hearts = 'H'; }) gives each case a unique int or string value, which you need to store it in a database, put it in a form or JSON, and convert it back with from() or tryFrom().
Can a PHP enum have methods?
Yes. Enums can have methods, static methods and constants, and can implement interfaces. Inside a method, $this is the current case, so return match ($this) { self::Active => 'green', self::Banned => 'red' }; is a common pattern. Enums cannot have properties.