Completed
Pull Request — master (#107)
by Alexander
03:29
created

ReflectionClassConstant::__debugInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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 Reflection;
20
use ReflectionClassConstant as BaseReflectionClassConstant;
21
22
class ReflectionClassConstant extends BaseReflectionClassConstant
23
{
24
    use InternalPropertiesEmulationTrait;
25
26
    /**
27
     * Concrete class constant node
28
     *
29
     * @var ClassConst
30
     */
31
    private $classConstantNode;
32
33
    /**
34
     * @var Const_
35
     */
36
    private $constNode;
37
38
    /**
39
     * Name of the class
40
     *
41
     * @var string
42
     */
43
    private $className;
44
45
    /**
46
     * Parses class constants from the concrete class node
47
     *
48
     * @param ClassLike $classLikeNode Class-like node
49
     * @param string $reflectionClassName FQN of the class
50
     *
51
     * @return array|ReflectionClassConstant[]
52
     */
53 8
    public static function collectFromClassNode(ClassLike $classLikeNode, string $reflectionClassName): array
54
    {
55 8
        $classConstants = [];
56
57 8
        foreach ($classLikeNode->stmts as $classLevelNode) {
58 8
            if ($classLevelNode instanceof ClassConst) {
59 7
                foreach ($classLevelNode->consts as $const) {
60 7
                    $classConstName = $const->name->toString();
61 7
                    $classConstants[$classConstName] = new ReflectionClassConstant(
62 7
                        $reflectionClassName,
63
                        $classConstName,
64
                        $classLevelNode,
65
                        $const
66
                    );
67
                }
68
            }
69
        }
70
71 8
        return $classConstants;
72
    }
73
74
    /**
75
     * Initializes a reflection for the class constant
76
     *
77
     * @param string      $className         Name of the class
78
     * @param string      $classConstantName Name of the class constant to reflect
79
     * @param ?ClassConst $classConstNode    ClassConstant definition node
0 ignored issues
show
Documentation introduced by
The doc-type ?ClassConst could not be parsed: Unknown type name "?ClassConst" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
80
     * @param Const_|null $constNode         Concrete const definition node
81
     */
82 7
    public function __construct(
83
        string $className,
84
        string $classConstantName,
85
        ClassConst $classConstNode = null,
86
        Const_ $constNode = null
87
    ) {
88 7
        $this->className = ltrim($className, '\\');
89
90 7
        if (!$classConstNode || !$constNode) {
91
            [$classConstNode, $constNode] = ReflectionEngine::parseClassConstant($className, $classConstantName);
92
        }
93
        // Let's unset original read-only property to have a control over it via __get
94 7
        unset($this->name, $this->class);
95
96 7
        $this->classConstantNode = $classConstNode;
97 7
        $this->constNode = $constNode;
98 7
    }
99
100
    /**
101
     * Emulating original behaviour of reflection
102
     */
103 1
    public function __debugInfo(): array
104
    {
105
        return [
106 1
            'name' => $this->getName(),
107 1
            'class' => $this->className
108
        ];
109
    }
110
111
    /**
112
     * @inheritDoc
113
     */
114 2
    public function getDeclaringClass()
115
    {
116 2
        return new ReflectionClass($this->className);
117
    }
118
119
    /**
120
     * @inheritDoc
121
     */
122 1
    public function getDocComment()
123
    {
124 1
        $docBlock = $this->classConstantNode->getDocComment();
125
126 1
        return $docBlock ? $docBlock->getText() : false;
127
    }
128
129
    /**
130
     * @inheritDoc
131
     */
132 2
    public function getModifiers()
133
    {
134 2
        $modifiers = 0;
135 2
        if ($this->isPublic()) {
136 2
            $modifiers += ReflectionMethod::IS_PUBLIC;
137
        }
138 2
        if ($this->isProtected()) {
139 1
            $modifiers += ReflectionMethod::IS_PROTECTED;
140
        }
141 2
        if ($this->isPrivate()) {
142 1
            $modifiers += ReflectionMethod::IS_PRIVATE;
143
        }
144
145 2
        return $modifiers;
146
    }
147
148
    /**
149
     * @inheritDoc
150
     */
151 4
    public function getName()
152
    {
153 4
        return $this->constNode->name->toString();
154
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159 2
    public function getValue()
160
    {
161 2
        $solver = new NodeExpressionResolver($this->getDeclaringClass());
162 2
        $solver->process($this->constNode->value);
163 2
        return $solver->getValue();
164
    }
165
166
    /**
167
     * @inheritDoc
168
     */
169 2
    public function isPrivate()
170
    {
171 2
        return $this->classConstantNode->isPrivate();
172
    }
173
174
    /**
175
     * @inheritDoc
176
     */
177 2
    public function isProtected()
178
    {
179 2
        return $this->classConstantNode->isProtected();
180
    }
181
182
    /**
183
     * @inheritDoc
184
     */
185 2
    public function isPublic()
186
    {
187 2
        return $this->classConstantNode->isPublic();
188
    }
189
190
    /**
191
     * @inheritDoc
192
     */
193 2
    public function __toString()
194
    {
195
        # Starting from PHP7.3 gettype returns different names, need to remap them
196 2
        static $typeMap = [
197
            'integer' => 'int',
198
            'boolean' => 'bool',
199
            'double'  => 'float',
200
        ];
201 2
        $value = $this->getValue();
202 2
        $type  = gettype($value);
203 2
        if (PHP_VERSION_ID >= 70300 && isset($typeMap[$type])) {
204 2
            $type = $typeMap[$type];
205
        }
206 2
        $valueType = new ReflectionType($type, null, true);
207
208 2
        return sprintf(
209 2
            "Constant [ %s %s %s ] { %s }\n",
210 2
            implode(' ', Reflection::getModifierNames($this->getModifiers())),
211 2
            strtolower((string) ReflectionType::convertToDisplayType($valueType)),
212 2
            $this->getName(),
213 2
            (string) $value
214
        );
215
    }
216
}
217