<?php
/**
* @link http://github.com/myclabs/php-enum
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace MyCLabs\Enum;
/**
* Base Enum class
*
* Create an enum by implementing this class and adding class constants.
*
* @author Matthieu Napoli <matthieu@mnapoli.fr>
* @author Daniel Costa <danielcosta@gmail.com>
* @author Mirosław Filip <mirfilip@gmail.com>
*
* @psalm-template T
* @psalm-immutable
> * @psalm-consistent-constructor
*/
abstract class Enum implements \JsonSerializable
{
/**
* Enum value
*
* @var mixed
* @psalm-var T
*/
protected $value;
/**
> * Enum key, the constant name
* Store existing constants in a static cache per object.
> *
*
> * @var string
*
> */
* @var array
> private $key;
* @psalm-var array<class-string, array<string, mixed>>
>
*/
> /**
protected static $cache = [];
/**
> * Cache of instances of the Enum class
* Creates a new value of some type
> *
*
> * @var array
* @psalm-pure
> * @psalm-var array<class-string, array<string, static>>
* @param mixed $value
> */
*
> protected static $instances = [];
* @psalm-param static<T>|T $value
>
* @throws \UnexpectedValueException if incompatible type is given.
> /**
< * @psalm-param static<T>|T $value
> * @psalm-param T $value
public function __construct($value)
{
if ($value instanceof static) {
/** @psalm-var T */
$value = $value->getValue();
}
< if (!$this->isValid($value)) {
< /** @psalm-suppress InvalidCast */
< throw new \UnexpectedValueException("Value '$value' is not part of the enum " . static::class);
< }
> /** @psalm-suppress ImplicitToStringCast assertValidValueReturningKey returns always a string but psalm has currently an issue here */
> $this->key = static::assertValidValueReturningKey($value);
/** @psalm-var T */
$this->value = $value;
}
/**
> * This method exists only for the compatibility reason when deserializing a previously serialized version
* @psalm-pure
> * that didn't had the key property
* @return mixed
> */
* @psalm-return T
> public function __wakeup()
*/
> {
public function getValue()
> /** @psalm-suppress DocblockTypeContradiction key can be null when deserializing an enum without the key */
{
> if ($this->key === null) {
return $this->value;
> /**
}
> * @psalm-suppress InaccessibleProperty key is not readonly as marked by psalm
> * @psalm-suppress PossiblyFalsePropertyAssignmentValue deserializing a case that was removed
/**
> */
* Returns the enum key (i.e. the constant name).
> $this->key = static::search($this->value);
*
> }
* @psalm-pure
> }
* @return mixed
>
*/
> /**
public function getKey()
> * @param mixed $value
{
> * @return static
return static::search($this->value);
> */
}
> public static function from($value): self
> {
/**
> $key = static::assertValidValueReturningKey($value);
* @psalm-pure
>
* @psalm-suppress InvalidCast
> return self::__callStatic($key, []);
* @return string
> }
*/
>
public function __toString()
> /**
< * @return mixed
> * @return string
< return static::search($this->value);
> return $this->key;
}
/**
* Determines if Enum should be considered equal with the variable passed as a parameter.
* Returns false if an argument is an object of different class or not an object.
*
* This method is final, for more information read https://github.com/myclabs/php-enum/issues/4
*
* @psalm-pure
* @psalm-param mixed $variable
* @return bool
*/
final public function equals($variable = null): bool
{
return $variable instanceof self
&& $this->getValue() === $variable->getValue()
&& static::class === \get_class($variable);
}
/**
* Returns the names (keys) of all constants in the Enum class
*
* @psalm-pure
* @psalm-return list<string>
* @return array
*/
public static function keys()
{
return \array_keys(static::toArray());
}
/**
* Returns instances of the Enum class of all Enum constants
*
* @psalm-pure
* @psalm-return array<string, static>
* @return static[] Constant name in key, Enum instance in value
*/
public static function values()
{
$values = array();
/** @psalm-var T $value */
foreach (static::toArray() as $key => $value) {
$values[$key] = new static($value);
}
return $values;
}
/**
* Returns all possible values as an array
*
* @psalm-pure
* @psalm-suppress ImpureStaticProperty
*
* @psalm-return array<string, mixed>
* @return array Constant name in key, constant value in value
*/
public static function toArray()
{
$class = static::class;
if (!isset(static::$cache[$class])) {
> /** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */
$reflection = new \ReflectionClass($class);
> /** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */
static::$cache[$class] = $reflection->getConstants();
}
return static::$cache[$class];
}
/**
* Check if is valid enum value
*
* @param $value
* @psalm-param mixed $value
* @psalm-pure
> * @psalm-assert-if-true T $value
* @return bool
*/
public static function isValid($value)
{
return \in_array($value, static::toArray(), true);
}
/**
> * Asserts valid enum value
* Check if is valid enum key
> *
*
> * @psalm-pure
* @param $key
> * @psalm-assert T $value
* @psalm-param string $key
> * @param mixed $value
* @psalm-pure
> */
* @return bool
> public static function assertValidValue($value): void
*/
> {
public static function isValidKey($key)
> self::assertValidValueReturningKey($value);
{
> }
$array = static::toArray();
>
> /**
return isset($array[$key]) || \array_key_exists($key, $array);
> * Asserts valid enum value
}
> *
> * @psalm-pure
/**
> * @psalm-assert T $value
* Return key for value
> * @param mixed $value
*
> * @return string
* @param $value
> */
*
> private static function assertValidValueReturningKey($value): string
* @psalm-param mixed $value
> {
* @psalm-pure
> if (false === ($key = static::search($value))) {
* @return mixed
> throw new \UnexpectedValueException("Value '$value' is not part of the enum " . static::class);
*/
> }
public static function search($value)
>
{
> return $key;
return \array_search($value, static::toArray(), true);
> }
}
>
> /**
< * @param $value
> * @param mixed $value
< * @return mixed
> * @return string|false
*
* @param string $name
* @param array $arguments
*
* @return static
< * @psalm-pure
* @throws \BadMethodCallException
> *
*/
> * @psalm-pure
public static function __callStatic($name, $arguments)
{
> $class = static::class;
$array = static::toArray();
> if (!isset(self::$instances[$class][$name])) {
< if (isset($array[$name]) || \array_key_exists($name, $array)) {
< return new static($array[$name]);
> if (!isset($array[$name]) && !\array_key_exists($name, $array)) {
> $message = "No static method or enum constant '$name' in class " . static::class;
> throw new \BadMethodCallException($message);
}
<
< throw new \BadMethodCallException("No static method or enum constant '$name' in class " . static::class);
> return self::$instances[$class][$name] = new static($array[$name]);
> }
> return clone self::$instances[$class][$name];
}
/**
* Specify data which should be serialized to JSON. This method returns data that can be serialized by json_encode()
* natively.
*
* @return mixed
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
* @psalm-pure
*/
> #[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->getValue();
}
}