Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 400 and 402] [Versions 400 and 403]

   1  <?php
   2  /**
   3   * @link    http://github.com/myclabs/php-enum
   4   * @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
   5   */
   6  
   7  namespace MyCLabs\Enum;
   8  
   9  /**
  10   * Base Enum class
  11   *
  12   * Create an enum by implementing this class and adding class constants.
  13   *
  14   * @author Matthieu Napoli <matthieu@mnapoli.fr>
  15   * @author Daniel Costa <danielcosta@gmail.com>
  16   * @author Mirosław Filip <mirfilip@gmail.com>
  17   *
  18   * @psalm-template T
  19   * @psalm-immutable
  20   * @psalm-consistent-constructor
  21   */
  22  abstract class Enum implements \JsonSerializable
  23  {
  24      /**
  25       * Enum value
  26       *
  27       * @var mixed
  28       * @psalm-var T
  29       */
  30      protected $value;
  31  
  32      /**
  33       * Enum key, the constant name
  34       *
  35       * @var string
  36       */
  37      private $key;
  38  
  39      /**
  40       * Store existing constants in a static cache per object.
  41       *
  42       *
  43       * @var array
  44       * @psalm-var array<class-string, array<string, mixed>>
  45       */
  46      protected static $cache = [];
  47  
  48      /**
  49       * Cache of instances of the Enum class
  50       *
  51       * @var array
  52       * @psalm-var array<class-string, array<string, static>>
  53       */
  54      protected static $instances = [];
  55  
  56      /**
  57       * Creates a new value of some type
  58       *
  59       * @psalm-pure
  60       * @param mixed $value
  61       *
  62       * @psalm-param T $value
  63       * @throws \UnexpectedValueException if incompatible type is given.
  64       */
  65      public function __construct($value)
  66      {
  67          if ($value instanceof static) {
  68             /** @psalm-var T */
  69              $value = $value->getValue();
  70          }
  71  
  72          /** @psalm-suppress ImplicitToStringCast assertValidValueReturningKey returns always a string but psalm has currently an issue here */
  73          $this->key = static::assertValidValueReturningKey($value);
  74  
  75          /** @psalm-var T */
  76          $this->value = $value;
  77      }
  78  
  79      /**
  80       * This method exists only for the compatibility reason when deserializing a previously serialized version
  81       * that didn't had the key property
  82       */
  83      public function __wakeup()
  84      {
  85          /** @psalm-suppress DocblockTypeContradiction key can be null when deserializing an enum without the key */
  86          if ($this->key === null) {
  87              /**
  88               * @psalm-suppress InaccessibleProperty key is not readonly as marked by psalm
  89               * @psalm-suppress PossiblyFalsePropertyAssignmentValue deserializing a case that was removed
  90               */
  91              $this->key = static::search($this->value);
  92          }
  93      }
  94  
  95      /**
  96       * @param mixed $value
  97       * @return static
  98       */
  99      public static function from($value): self
 100      {
 101          $key = static::assertValidValueReturningKey($value);
 102  
 103          return self::__callStatic($key, []);
 104      }
 105  
 106      /**
 107       * @psalm-pure
 108       * @return mixed
 109       * @psalm-return T
 110       */
 111      public function getValue()
 112      {
 113          return $this->value;
 114      }
 115  
 116      /**
 117       * Returns the enum key (i.e. the constant name).
 118       *
 119       * @psalm-pure
 120       * @return string
 121       */
 122      public function getKey()
 123      {
 124          return $this->key;
 125      }
 126  
 127      /**
 128       * @psalm-pure
 129       * @psalm-suppress InvalidCast
 130       * @return string
 131       */
 132      public function __toString()
 133      {
 134          return (string)$this->value;
 135      }
 136  
 137      /**
 138       * Determines if Enum should be considered equal with the variable passed as a parameter.
 139       * Returns false if an argument is an object of different class or not an object.
 140       *
 141       * This method is final, for more information read https://github.com/myclabs/php-enum/issues/4
 142       *
 143       * @psalm-pure
 144       * @psalm-param mixed $variable
 145       * @return bool
 146       */
 147      final public function equals($variable = null): bool
 148      {
 149          return $variable instanceof self
 150              && $this->getValue() === $variable->getValue()
 151              && static::class === \get_class($variable);
 152      }
 153  
 154      /**
 155       * Returns the names (keys) of all constants in the Enum class
 156       *
 157       * @psalm-pure
 158       * @psalm-return list<string>
 159       * @return array
 160       */
 161      public static function keys()
 162      {
 163          return \array_keys(static::toArray());
 164      }
 165  
 166      /**
 167       * Returns instances of the Enum class of all Enum constants
 168       *
 169       * @psalm-pure
 170       * @psalm-return array<string, static>
 171       * @return static[] Constant name in key, Enum instance in value
 172       */
 173      public static function values()
 174      {
 175          $values = array();
 176  
 177          /** @psalm-var T $value */
 178          foreach (static::toArray() as $key => $value) {
 179              $values[$key] = new static($value);
 180          }
 181  
 182          return $values;
 183      }
 184  
 185      /**
 186       * Returns all possible values as an array
 187       *
 188       * @psalm-pure
 189       * @psalm-suppress ImpureStaticProperty
 190       *
 191       * @psalm-return array<string, mixed>
 192       * @return array Constant name in key, constant value in value
 193       */
 194      public static function toArray()
 195      {
 196          $class = static::class;
 197  
 198          if (!isset(static::$cache[$class])) {
 199              /** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */
 200              $reflection            = new \ReflectionClass($class);
 201              /** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */
 202              static::$cache[$class] = $reflection->getConstants();
 203          }
 204  
 205          return static::$cache[$class];
 206      }
 207  
 208      /**
 209       * Check if is valid enum value
 210       *
 211       * @param $value
 212       * @psalm-param mixed $value
 213       * @psalm-pure
 214       * @psalm-assert-if-true T $value
 215       * @return bool
 216       */
 217      public static function isValid($value)
 218      {
 219          return \in_array($value, static::toArray(), true);
 220      }
 221  
 222      /**
 223       * Asserts valid enum value
 224       *
 225       * @psalm-pure
 226       * @psalm-assert T $value
 227       * @param mixed $value
 228       */
 229      public static function assertValidValue($value): void
 230      {
 231          self::assertValidValueReturningKey($value);
 232      }
 233  
 234      /**
 235       * Asserts valid enum value
 236       *
 237       * @psalm-pure
 238       * @psalm-assert T $value
 239       * @param mixed $value
 240       * @return string
 241       */
 242      private static function assertValidValueReturningKey($value): string
 243      {
 244          if (false === ($key = static::search($value))) {
 245              throw new \UnexpectedValueException("Value '$value' is not part of the enum " . static::class);
 246          }
 247  
 248          return $key;
 249      }
 250  
 251      /**
 252       * Check if is valid enum key
 253       *
 254       * @param $key
 255       * @psalm-param string $key
 256       * @psalm-pure
 257       * @return bool
 258       */
 259      public static function isValidKey($key)
 260      {
 261          $array = static::toArray();
 262  
 263          return isset($array[$key]) || \array_key_exists($key, $array);
 264      }
 265  
 266      /**
 267       * Return key for value
 268       *
 269       * @param mixed $value
 270       *
 271       * @psalm-param mixed $value
 272       * @psalm-pure
 273       * @return string|false
 274       */
 275      public static function search($value)
 276      {
 277          return \array_search($value, static::toArray(), true);
 278      }
 279  
 280      /**
 281       * Returns a value when called statically like so: MyEnum::SOME_VALUE() given SOME_VALUE is a class constant
 282       *
 283       * @param string $name
 284       * @param array  $arguments
 285       *
 286       * @return static
 287       * @throws \BadMethodCallException
 288       *
 289       * @psalm-pure
 290       */
 291      public static function __callStatic($name, $arguments)
 292      {
 293          $class = static::class;
 294          if (!isset(self::$instances[$class][$name])) {
 295              $array = static::toArray();
 296              if (!isset($array[$name]) && !\array_key_exists($name, $array)) {
 297                  $message = "No static method or enum constant '$name' in class " . static::class;
 298                  throw new \BadMethodCallException($message);
 299              }
 300              return self::$instances[$class][$name] = new static($array[$name]);
 301          }
 302          return clone self::$instances[$class][$name];
 303      }
 304  
 305      /**
 306       * Specify data which should be serialized to JSON. This method returns data that can be serialized by json_encode()
 307       * natively.
 308       *
 309       * @return mixed
 310       * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
 311       * @psalm-pure
 312       */
 313      #[\ReturnTypeWillChange]
 314      public function jsonSerialize()
 315      {
 316          return $this->getValue();
 317      }
 318  }