Completed
Pull Request — master (#3)
by Pavel
02:59
created

Enum::__callStatic()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
crap 2
1
<?php
2
3
namespace Paillechat\Enum;
4
5
use Paillechat\Enum\Exception\EnumException;
6
7
abstract class Enum
8
{
9
    /** @var string */
10
    private static $defaultConstantName = '__default';
11
    /** @var \ReflectionClass[] */
12
    private static $reflections;
13
    /** @var mixed */
14
    protected $value;
15
16
    /**
17
     * @param mixed $value
18
     *
19
     * @throws EnumException
20
     */
21 7
    final public function __construct($value = null)
22
    {
23 7
        if ($value === null) {
24 3
            $value = static::getDefaultValue();
25
        }
26
27 6
        $this->assertValue($value);
28
29 5
        $this->value = $value;
30 5
    }
31
32
    /**
33
     * @param bool $includeDefault
34
     *
35
     * @return array
36
     */
37 11
    final public static function getConstList(bool $includeDefault = false): array
38
    {
39 11
        self::$reflections[static::class] =
40 11
            self::$reflections[static::class] ??
41 1
            new \ReflectionClass(static::class);
42
43 11
        return array_filter(
44 11
            self::$reflections[static::class]->getConstants(),
45 11
            function ($key) use ($includeDefault) {
46 11
                if ($includeDefault === false && $key === self::$defaultConstantName) {
47 1
                    return false;
48
                }
49
50 11
                return true;
51 11
            },
52 11
            ARRAY_FILTER_USE_KEY
53
        );
54
    }
55
56
    /**
57
     * Creates enum instance with short static constructor
58
     *
59
     * @param string $name
60
     * @param array $arguments
61
     *
62
     * @return static
63
     *
64
     * @throws \BadMethodCallException
65
     */
66 2
    final public static function __callStatic(string $name, array $arguments)
67
    {
68 2
        $const = static::getConstList();
69
70 2
        if (!array_key_exists($name, $const)) {
71 1
            throw new \BadMethodCallException(sprintf('Unknown static constructor "%s" for %s', $name, static::class));
72
        }
73
74 1
        return new static($const[$name]);
75
    }
76
77
    /**
78
     * @return mixed
79
     *
80
     * @throws EnumException
81
     */
82 3
    protected static function getDefaultValue()
83
    {
84 3
        $const = static::getConstList(true);
85
86 3
        if (!array_key_exists(self::$defaultConstantName, $const)) {
87 1
            throw EnumException::becauseNoDefaultValue(static::class);
88
        }
89
90 2
        return $const[self::$defaultConstantName];
91
    }
92
93
    /**
94
     * @return mixed
95
     */
96 6
    final public function getValue()
97
    {
98 6
        return $this->value;
99
    }
100
101
    /**
102
     * Compares one Enum with another.
103
     *
104
     * @param Enum $enum
105
     *
106
     * @return bool True if Enums are equal, false if not equal
107
     */
108 3
    final public function equals(Enum $enum)
109
    {
110 3
        return $this->getValue() === $enum->getValue() && static::class === get_class($enum);
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116 1
    public function __toString(): string
117
    {
118 1
        return (string) $this->getValue();
119
    }
120
121
    /**
122
     * @param mixed $value
123
     *
124
     * @throws EnumException
125
     */
126 6
    private function assertValue($value)
127
    {
128 6
        $const = static::getConstList(true);
129
130 6
        $defaultValueUsed = $value === null && isset($const[self::$defaultConstantName]);
131
132 6
        if (!$defaultValueUsed && !in_array($value, $const, true)) {
133 1
            throw EnumException::becauseUnrecognisedValue(static::class, $value);
134
        }
135 5
    }
136
}
137