ReflectionProperty   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 10

Test Coverage

Coverage 95.06%

Importance

Changes 0
Metric Value
wmc 34
lcom 3
cbo 10
dl 0
loc 266
ccs 77
cts 81
cp 0.9506
rs 9.68
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 3
A getNode() 0 4 1
A getTypeNode() 0 4 1
A ___debugInfo() 0 7 2
A __toString() 0 9 3
A getDeclaringClass() 0 4 1
A getDocComment() 0 6 2
A getModifiers() 0 18 5
A getName() 0 4 1
A getValue() 0 16 3
A isDefault() 0 6 1
A isPrivate() 0 4 1
A isProtected() 0 4 1
A isPublic() 0 4 1
A isStatic() 0 4 1
A setAccessible() 0 6 1
A setValue() 0 6 1
A collectFromClassNode() 0 20 4
A __initialize() 0 4 1
1
<?php
2
/**
3
 * Parser Reflection API
4
 *
5
 * @copyright Copyright 2015, 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
11
namespace Go\ParserReflection;
12
13
use Go\ParserReflection\Traits\InitializationTrait;
14
use Go\ParserReflection\Traits\InternalPropertiesEmulationTrait;
15
use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
16
use PhpParser\Node\Stmt\ClassLike;
17
use PhpParser\Node\Stmt\Property;
18
use PhpParser\Node\Stmt\PropertyProperty;
19
use ReflectionProperty as BaseReflectionProperty;
20
21
/**
22
 * AST-based reflection for class property
23
 */
