Completed
Pull Request — master (#4)
by Pavel
04:03
created

Enum::createNamedInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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