Passed
Push — 7.x ( 42e260...f51c13 )
by Adrien
09:26
created

SplReflectionEnumUnitCase::getEnumValue()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 11
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 19
rs 9.9
1
<?php
2
3
/**
4
 * Part of SplTypes package.
5
 *
6
 * (c) Adrien Loyant <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Ducks\Component\SplTypes\Reflection;
15
16
use Ducks\Component\SplTypes\SplUnitEnum;
17
18
/**
19
 * The SplReflectionEnumUnitCase class reports information about an SplEnum unit case, which has no scalar equivalent.
20
 *
21
 * @property-read class-string<\Ducks\Component\SplTypes\SplEnumerable> $class
22
 *
23
 * @psalm-api
24
 * @psalm-immutable
25
 * @psalm-suppress PropertyNotSetInConstructor
26
 */
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<\Ducks\Comp...SplTypes\SplEnumerable> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<\Ducks\Component\SplTypes\SplEnumerable>.
Loading history...
27
class SplReflectionEnumUnitCase extends \ReflectionClassConstant
28
{
29
    /**
30
     * Internal instances enum
31
     *
32
     * @var array[]
33
     *
34
     * @phpstan-var array<string,array<string,SplUnitEnum>>
35
     */
36
    private static array $instances = [];
37
38
    /**
39
     * Instantiates a SplReflectionEnumUnitCase object
40
     *
41
     * @param object|string $class An enum instance or a name.
42
     * @param string $constant An enum constant name.
43
     *
44
     * @throws \ReflectionException if $class is not a \Ducks\Component\SplTypes\SplEnumerable
45
     *
46
     * @phpcs:ignore Generic.Files.LineLength.TooLong
47
     * @phpstan-param \Ducks\Component\SplTypes\SplEnumerable|class-string<\Ducks\Component\SplTypes\SplEnumerable> $class An enum instance or a name.
48
     * @phpstan-param string $constant An enum constant name.
49
     *
50
     * @psalm-suppress UninitializedProperty
51
     * @psalm-suppress ImpureMethodCall
52
     *
53
     * @link https://www.php.net/manual/en/reflectionenumunitcase.construct.php
54
     */
55
    public function __construct($class, string $constant)
56
    {
57
        parent::__construct($class, $constant);
58
59
        if (!$this->getEnum()->hasCase($constant)) {
60
            /** @psalm-suppress PossiblyNullOperand */
61
            throw new \ReflectionException(
62
                'Enum case ' . $this->class . '::' . $this->name . ' is not a case'
63
            );
64
        }
65
    }
66
67
    /**
68
     * Gets the reflection of the enum of this case
69
     *
70
     * @return SplReflectionEnum instance describing the Enum this case belongs to.
71
     *
72
     * @throws \ReflectionException if objectOrClass is not a \Ducks\Component\SplTypes\SplEnumerable
73
     *
74
     * @phpstan-return SplReflectionEnum<\Ducks\Component\SplTypes\SplEnumerable>
75
     *
76
     * @psalm-suppress ArgumentTypeCoercion Needed because we need to throw Error on wrong type
77
     *
78
     * @see SplReflectionEnum::__construct()
79
     * @link https://www.php.net/manual/en/reflectionenumunitcase.getenum.php
80
     */
81
    public function getEnum(): SplReflectionEnum
82
    {
83
        /** @var SplReflectionEnum<\Ducks\Component\SplTypes\SplEnumerable> */
84
        return new SplReflectionEnum($this->class);
85
    }
86
87
    /**
88
     * Gets the enum case object described by this reflection object
89
     *
90
     * @return SplUnitEnum The enum case object described by this reflection object.
91
     *
92
     * @psalm-suppress MoreSpecificReturnType
93
     * @psalm-suppress LessSpecificReturnStatement
94
     * @psalm-suppress ImpureMethodCall
95
     * @psalm-suppress ImpureStaticProperty
96
     */
97
    public function getValue(): SplUnitEnum
98
    {
99
        if (!isset(self::$instances[$this->class][$this->name])) {
100
            self::$instances[$this->class][$this->name] = $this->getEnumValue();
101
        }
102
103
        return self::$instances[$this->class][$this->name];
104
    }
105
106
    /**
107
     * Gets the enum from the class and constant name.
108
     *
109
     * @return SplUnitEnum
110
     *
111
     * @psalm-suppress ImpureMethodCall
112
     */
113
    private function getEnumValue(): SplUnitEnum
114
    {
115
        $class = $this->getDeclaringClass();
116
        /** @var SplUnitEnum $instance */
117
        $instance = $class->newInstanceWithoutConstructor();
118
119
        $object = $class->getConstructor();
120
        if ($object instanceof \ReflectionMethod) {
121
            $object->setAccessible(true);
122
            $object->invoke($instance);
123
124
            if ($class->hasProperty('name')) {
125
                $property = $class->getProperty('name');
126
                $property->setAccessible(true);
127
                $property->setValue($instance, $this->name);
128
            }
129
        }
130
131
        return $instance;
132
    }
133
}
134