Created
January 7, 2019 02:52
-
-
Save FerrielMelarpis/b0209e57f0c3302afc8e650a902b85f8 to your computer and use it in GitHub Desktop.
PHP Enum
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class InvalidValueException extends InvalidArgumentException { | |
public function __construct( $value, $class ) { | |
$message = sprintf( '%s is not an acceptable value for "%s" enum.', json_encode( $value ), $class ); | |
parent::__construct( $message ); | |
} | |
} | |
interface EnumInterface { | |
/** | |
* @param int|string $value The value of a particular enumerated constant | |
* | |
* @throws InvalidValueException When $value is not acceptable for this enumeration type | |
* | |
* @return EnumInterface The enum instance for given value | |
*/ | |
public static function get( $value ) : self; | |
/** | |
* Returns any possible value for the enumeration. | |
* | |
* @return int[]|string[] | |
*/ | |
public static function values() : array; | |
/** | |
* @param int|string $value | |
* | |
* @return bool True if the value is acceptable for this enumeration | |
*/ | |
public static function accepts( $value ) : bool; | |
/** | |
* Returns the list of all possible enum instances. | |
* | |
* @return EnumInterface[] | |
*/ | |
public static function instances() : array; | |
/** | |
* Gets the raw value. | |
* | |
* @return int|string | |
*/ | |
public function getValue(); | |
// Determines whether two enumerations instances should be considered the same. | |
public function equals( self $enum ) : bool; | |
/** | |
* Determines if the enumeration instance value is equal to the given value. | |
* | |
* @param int|string $value | |
* | |
* @return bool | |
*/ | |
public function is( $value ) : bool; | |
} | |
abstract class Enum implements EnumInterface { | |
/** | |
* Cached array of enum instances by enum type (FQCN). | |
* This cache is used in order to make single enums values act as singletons. | |
* This means you'll always get the exact same instance for a same enum value. | |
* | |
* @var array | |
*/ | |
private static $instances; | |
/** @var mixed */ | |
protected $value; | |
/** | |
* The constructor is private and cannot be overridden: use the static get method instead. | |
* | |
* @param mixed $value The raw value of an enumeration | |
*/ | |
final private function __construct( $value ) { | |
$this->value = $value; | |
$enumType = static::class; | |
$identifier = serialize( $value ); | |
if( isset( self::$instances[ $enumType ][ $identifier ] ) ) { | |
throw new LogicException( | |
'"__construct" should not be called when an instance already exists for this enum value.' | |
); | |
} | |
if( ! isset( self::$instances[ $enumType ] ) ) { | |
self::$instances[ $enumType ] = []; | |
} | |
self::$instances[ $enumType ][ $identifier ] = $this; | |
} | |
public static function get( $value ) : EnumInterface { | |
// Return the cached instance for given value if it already exists: | |
$instance = self::getCachedInstance( $value ); | |
if( isset( $instance ) ) { | |
return $instance; | |
} | |
if( ! static::accepts( $value ) ) { | |
throw new InvalidValueException( $value, static::class ); | |
} | |
return new static( $value ); | |
} | |
/** | |
* Instantiates a new enumeration. | |
* | |
* @param string $name The name of a particular enumerated constant | |
* @param array $arguments | |
* | |
* @throws \BadMethodCallException On invalid constant name | |
* | |
* @return static When $name is an existing constant for this enumeration type | |
*/ | |
public static function __callStatic( $name, $arguments = [] ) : EnumInterface { | |
if( ! \defined( 'static::' . $name ) ) { | |
throw new \BadMethodCallException( sprintf( | |
'No constant named "%s" exists in class "%s"', | |
$name, | |
static::class | |
) ); | |
} | |
return static::get( \constant( 'static::' . $name ) ); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function accepts( $value ) : bool { | |
return \in_array( $value, static::values(), true ); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function instances() : array { | |
return array_map( function( $value ) { | |
return static::get( $value ); | |
}, static::values() ); | |
} | |
private static function getCachedInstance( $value ) { | |
$enumType = static::class; | |
$identifier = serialize( $value ); | |
return self::$instances[ $enumType ][ $identifier ] ?? null; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getValue() { | |
return $this->value; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function equals( self $enum ) : bool { | |
return \get_class( $this ) === \get_class( $enum ) && $this->value === $enum->getValue(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function is( $value ) : bool { | |
return $this->getValue() === $value; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment