enum (Enumerations)
| Since: | PHP 8.1(2021) |
|---|
To handle a fixed set of values in a type-safe way, the『enum』(enumeration type) added in『PHP』8.1 is useful. Instead of passing "states" or "categories" around as constants or strings, defining them as a dedicated type makes the intent of the code clear and prevents invalid values from being assigned at compile time.
Syntax
// Pure enum (enumeration without a backing value)
enum EnumName {
case CaseName;
}
// Backed enum (enumeration with int or string values)
enum EnumName: int {
case CaseName = value;
}
enum EnumName: string {
case CaseName = 'value';
}
// Accessing an enum case
EnumName::CaseName
// Getting a case from a value in a Backed enum
EnumName::from(value) // throws ValueError if no match
EnumName::tryFrom(value) // returns null if no match
Differences Between Pure Enum and Backed Enum
| Type | Syntax | Description |
|---|---|---|
| Pure enum | enum Name { case ... } | Does not hold a scalar value such as an integer or string. The case itself is treated as an object. |
| Backed enum (int) | enum Name: int { case ... = value } | Assigns an integer value to each case. Convenient for storage in databases. |
| Backed enum (string) | enum Name: string { case ... = 'value' } | Assigns a string value to each case. Convenient for interacting with JSON or external APIs. |
Enum Properties and Methods
| Name | Available in | Description |
|---|---|---|
| $case->name | Pure enum / Backed enum | Returns the case name as a string. Example:『Suit::Hearts->name』returns『"Hearts"』. |
| $case->value | Backed enum only | Returns the scalar value assigned to the case. Not available in Pure enums. |
| ::from($value) | Backed enum only | Retrieves a case from a scalar value. Throws a『ValueError』if no matching case exists. |
| ::tryFrom($value) | Backed enum only | Retrieves a case from a scalar value. Returns『null』if no matching case exists. |
| ::cases() | Pure enum / Backed enum | Returns an array of all cases. |
Sample Code
Pure Enum Basics
enum_pure.php
<?php
// Define KOF character attributes using a Pure enum
// Pure enums hold no scalar value; the case itself is an object
enum Element {
case Fire; // fire
case Ice; // ice
case Thunder; // lightning
case Wind; // wind
}
// Cases are accessed like class constants
$kyo = Element::Fire;
$iori = Element::Fire;
$kula = Element::Ice;
$benimaru = Element::Thunder;
// Identical cases match with strict comparison (===)
var_dump($kyo === $iori); // true — same case
var_dump($kyo === $kula); // false — different case
// ->name retrieves the case name as a string
echo $kyo->name . "\n"; // Fire
echo $kula->name . "\n"; // Ice
// Combined with a match expression for per-case logic
function getElementDescription(Element $element): string
{
return match($element) {
Element::Fire => "Kusanagi Kyo uses fire.",
Element::Ice => "Kula uses ice.",
Element::Thunder => "Benimaru uses lightning.",
Element::Wind => "This fighter uses wind.",
};
}
echo "草薙京: " . getElementDescription($kyo) . "\n";
echo "クーラ: " . getElementDescription($kula) . "\n";
echo "八神庵: " . getElementDescription($iori) . "\n";
echo "二階堂紅丸: " . getElementDescription($benimaru) . "\n";
Running the code produces the following output:
php enum_pure.php bool(true) bool(false) Fire Ice 草薙京: Kusanagi Kyo uses fire. クーラ: Kula uses ice. 八神庵: Kusanagi Kyo uses fire. 二階堂紅丸: Benimaru uses lightning.
Backed Enum (int)
enum_backed_int.php
<?php
// Define KOF character ranks using an int-backed enum
// Assigning integer values to each case makes them usable for database storage
enum Rank: int {
case D = 1;
case C = 2;
case B = 3;
case A = 4;
case S = 5;
}
// ->value retrieves the integer value assigned to the case
echo Rank::A->value . "\n"; // 4
echo Rank::S->name . "\n"; // S
// ::from() retrieves a case from an integer value
// Throws ValueError if no matching case exists
$rank = Rank::from(3);
echo $rank->name . "\n"; // B
// ::tryFrom() returns null when no case is found (no exception)
$unknownRank = Rank::tryFrom(99);
var_dump($unknownRank); // NULL
// Example combining characters with ranks
$fighters = [
["name" => "草薙京", "rank" => Rank::S],
["name" => "八神庵", "rank" => Rank::S],
["name" => "テリー・ボガード", "rank" => Rank::A],
["name" => "ラルフ・ジョーンズ", "rank" => Rank::B],
];
foreach ($fighters as $fighter) {
// ->value for integer, ->name for case name
echo $fighter['name'] . ": Rank " . $fighter['rank']->name
. " (score: " . $fighter['rank']->value . ")\n";
}
Running the code produces the following output:
php enum_backed_int.php 4 S B NULL 草薙京: Rank S (score: 5) 八神庵: Rank S (score: 5) テリー・ボガード: Rank A (score: 4) ラルフ・ジョーンズ: Rank B (score: 3)
Backed Enum (string)
enum_backed_string.php
<?php
// Define KOF teams using a string-backed enum
// Useful when string values are needed for external APIs or JSON
enum Team: string {
case HeroesTeam = 'heroes';
case RivalsTeam = 'rivals';
case FatalFury = 'fatal_fury';
case IkariTeam = 'ikari';
}
// ->value retrieves the string value
echo Team::HeroesTeam->value . "\n"; // heroes
echo Team::FatalFury->value . "\n"; // fatal_fury
// ::from() restores a case from a string value (e.g., value read from JSON)
$teamFromJson = Team::from('ikari');
echo $teamFromJson->name . "\n"; // IkariTeam
// ::cases() returns an array of all cases
echo "--- All Teams ---\n";
foreach (Team::cases() as $team) {
echo $team->name . ": " . $team->value . "\n";
}
// Example of character-team mappings
$members = [
["name" => "草薙京", "team" => Team::HeroesTeam],
["name" => "八神庵", "team" => Team::RivalsTeam],
["name" => "テリー・ボガード", "team" => Team::FatalFury],
["name" => "ラルフ・ジョーンズ", "team" => Team::IkariTeam],
];
echo "\n--- Team Assignments ---\n";
foreach ($members as $member) {
// Use ->value when sending JSON or saving to DB
echo $member['name'] . ": " . $member['team']->value . "\n";
}
Running the code produces the following output:
php enum_backed_string.php heroes fatal_fury IkariTeam --- All Teams --- HeroesTeam: heroes RivalsTeam: rivals FatalFury: fatal_fury IkariTeam: ikari --- Team Assignments --- 草薙京: heroes 八神庵: rivals テリー・ボガード: fatal_fury ラルフ・ジョーンズ: ikari
Defining Methods and Implementing Interfaces on Enums
enum_method_interface.php
<?php
// Methods can be defined on enums
// Enums can also implement interfaces
// Define an interface for retrieving a label
interface HasLabel {
public function label(): string;
}
// Define KOF fighting styles as a string-backed enum implementing the interface
enum FightingStyle: string implements HasLabel {
case Karate = 'karate';
case Muay_Thai = 'muay_thai';
case Wrestling = 'wrestling';
case Martial_Art = 'martial_art';
// Implement the interface method
public function label(): string
{
return match($this) {
FightingStyle::Karate => "Karate",
FightingStyle::Muay_Thai => "Muay Thai",
FightingStyle::Wrestling => "Wrestling",
FightingStyle::Martial_Art => "Martial Arts",
};
}
// Additional custom method on the enum
public function description(): string
{
return match($this) {
FightingStyle::Karate => "Kusanagi-style karate. Features flame-imbued attacks.",
FightingStyle::Muay_Thai => "Muay Thai practitioner. Powerful kick techniques.",
FightingStyle::Wrestling => "Wrestling-based throws are a strong point.",
FightingStyle::Martial_Art => "Chinese martial arts. Agile and varied techniques.",
};
}
}
// Call the method via the interface
function printStyle(HasLabel $style): void
{
echo $style->label() . "\n";
}
$style = FightingStyle::Karate;
printStyle($style); // Karate
// Call each method
$fighters = [
["name" => "草薙京", "style" => FightingStyle::Karate],
["name" => "キム・カッファン", "style" => FightingStyle::Muay_Thai],
["name" => "クラーク・スティル", "style" => FightingStyle::Wrestling],
["name" => "レオナ・ハイデルン", "style" => FightingStyle::Martial_Art],
];
foreach ($fighters as $fighter) {
echo $fighter['name'] . " (" . $fighter['style']->label() . "): "
. $fighter['style']->description() . "\n";
}
// Can also be restored from a value and used
$fromValue = FightingStyle::from('muay_thai');
echo "\nRestored style: " . $fromValue->label() . "\n";
Running the code produces the following output:
php enum_method_interface.php Karate 草薙京 (Karate): Kusanagi-style karate. Features flame-imbued attacks. キム・カッファン (Muay Thai): Muay Thai practitioner. Powerful kick techniques. クラーク・スティル (Wrestling): Wrestling-based throws are a strong point. レオナ・ハイデルン (Martial Arts): Chinese martial arts. Agile and varied techniques. Restored style: Muay Thai
Common Mistakes
Trying to access ->value on a Pure enum
Pure enums do not hold a scalar value, so accessing ->value causes a fatal error. ->value is exclusive to Backed enums.
ng_enum_value.php
<?php
enum Element {
case Fire;
case Ice;
}
$kyo = Element::Fire;
echo $kyo->value . "\n"; // Pure enum has no value, causes an error
Running the code produces the following output:
php ng_enum_value.php Fatal error: Uncaught Error: Cannot access the value of a non-backed enum in ng_enum_value.php:8
Use a Backed enum when scalar values are needed. When no value is required, ->name retrieves the case name as a string.
ok_enum_value.php
<?php
// Pure enum: use ->name to get the case name
enum Element {
case Fire;
case Ice;
}
$kyo = Element::Fire;
echo $kyo->name . "\n"; // "Fire"
// Backed enum: use ->value to get the scalar value
enum ElementBacked: string {
case Fire = 'fire';
case Ice = 'ice';
}
$iori = ElementBacked::Fire;
echo $iori->value . "\n"; // "fire"
Running the code produces the following output:
php ok_enum_value.php Fire fire
Passing a non-existent value to ::from()
::from() throws a ValueError when no matching case is found. If an unknown value enters from external input without exception handling, the script will stop.
ng_enum_from.php
<?php
enum Rank: int {
case D = 1;
case C = 2;
case B = 3;
case A = 4;
case S = 5;
}
// Passing the non-existent value 99 to from() raises a ValueError
$rank = Rank::from(99);
echo $rank->name . "\n";
Running the code produces the following output:
php ng_enum_from.php Fatal error: Uncaught ValueError: 99 is not a valid backing value for enum "Rank" in ng_enum_from.php:13
When the value may not be valid—such as from external input—use ::tryFrom(), which returns null, and add a null check.
ok_enum_from.php
<?php
enum Rank: int {
case D = 1;
case C = 2;
case B = 3;
case A = 4;
case S = 5;
}
$fighters = [
["name" => "草薙京", "rankValue" => 5],
["name" => "テリー・ボガード", "rankValue" => 4],
["name" => "Unknown fighter", "rankValue" => 99],
];
foreach ($fighters as $fighter) {
$rank = Rank::tryFrom($fighter['rankValue']);
if ($rank !== null) {
echo $fighter['name'] . ": Rank " . $rank->name . "\n";
} else {
echo $fighter['name'] . ": Unknown rank\n";
}
}
Running the code produces the following output:
php ok_enum_from.php 草薙京: Rank S テリー・ボガード: Rank A Unknown fighter: Unknown rank
Summary
『enum』is a syntax added in PHP 8.1 that defines a fixed set of values as a type. Representing "states" and "categories" that were previously handled as constants or strings as a dedicated type means that,when combined with type hints, invalid values can be rejected at compile time and IDE autocompletion becomes available.
There are two kinds:『Pure enum』, which holds no scalar value, and『Backed enum』, which holds an int or string value. With Backed enums,『::from()』allows restoring a case from a value, making them well-suited for interacting with databases and external APIs. When an invalid value may be passed, use『::tryFrom()』, which returns『null』rather than throwing an exception as『::from()』does.
Methods can be defined on an『enum』, and interfaces can be implemented. This allows designing cases to hold their own logic, rather than writing per-case handling in a『match』expression. For『match』expressions, see『match expression』. For interfaces, see『extends / implements』.
If you find any errors or copyright issues, please contact us.