Enums in PHP
Before PHP 8.1, developers simulated enumerations with class constants (class Status { const ACTIVE = 'active'; }), which offered no type safety — any string could be passed where a status was expected. PHP 8.1 introduced true enums via the enum keyword, producing a real type: an enum's cases are singleton instances of the enum type itself, so a parameter typed Status $status can only ever receive one of the enum's declared cases, and PHP enforces that at the type level, not just by convention. Enums can be 'pure' (cases have no underlying scalar value) or 'backed' (each case maps to a specific int or string value), and both kinds can implement interfaces, declare methods, and use traits, exactly like a class.
Cricket analogy: Simulating a status with class constants is like allowing any word to be scribbled on the scoreboard for 'out' or 'not out'; a true PHP 8.1 enum is like the umpire's official signal set, where only the recognized signals (declared cases) can ever be shown.
Pure enums and backed enums
A pure enum simply lists cases without any underlying value — useful when you only need distinct, comparable identities. A backed enum declares a scalar type (: string or : int) after the enum name, and every case must then specify a unique literal value of that type. Backed enums automatically gain a ->value property to read the underlying scalar, plus two static methods: from(), which converts a scalar to the matching case or throws a ValueError if none matches, and tryFrom(), which returns null instead of throwing. These are essential when persisting enum values to a database column or accepting them from an HTTP request.
Cricket analogy: A pure enum listing only case names is like naming fielding positions (Slip, Gully, MidOn) with no numeric value attached, just distinct identities; a backed enum is like assigning each position a jersey number, so from() converts number 4 straight to MidOn or throws if no fielder wears it.
<?php
declare(strict_types=1);
enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
enum OrderStatus: string
{
case Pending = 'pending';
case Shipped = 'shipped';
case Delivered = 'delivered';
case Cancelled = 'cancelled';
public function isFinal(): bool
{
return match ($this) {
self::Delivered, self::Cancelled => true,
self::Pending, self::Shipped => false,
};
}
}
$status = OrderStatus::from('shipped'); // OrderStatus::Shipped
var_dump($status->isFinal()); // false
$unknown = OrderStatus::tryFrom('lost'); // null, no exceptionInterfaces, constants, and static methods on enums
Enums can implement interfaces, which is the standard way to attach richer, polymorphic behaviour — for example, an enum could implement a HasLabel interface requiring a label(): string method, letting UI code call $status->label() uniformly across enum types. Enums can also declare their own constants and static factory methods, and — since enum cases are just class constants under the hood — SomeEnum::cases() (a built-in static method) returns an ordered array of every declared case, which is invaluable for populating select dropdowns or validating input against the full set of allowed values.
Cricket analogy: An enum implementing a HasLabel interface is like every fielding position implementing a common 'announce yourself' contract, so the stadium PA system calls the same method regardless of position and gets 'Silly Point' or 'Long On' back automatically.
<?php
declare(strict_types=1);
interface HasLabel
{
public function label(): string;
}
enum Priority: int implements HasLabel
{
case Low = 1;
case Medium = 2;
case High = 3;
public function label(): string
{
return match ($this) {
self::Low => 'Low priority',
self::Medium => 'Medium priority',
self::High => 'High priority',
};
}
}
foreach (Priority::cases() as $priority) {
echo "{$priority->value}: {$priority->label()}" . PHP_EOL;
}Because each enum case is a genuine singleton object, comparing cases with === is always safe and correct — OrderStatus::Shipped === OrderStatus::Shipped is always true, and there is exactly one instance of each case in memory for the entire request lifecycle.
Enums cannot have public, mutable instance properties — only cases, constants, and methods. If mutable per-case state seems necessary, that is usually a sign the design should be a class (possibly with a static registry) rather than an enum, since enums model fixed identity, not mutable data.
- Enum cases are true singleton instances of the enum type, giving compile-time-checked type safety that string/int constants never had.
- Pure enums have no underlying scalar value; backed enums (
: stringor: int) expose->valueand gainfrom()/tryFrom(). from()throws aValueErrorfor an unmatched scalar;tryFrom()returnsnullinstead.- Enums can implement interfaces, declare methods, use traits, and define constants, just like classes.
- The built-in static
cases()method returns an ordered array of every declared case. - Enum cases cannot hold mutable instance properties — they represent fixed, singleton identities, not mutable objects.
Practice what you learned
1. What is the key advantage of a PHP enum over the older pattern of class constants for representing a fixed set of values?
2. What happens when you call `SomeBackedEnum::from($value)` with a value that doesn't match any case?
3. Which of the following is true about a pure (non-backed) enum?
4. What does `SomeEnum::cases()` return?
5. Can a PHP enum declare a public, mutable instance property that differs per instance of the same case?
Was this page helpful?
You May Also Like
Type Declarations and Strict Types
PHP supports optional scalar and object type declarations on parameters, return values, and properties, with strict_types controlling how aggressively the engine coerces mismatched values.
Match Expressions
Introduces PHP 8's match expression, its strict comparison semantics, and why it is often a safer, more concise replacement for switch.
Classes and Objects
Explore PHP's object-oriented foundations: declaring classes, constructing objects, typed properties, visibility, and constructor promotion.
Attributes in PHP
Attributes are PHP's native, structured metadata syntax (introduced in PHP 8.0) that let you annotate classes, methods, and properties with machine-readable data read via reflection.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics