HOWTO · PHP
Enumerations in PHP
This tutorial will teach how to create and use enumerations in PHP. You'll learn how to emulate an enumeration with abstract classes. Also, you'll learn how to work with native enumerations in PHP.
On this page
This guide explains when to use a class-based enumeration emulation and when to use PHP’s native enum. PHP added native enums in PHP 8.1; older versions can use class constants, but those do not provide native enum case objects or their built-in checks. Choose emulation when deployment must remain below PHP 8.1; its validation is custom, while native enums make valid cases explicit in the type system. See the PHP enumeration manual.
Emulate Enumeration With Abstract Classes in PHP
Before PHP 8.1, a class can group named constants. Access a constant with the scope resolution operator ::. This is a simple naming convention: callers can still pass unrelated values, and constants do not have the identity or type guarantees of native enum cases.
<?php
abstract class CalendarMonth
{
public const JANUARY = 1;
public const FEBRUARY = 2;
public const MARCH = 3;
}
$month = CalendarMonth::JANUARY;
echo $month;
Emulate Enumeration With Abstract Classes With Validation and More Constant Values in PHP
A base class can use reflection to validate names and values. This example caches constants by the concrete subclass name, so each subclass gets its own set. It remains an emulation: the checks run only when callers use them, and the class does not create native enum cases. This typed-property example requires PHP 7.4 or later.
<?php
abstract class EnumEmulation
{
private static array $cache = [];
private static function constantsFor(string $class): array
{
if (!array_key_exists($class, self::$cache)) {
self::$cache[$class] = (new ReflectionClass($class))->getConstants();
}
return self::$cache[$class];
}
public static function hasName(string $name, bool $strict = false): bool
{
$constants = self::constantsFor(static::class);
if ($strict) {
return array_key_exists($name, $constants);
}
foreach (array_keys($constants) as $constantName) {
if (strcasecmp($constantName, $name) === 0) {
return true;
}
}
return false;
}
public static function hasValue(int $value): bool
{
return in_array($value, array_values(self::constantsFor(static::class)), true);
}
}
abstract class CalendarMonth extends EnumEmulation
{
public const JANUARY = 1;
public const FEBRUARY = 2;
public const MARCH = 3;
}
var_dump(CalendarMonth::hasName('march'));
var_dump(CalendarMonth::hasName('march', true));
var_dump(CalendarMonth::hasValue(2));
bool(true)
bool(false)
bool(true)
Enumeration With PHP enum
Native enum examples in this article require PHP 8.1 or later. A native enum declares a fixed set of cases. A case is an object: compare cases for identity with ===, and use instanceof to check their enum type. Native enum cases are not ordered values, so ordering comparisons are not a way to rank them.
<?php
enum ProgrammingLanguage
{
case PHP;
case JavaScript;
case Ruby;
}
$first = ProgrammingLanguage::PHP;
$same = ProgrammingLanguage::PHP;
$other = ProgrammingLanguage::Ruby;
var_dump($first === $same);
var_dump($first === $other);
var_dump($first instanceof ProgrammingLanguage);
Backed PHP Enumerations
A backed enum assigns each case one unique int or string value. Declare the backing type after the enum name, and give every case a distinct literal value. Read a case’s scalar through its value property. Backed enums implement BackedEnum.
Use from() when the input is expected to match a case; an unmatched value throws ValueError. Use tryFrom() when a missing match is an ordinary lookup result; it returns null. For untrusted input, validate or handle the from() error rather than allowing it to terminate a request.
<?php
enum AccountStatus: string
{
case Active = 'active';
case Paused = 'paused';
}
$status = AccountStatus::from('active');
$unknown = AccountStatus::tryFrom('archived');
var_dump($status->value);
var_dump($unknown);
$unmatchedValue = 'archived';
try {
AccountStatus::from($unmatchedValue);
} catch (ValueError $error) {
echo 'from(): ' . $error->getMessage() . PHP_EOL;
}
$result = AccountStatus::tryFrom($unmatchedValue);
echo 'tryFrom(): ';
var_dump($result);
string(6) "active"
NULL
from(): "archived" is not a valid backing value for enum AccountStatus
tryFrom(): NULL
Backed Enumerations With Methods in PHP
Enums can define methods and implement interfaces. A match expression must account for every case that can reach it; otherwise PHP raises UnhandledMatchError. This example handles all four cases and derives its travel cost from the case’s backed value.
<?php
interface TravelRequirements
{
public function calculateTravelCost(int $distance): int;
public function requiresFuel(): bool;
}
enum CarType: int implements TravelRequirements
{
case Bugatti = 300;
case Lamborghini = 500;
case Ferrari = 450;
case Audi = 350;
public function calculateTravelCost(int $distance): int
{
return $this->value * $distance;
}
public function requiresFuel(): bool
{
return match ($this) {
self::Bugatti, self::Lamborghini, self::Ferrari, self::Audi => true,
};
}
}
$car = CarType::Bugatti;
var_dump($car->requiresFuel());
var_dump($car->calculateTravelCost(250));
List The Cases of Backed Enumerations in PHP
Every enum type provides cases() through UnitEnum, including backed enums. It returns an array of case objects, not an array of scalar backing values. Read each case’s name and, for a backed enum, its value when those are needed.
<?php
enum Priority: int
{
case Low = 1;
case Normal = 2;
case High = 3;
}
foreach (Priority::cases() as $case) {
echo $case->name . ': ' . $case->value . PHP_EOL;
}