An enumeration (PHP 8.1) defines a type with a fixed set of values. Internally an enum is a class, and each case is a singleton object of that class. Enums share a namespace with classes, interfaces and traits, and autoload the same way (manual).
Declaration
enum Name [: int | : string] [implements Interface {, Interface}]
{
{case Name [= value]; | constant | method | use Trait;}
}
Pure enums
enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
function pick(Suit $s): void { /* ... */ }
pick(Suit::Clubs); // OK
pick('Clubs'); // TypeError
echo Suit::Clubs->name; // Clubs
- Cases are written as
Name::Case. They are class constants and case names are case-sensitive. - Each case has a read-only
nameproperty holding the case name. - A case is a singleton, so
Suit::Clubs === Suit::Clubsis true.Suit::Clubs instanceof Suitis true. - Comparing enum values with
<or>is alwaysfalse. - An enum may have no cases at all. It is valid but not useful.
Backed enums
A backed enum gives each case a scalar value of one type, for storing in a database or sending over a network.
enum Status: string
{
case Active = 'active';
case Hidden = 'hidden';
}
Status::Active->value; // 'active'
Status::from('hidden'); // Status::Hidden
Status::from('x'); // ValueError
Status::tryFrom('x'); // null
Status::tryFrom('x') ?? Status::Active;
- The backing type follows the name with a colon. Only
intandstringare allowed, and a union is not. - Every case of a backed enum must have a value, and no two cases may share one. Pure and backed cases cannot be mixed. There is no auto-numbering.
- The value must be a constant expression. Before PHP 8.2 it had to be a literal or literal expression.
valueis read-only, and a reference to it cannot be taken.
from and tryFrom
A backed enum implements BackedEnum, which gives two static methods.
Neither may be written by hand.
| Method | If no case matches |
|---|---|
from(int|string $value): self | Throws ValueError |
tryFrom(int|string $value): ?self | Returns null |
In coercive mode an argument is converted to the backing type. Under
strict_types a mismatched argument is a TypeError.
Methods and members
interface Colourful
{
public function colour(): string;
}
enum Suit implements Colourful
{
use Rectangle;
case Hearts;
case Spades;
const Wild = self::Spades;
public function colour(): string
{
return match ($this) {
self::Hearts => 'Red',
self::Spades => 'Black',
};
}
public static function fromChar(string $c): self
{
return match ($c) {
'H' => self::Hearts,
'S' => self::Spades,
};
}
}
| Member | Allowed |
|---|---|
| Methods, with any visibility | Yes. Inside one, $this is the case |
| Static methods, with any visibility | Yes |
| Constants, with any visibility | Yes. A constant may alias a case |
| Interfaces | Any number |
| Traits | Yes, but a trait with properties is a fatal error |
| Attributes on the enum and its cases | Yes. TARGET_CLASS and TARGET_CLASS_CONSTANT apply |
__call, __callStatic, __invoke | Yes |
__CLASS__, __FUNCTION__ | Yes |
Every enum also has a static method cases(), from the
UnitEnum interface. It returns all the cases in declaration order, and
is empty for an enum with no cases.
Differences from classes
Enum cases hold no state. The following are not allowed:
- Constructors and destructors.
- Inheritance. An enum cannot extend or be extended.
- Static or object properties, other than the implicit
nameandvalue. - Cloning a case.
- Magic methods other than
__call,__callStaticand__invoke. Before PHP 8.6 that excludes__debugInfo. - Creating a case with
newor through Reflection.
An enum must be declared before it is used, or be autoloaded. A case is an object, so
it cannot be an array key, though it can be a WeakMap or
SplObjectStorage key.
Enums in constant expressions
A case can be used as a value wherever a constant expression is allowed: property, static variable and parameter defaults, and global and class constants.
class Connection
{
public function __construct(public Status $status = Status::Active) {}
}
Reading a property of a case in a constant expression was added in PHP 8.2:
const VALUE = Status::Active->value;. Using [] on a case is
not allowed in a constant expression, because it would run ArrayAccess
code.
Serialisation
serialize()uses its own format,E:11:"Suit:Hearts";, andunserialize()returns the same singleton object.- A backed enum encodes to JSON as its value. A pure enum cannot be encoded, and
json_encode()fails, unless it implementsJsonSerializable. var_export()writes the case by name, as\Suit::Hearts.