24
class ReflectionProperty extends BaseReflectionProperty
25
{
26
    use InitializationTrait, InternalPropertiesEmulationTrait;
27
28
    /**
29
     * Type of property node
30
     *
31
     * @var Property
32
     */
33
    private $propertyTypeNode;
34
35
    /**
36
     * Concrete property node
37
     *
38
     * @var PropertyProperty
39
     */
40
    private $propertyNode;
41
42
    /**
43
     * Name of the class
44
     *
45
     * @var string
46
     */
47
    private $className;
48
49
    /**
50
     * Initializes a reflection for the property
51
     *
52
     * @param string $className Name of the class with properties
53
     * @param string $propertyName Name of the property to reflect
54
     * @param Property $propertyType Property type definition node
55
     * @param PropertyProperty $propertyNode Concrete property definition (value, name)
56
     */
57 20
    public function __construct(
58
        $className,
59
        $propertyName,
60
        Property $propertyType = null,
61
        PropertyProperty $propertyNode = null
62
    ) {
63 20
        $this->className = ltrim($className, '\\');
64 20
        if (!$propertyType || !$propertyNode) {
65 1
            list ($propertyType, $propertyNode) = ReflectionEngine::parseClassProperty($className, $propertyName);
66
        }
67
68 20
        $this->propertyTypeNode = $propertyType;
69 20
        $this->propertyNode     = $propertyNode;
70
71
        // Let's unset original read-only properties to have a control over them via __get
72 20
        unset($this->name, $this->class);
73 20
    }
74
75
    /**
76
     * Returns an AST-node for property
77
     *
78
     * @return PropertyProperty
79
     */
80
    public function getNode()
81
    {
82
        return $this->propertyNode;
83
    }
84
85
    /**
86
     * Returns an AST-node for property type
87
     *
88
     * @return Property
89
     */
90
    public function getTypeNode()
91
    {
92
        return $this->propertyTypeNode;
93
    }
94
95
    /**
96
     * Emulating original behaviour of reflection
97
     */
98 1
    public function ___debugInfo()
99
    {
100
        return array(
101 1
            'name'  => isset($this->propertyNode) ? $this->propertyNode->name->toString() : 'unknown',
102 1
            'class' => $this->className
103
        );
104
    }
105
106
    /**
107
     * Return string representation of this little old property.
108
     *
109
     * @return string
110
     */
111 26
    public function __toString()
112
    {
113 26
        return sprintf(
114 26
            "Property [%s %s $%s ]\n",
115 26
            $this->isStatic() ? '' : ($this->isDefault() ? ' <default>' : ' <dynamic>'),
116 26
            join(' ', \Reflection::getModifierNames($this->getModifiers())),
117 26
            $this->getName()
118
        );
119
    }
120
121
    /**
122
     * {@inheritDoc}
123
     */
124 15
    public function getDeclaringClass()
125
    {
126 15
        return new ReflectionClass($this->className);
127
    }
128
129
    /**
130
     * @inheritDoc
131
     */
132 26
    public function getDocComment()
133
    {
134 26
        $docBlock = $this->propertyTypeNode->getDocComment();
135
136 26
        return $docBlock ? $docBlock->getText() : false;
137
    }
138
139
    /**
140
     * {@inheritDoc}
141
     */
142 60
    public function getModifiers()
143
    {
144 60
        $modifiers = 0;
145 60
        if ($this->isPublic()) {
146 28
            $modifiers += self::IS_PUBLIC;
147
        }
148 60
        if ($this->isProtected()) {
149 22
            $modifiers += self::IS_PROTECTED;
150
        }
151 60
        if ($this->isPrivate()) {
152 22
            $modifiers += self::IS_PRIVATE;
153
        }
154 60
        if ($this->isStatic()) {
155 32
            $modifiers += self::IS_STATIC;
156
        }
157
158 60
        return $modifiers;
159
    }
160
161
    /**
162
     * @inheritDoc
163
     */
164 268
    public function getName()
165
    {
166 268
        return $this->propertyNode->name->toString();
167
    }
168
169
    /**
170
     * @inheritDoc
171
     */
172 16
    public function getValue($object = null)
173
    {
174 16
        if (!isset($object)) {
175 15
            $solver = new NodeExpressionResolver($this->getDeclaringClass());
176 15
            if (!isset($this->propertyNode->default)) {
177 2
                return null;
178
            }
179 13
            $solver->process($this->propertyNode->default);
180
181 13
            return $solver->getValue();
182
        }
183
184 1
        $this->initializeInternalReflection();
185
186 1
        return parent::getValue($object);
187
    }
188
189
    /**
190
     * @inheritDoc
191
     */
192 39
    public function isDefault()
193
    {
194
        // TRUE if the property was declared at compile-time
195
196 39
        return true;
197
    }
198
199
    /**
200
     * {@inheritDoc}
201
     */
202 86
    public function isPrivate()
203
    {
204 86
        return $this->propertyTypeNode->isPrivate();
205
    }
206
207
    /**
208
     * {@inheritDoc}
209
     */
210 86
    public function isProtected()
211
    {
212 86
        return $this->propertyTypeNode->isProtected();
213
    }
214
215
    /**
216
     * {@inheritDoc}
217
     */
218 86
    public function isPublic()
219
    {
220 86
        return $this->propertyTypeNode->isPublic();
221
    }
222
223
    /**
224
     * {@inheritDoc}
225
     */
226 93
    public function isStatic()
227
    {
228 93
        return $this->propertyTypeNode->isStatic();
229
    }
230
231
    /**
232
     * {@inheritDoc}
233
     */
234 2
    public function setAccessible($accessible)
235
    {
236 2
        $this->initializeInternalReflection();
237
238 2
        parent::setAccessible($accessible);
239 2
    }
240
241
    /**
242
     * @inheritDoc
243
     */
244 1
    public function setValue($object, $value = null)
245
    {
246 1
        $this->initializeInternalReflection();
247
248 1
        parent::setValue($object, $value);
249 1
    }
250
251
    /**
252
     * Parses properties from the concrete class node
253
     *
254
     * @param ClassLike $classLikeNode Class-like node
255
     * @param string    $fullClassName FQN of the class
256
     *
257
     * @return array|ReflectionProperty[]
258
     */
259 44
    public static function collectFromClassNode(ClassLike $classLikeNode, $fullClassName)
260
    {
261 44
        $properties = [];
262
263 44
        foreach ($classLikeNode->stmts as $classLevelNode) {
264 40
            if ($classLevelNode instanceof Property) {
265 19
                foreach ($classLevelNode->props as $classPropertyNode) {
266 19
                    $propertyName = $classPropertyNode->name->toString();
267 19
                    $properties[$propertyName] = new static(
268 19
                        $fullClassName,
269 19
                        $propertyName,
270 19
                        $classLevelNode,
271 40
                        $classPropertyNode
272
                    );
273
                }
274
            }
275
        }
276
277 44
        return $properties;
278
    }
279
280
    /**
281
     * Implementation of internal reflection initialization
282
     *
283
     * @return void
284
     */
285 2
    protected function __initialize()
286
    {
287 2
        parent::__construct($this->className, $this->getName());
288 2
    }
289
}
290