<?php
abstract class Enum {
private $name;
private static $enums;
private function __construct($name) {
$this->name = $name;
}
/**
* Returns an assoc. array of ['ENUM_NAME' => $ENUM_VALUE] for all enum values.
* @return array
*/
public static function getAll(): array {
$class = static::class;
if (!isset(self::$enums[$class])) static::init();
return self::$enums[$class];
}
/**
* Return an enum value (object) from a string name.
* @return $this
*/
public static function fromString($name) {
return static::__callStatic($name, []);
}
public function __toString() {
return $this->name;
}
public static function __callStatic($name, $args) {
$class = static::class;
if (!isset(self::$enums[$class])) static::init();
if (!isset(self::$enums[$class][$name])) {
throw new \TypeError('Undefined enum ' . $class . '::' . $name . '()');
}
return self::$enums[$class][$name];
}
private static function init() {
$class = static::class;
if ($class === __CLASS__) {
throw new \Exception('Do not invoke methods directly on class Enum.');
}
$doc = (new \ReflectionClass($class))->getDocComment();
if (preg_match_all('/@method\s+static\s+(\w+)/i', $doc, $matches)) {
foreach ($matches[1] as $name) {
self::$enums[$class][$name] = new static($name);
}
} else {
throw new \Exception('Please provide a PHPDoc for ' . $class . ' with a static @method for each enum value.');
}
}
}
/**
* @method static RED()
* @method static GREEN()
* @method static BLUE()
*/
class Color extends Enum {}
$red = Color::RED();
$red2 = Color::RED();
$green = Color::GREEN();
var_dump($red === $red2);
var_dump($red == $red2);
var_dump($red === $green);
var_dump($red == $green);
var_dump((string) $red);
var_dump((string) $green);
var_dump($red === Color::fromString('RED'));
var_dump(Color::getAll());
try {
$geern = Color::GEERN(); // Intentional typo. Throws.
} catch (\Throwable $e) {
echo get_class($e) . ': ' . $e->getMessage(). "\n";
}
try {
Enum::getAll(); // Shouldn't call methods directly on Enum. Throws.
} catch (\Throwable $e) {
echo get_class($e) . ': ' . $e->getMessage(). "\n";
}
- Output for 7.0.0 - 7.0.33, 7.1.0 - 7.1.30, 7.2.0 - 7.2.33, 7.3.0 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.28, 8.2.0 - 8.2.18, 8.3.0 - 8.3.4, 8.3.6
- bool(true)
bool(true)
bool(false)
bool(false)
string(3) "RED"
string(5) "GREEN"
bool(true)
array(3) {
["RED"]=>
object(Color)#1 (1) {
["name":"Enum":private]=>
string(3) "RED"
}
["GREEN"]=>
object(Color)#2 (1) {
["name":"Enum":private]=>
string(5) "GREEN"
}
["BLUE"]=>
object(Color)#3 (1) {
["name":"Enum":private]=>
string(4) "BLUE"
}
}
TypeError: Undefined enum Color::GEERN()
Exception: Do not invoke methods directly on class Enum.
- Output for 8.3.5
- Warning: PHP Startup: Unable to load dynamic library 'sodium.so' (tried: /usr/lib/php/8.3.5/modules/sodium.so (libsodium.so.23: cannot open shared object file: No such file or directory), /usr/lib/php/8.3.5/modules/sodium.so.so (/usr/lib/php/8.3.5/modules/sodium.so.so: cannot open shared object file: No such file or directory)) in Unknown on line 0
bool(true)
bool(true)
bool(false)
bool(false)
string(3) "RED"
string(5) "GREEN"
bool(true)
array(3) {
["RED"]=>
object(Color)#1 (1) {
["name":"Enum":private]=>
string(3) "RED"
}
["GREEN"]=>
object(Color)#2 (1) {
["name":"Enum":private]=>
string(5) "GREEN"
}
["BLUE"]=>
object(Color)#3 (1) {
["name":"Enum":private]=>
string(4) "BLUE"
}
}
TypeError: Undefined enum Color::GEERN()
Exception: Do not invoke methods directly on class Enum.
- Output for 5.6.38 - 5.6.40
- Parse error: syntax error, unexpected ':', expecting ';' or '{' in /in/ZQhMn on line 14
Process exited with code 255.
preferences:
204.68 ms | 401 KiB | 237 Q