Completed
Pull Request — master (#7)
by Pavel
04:24
created

Enum::createByName()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 8
cts 8
cp 1
rs 9.568
c 0
b 0
f 0
cc 4
nc 6
nop 1
crap 4
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
     * @param bool $deprecate
19
     *
20
     * @throws EnumException
21 3
     *
22
     * @deprecated use by-name constructor instead
23 3
     * @see Enum::createByName
24 3
     * @see Enum::__callStatic
25
     */
26
    final public function __construct($value = null, bool $deprecate = true)
27
    {
28
        if ($deprecate) {
29
            trigger_error(__METHOD__ . ' is deprecated and will be private in 2.0. Use static constructors or createByName.', E_USER_DEPRECATED);
30
        }
31
32
        if ($value === null) {
33
            $value = static::getDefaultValue();
0 ignored issues
show
Deprecated Code introduced by
The method Paillechat\Enum\Enum::getDefaultValue() has been deprecated.

This method has been deprecated.

Loading history...
34
        }
35
36 6
        $this->assertValue($value);
37
38 6
        $this->value = $value;
39
    }
40 6
41 1
    /**
42
     * @param bool $includeDefault
43
     *
44 5
     * @return array
45
     */
46
    final public static function getConstList(bool $includeDefault = false): array
47 7
    {
48
        try {
49 7
            self::$reflections[static::class] =
50
                self::$reflections[static::class] ??
51
                new \ReflectionClass(static::class);
52 5
            // @codeCoverageIgnoreStart
53
        } catch (\ReflectionException $e) {
54 5
            throw new \LogicException('Reflection exception for static::class is not expected.');
55 5
            // @codeCoverageIgnoreEnd
56 4
        }
57
58 4
        return array_filter(
59
            self::$reflections[static::class]->getConstants(),
60
            function ($key) use ($includeDefault) {
61 5
                return !($includeDefault === false && $key === self::$defaultConstantName);
62
            },
63
            ARRAY_FILTER_USE_KEY
64 5
        );
65
    }
66 5
67
    /**
68
     * Creates enum instance by name
69 5
     *
70
     * @param string $name
71 5
     *
72
     * @return static
73
     *
74 7
     * @throws \BadMethodCallException
75
     */
76 7
    final public static function createByName(string $name)
77 3
    {
78
        $canonicalName = strtoupper($name);
79
        if ($canonicalName !== $name) {
80 7
            $name = $canonicalName;
81
            trigger_error('PSR-1 requires constant to be declared in upper case.', E_USER_NOTICE);
82
        }
83
84
        $const = static::getConstList();
85
86
        if (!array_key_exists($name, $const)) {
87
            throw new \BadMethodCallException(sprintf('Unknown static constructor "%s" for %s.', $name, static::class));
88
        }
89
90 5
        try {
91
            return new static($const[$name], false);
92 5
            // @codeCoverageIgnoreStart
93
        } catch (EnumException $e) {
94 5
            throw new \LogicException('Existence of constant value is checked. Fix constructor.');
95
            // @codeCoverageIgnoreEnd
96 5
        }
97 3
    }
98
99
    /**
100 5
     * Creates enum instance with short static constructor
101
     *
102
     * @param string $name
103 1
     * @param array $arguments
104
     *
105 1
     * @return static
106
     *
107
     * @throws \BadMethodCallException
108
     */
109
    final public static function __callStatic(string $name, array $arguments)
110
    {
111 1
        return static::createByName($name);
112
    }
113 1
114
    /**
115
     * @return mixed
116
     *
117
     * @throws EnumException
118
     *
119
     * @deprecated
120
     */
121
    protected static function getDefaultValue()
122
    {
123
        trigger_error('Default enum value is deprecated. Define argument explicitly.', E_USER_DEPRECATED);
124
125
        $const = static::getConstList(true);
126
127
        if (!array_key_exists(self::$defaultConstantName, $const)) {
128
            throw EnumException::becauseNoDefaultValue(static::class);
129
        }
130
131
        return $const[self::$defaultConstantName];
132
    }
133
134
    /**
135
     * @return mixed
136
     *
137
     * @deprecated Cast to string instead
138
     */
139
    final public function getValue()
140
    {
141
        trigger_error(__METHOD__ . ' is deprecated and will be removed in 2.0. Cast to string instead.', E_USER_DEPRECATED);
142
143
        return $this->value;
144
    }
145
146
    /**
147
     * Compares one Enum with another.
148
     *
149
     * @param Enum $enum
150
     *
151
     * @return bool True if Enums are equal, false if not equal
152
     *
153
     * @deprecated Use weak comparison instead
154
     */
155
    final public function equals(Enum $enum): bool
156
    {
157
        trigger_error(__METHOD__ . ' is deprecated and will be removed in 2.0. Use weak comparison instead.', E_USER_DEPRECATED);
158
159
        return (string) $this === (string) $enum && static::class === \get_class($enum);
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165
    public function __toString(): string
166
    {
167
        return (string) $this->getValue();
0 ignored issues
show
Deprecated Code introduced by
The method Paillechat\Enum\Enum::getValue() has been deprecated with message: Cast to string instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
168
    }
169
170
    /**
171
     * @param mixed $value
172
     *
173
     * @throws EnumException
174
     */
175
    private function assertValue($value)
176
    {
177
        $const = static::getConstList(true);
178
179
        $defaultValueUsed = $value === null && isset($const[self::$defaultConstantName]);
180
181
        if (!$defaultValueUsed && !\in_array($value, $const, true)) {
182
            throw EnumException::becauseUnrecognisedValue(static::class, $value);
183
        }
184
    }
185
}
186