Completed
Push — master ( 7db56e...e58965 )
by Julián
01:19
created

AbstractEnum::__callStatic()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
3
/*
4
 * enum (https://github.com/phpgears/enum).
5
 * Enum object for PHP.
6
 *
7
 * @license MIT
8
 * @link https://github.com/phpgears/enum
9
 * @author Julián Gutiérrez <[email protected]>
10
 */
11
12
declare(strict_types=1);
13
14
namespace Gears\Enum;
15
16
use Gears\Enum\Exception\InvalidEnumValueException;
17
use Gears\Immutability\ImmutabilityBehaviour;
18
19
/**
20
 * Base immutable enum class.
21
 */
22
abstract class AbstractEnum implements Enum
23
{
24
    use ImmutabilityBehaviour;
25
26
    /**
27
     * Enum class constants map.
28
     *
29
     * @var array
30
     */
31
    protected static $enumConstantsMap = [];
32
33
    /**
34
     * Enum value.
35
     *
36
     * @var mixed
37
     */
38
    private $value;
39
40
    /**
41
     * AbstractEnum constructor.
42
     *
43
     * @param mixed $value
44
     *
45
     * @throws InvalidEnumValueException
46
     */
47
    final public function __construct($value)
48
    {
49
        $this->checkImmutability();
50
51
        $this->checkValue($value);
52
53
        $this->value = $value;
54
    }
55
56
    /**
57
     * Value based static constructor.
58
     *
59
     * @param string  $value
60
     * @param mixed[] $params
61
     *
62
     * @return self
63
     */
64
    final public static function __callStatic(string $value, array $params)
65
    {
66
        if (\count($params) !== 0) {
67
            throw new InvalidEnumValueException('Enum static constructor must be called with no parameters');
68
        }
69
70
        $validValues = static::getValidValues();
0 ignored issues
show
Bug introduced by
Since getValidValues() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of getValidValues() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
71
72
        if (!\array_key_exists($value, $validValues)) {
73
            throw new InvalidEnumValueException(\sprintf(
74
                '%s is not a valid value for enum %s',
75
                $value,
76
                static::class
77
            ));
78
        }
79
80
        return new static($validValues[$value]);
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    final public function isEqualTo(Enum $enum): bool
87
    {
88
        return \get_class($enum) === static::class && $enum->getValue() === $this->value;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    final public function getValue()
95
    {
96
        return $this->value;
97
    }
98
99
    /**
100
     * Check enum value validity.
101
     *
102
     * @param mixed $value
103
     *
104
     * @throws InvalidEnumValueException
105
     */
106
    private function checkValue($value): void
107
    {
108
        if (!\in_array($value, static::getValidValues(), true)) {
0 ignored issues
show
Bug introduced by
Since getValidValues() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of getValidValues() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
109
            throw new InvalidEnumValueException(\sprintf(
110
                '%s is not a valid value for enum %s',
111
                $value,
112
                static::class
113
            ));
114
        }
115
    }
116
117
    /**
118
     * Get list of valid enum values.
119
     *
120
     * @return array<string, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
121
     */
122
    private static function getValidValues(): array
123
    {
124
        $class = static::class;
125
126
        if (!isset(static::$enumConstantsMap[$class])) {
127
            static::$enumConstantsMap[$class] = (new \ReflectionClass($class))->getConstants();
128
        }
129
130
        return static::$enumConstantsMap[$class];
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     *
136
     * @return string[]
137
     */
138
    final protected function getAllowedInterfaces(): array
139
    {
140
        return [Enum::class];
141
    }
142
}
143