ReflectionClassConstant   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 10

Test Coverage

Coverage 98.31%

Importance

Changes 0
Metric Value
wmc 23
lcom 3
cbo 10
dl 0
loc 195
ccs 58
cts 59
cp 0.9831
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 3
A ___debugInfo() 0 7 1
A getDeclaringClass() 0 4 1
A getDocComment() 0 6 2
A getModifiers() 0 15 4
A getName() 0 4 1
A getValue() 0 6 1
A isPrivate() 0 4 1
A isProtected() 0 4 1
A isPublic() 0 4 1
A collectFromClassNode() 0 20 4
A __toString() 0 23 3
1
<?php
2
/**
3
 * Parser Reflection API
4
 *
5
 * @copyright Copyright 2019, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
declare(strict_types=1);
11
12
namespace Go\ParserReflection;
13
14
use Go\ParserReflection\Traits\InternalPropertiesEmulationTrait;
15
use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
16
use PhpParser\Node\Const_;
17
use PhpParser\Node\Stmt\ClassConst;
18
use PhpParser\Node\Stmt\ClassLike;
19
use \ReflectionClassConstant as BaseReflectionClassConstant;
20
21
class ReflectionClassConstant extends BaseReflectionClassConstant
22
{
23
    use InternalPropertiesEmulationTrait;
24
25
    /**
26
     * Concrete class constant node
27
     *
28
     * @var ClassConst
29
     */
30
    private $classConstantNode;
31
32
    /**
33
     * @var Const_
34
     */
35
    private $constNode;
36
37
    /**
38
     * Name of the class
39
     *
40
     * @var string
41
     */
42
    private $className;
43
44
    /**
45
     * Parses class constants from the concrete class node
46
     *
47
     * @param ClassLike $classLikeNode Class-like node
48
     * @param string $reflectionClassName FQN of the class
49
     *
50
     * @return array|ReflectionClassConstant[]
51
     */
52 8
    public static function collectFromClassNode(ClassLike $classLikeNode, string $reflectionClassName): array
53
    {
54 8
        $classConstants = [];
55
56 8
        foreach ($classLikeNode->stmts as $classLevelNode) {
57 8
            if ($classLevelNode instanceof ClassConst) {
58 7
                foreach ($classLevelNode->consts as $const) {
59 7
                    $classConstName = $const->name->toString();
60 7
                    $classConstants[$classConstName] = new ReflectionClassConstant(
61 7
                        $reflectionClassName,
62
                        $classConstName,
63
                        $classLevelNode,
64
                        $const
65
                    );
66
                }
67
            }
68
        }
69
70 8
        return $classConstants;
71
    }
72
73
    /**
74
     * Initializes a reflection for the class constant
75
     *
76
     * @param string $className Name of the class
77
     * @param string $classConstantName Name of the class constant to reflect
78
     * @param ClassConst $classConstNode ClassConstant definition node
79
     * @param Const_|null $constNode Concrete const definition node
80
     */
81 7
    public function __construct(
82
        string $className,
83
        string $classConstantName,
84
        ClassConst $classConstNode = null,
85
        Const_ $constNode = null
86
    ) {
87 7
        $this->className = ltrim($className, '\\');
88
89 7
        if (!$classConstNode || !$constNode) {
90
            [$classConstNode, $constNode] = ReflectionEngine::parseClassConstant($className, $classConstantName);
91
        }
92
        // Let's unset original read-only property to have a control over it via __get
93 7
        unset($this->name, $this->class);
94
95 7
        $this->classConstantNode = $classConstNode;
96 7
        $this->constNode = $constNode;
97 7
    }
98
99
    /**
100
     * Emulating original behaviour of reflection
101
     */
102 1
    public function ___debugInfo()
103
    {
104
        return [
105 1
            'name' => $this->getName(),
106 1
            'class' => $this->className
107
        ];
108
    }
109
110
    /**
111
     * @inheritDoc
112
     */
113 2
    public function getDeclaringClass()
114
    {
115 2
        return new ReflectionClass($this->className);
116
    }
117
118
    /**
119
     * @inheritDoc
120
     */
121 1
    public function getDocComment()
122
    {
123 1
        $docBlock = $this->classConstantNode->getDocComment();
124
125 1
        return $docBlock ? $docBlock->getText() : false;
126
    }
127
128
    /**
129
     * @inheritDoc
130
     */
131 2
    public function getModifiers()
132
    {
133 2
        $modifiers = 0;
134 2
        if ($this->isPublic()) {
135 2
            $modifiers += ReflectionMethod::IS_PUBLIC;
136
        }
137 2
        if ($this->isProtected()) {
138 1
            $modifiers += ReflectionMethod::IS_PROTECTED;
139
        }
140 2
        if ($this->isPrivate()) {
141 1
            $modifiers += ReflectionMethod::IS_PRIVATE;
142
        }
143
144 2
        return $modifiers;
145
    }
146
147
    /**
148
     * @inheritDoc
149
     */
150 4
    public function getName()
151
    {
152 4
        return $this->constNode->name->toString();
153
    }
154
155
    /**
156
     * @inheritDoc
157
     */
158 2
    public function getValue()
159
    {
160 2
        $solver = new NodeExpressionResolver($this->getDeclaringClass());
161 2
        $solver->process($this->constNode->value);
162 2
        return $solver->getValue();
163
    }
164
165
    /**
166
     * @inheritDoc
167
     */
168 2
    public function isPrivate()
169
    {
170 2
        return $this->classConstantNode->isPrivate();
171
    }
172
173
    /**
174
     * @inheritDoc
175
     */
176 2
    public function isProtected()
177
    {
178 2
        return $this->classConstantNode->isProtected();
179
    }
180
181
    /**
182
     * @inheritDoc
183
     */
184 2
    public function isPublic()
185
    {
186 2
        return $this->classConstantNode->isPublic();
187
    }
188
189
    /**
190
     * @inheritDoc
191
     */
192 2
    public function __toString()
193
    {
194
        # Starting from PHP7.3 gettype returns different names, need to remap them
195 2
        static $typeMap = [
196
            'integer' => 'int',
197
            'boolean' => 'bool',
198
            'double'  => 'float',
199
        ];
200 2
        $value = $this->getValue();
201 2
        $type  = gettype($value);
202 2
        if (PHP_VERSION_ID >= 70300 && isset($typeMap[$type])) {
203 2
            $type = $typeMap[$type];
204
        }
205 2
        $valueType = new ReflectionType($type, null, true);
206
207 2
        return sprintf(
208 2
            "Constant [ %s %s %s ] { %s }\n",
209 2
            implode(' ', \Reflection::getModifierNames($this->getModifiers())),
210 2
            strtolower((string) ReflectionType::convertToDisplayType($valueType)),
211 2
            $this->getName(),
212 2
            (string) $value
213
        );
214
    }
215
}
216