Completed
Push — master ( ecebf9...83c0fc )
by Alexander
03:38
created

ReflectionProperty   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Test Coverage

Coverage 98.85%

Importance

Changes 4
Bugs 1 Features 1
Metric Value
wmc 32
lcom 2
cbo 9
dl 0
loc 244
ccs 86
cts 87
cp 0.9885
rs 9.6
c 4
b 1
f 1

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 3
A __debugInfo() 0 7 2
A __toString() 0 9 3
A getDeclaringClass() 0 4 1
A getDocComment() 0 6 2
B getModifiers() 0 18 5
A getName() 0 4 1
A getValue() 0 16 3
A isDefault() 0 4 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 6
    public function __construct(
58
        $className,
59
        $propertyName,
60
        Property $propertyType = null,
61
        PropertyProperty $propertyNode = null
62
    ) {
63 6
        $this->className    = $className;
64 6
        if (!$propertyType || !$propertyNode) {
65 2
            list ($propertyType, $propertyNode) = ReflectionEngine::parseClassProperty($className, $propertyName);
66 2
        }
67
68 6
        $this->propertyTypeNode = $propertyType;
69 6
        $this->propertyNode     = $propertyNode;
70
71
        // Let's unset original read-only properties to have a control over them via __get
72 6
        unset($this->name, $this->class);
73 6
    }
74
75
    /**
76
     * Emulating original behaviour of reflection
77
     */
78 1
    public function __debugInfo()
79
    {
80
        return array(
81 1
            'name'  => isset($this->propertyNode) ? $this->propertyNode->name : 'unknown',
82 1
            'class' => $this->className
83 1
        );
84
    }
85
86
    /**
87
     * Return string representation of this little old property.
88
     *
89
     * @return string
90
     */
91 1
    public function __toString()
92
    {
93 1
        return sprintf(
94 1
            "Property [%s %s $%s ]\n",
95 1
            $this->isStatic() ? '' : ($this->isDefault() ? ' <default>' : ' <dynamic>'),
96 1
            join(' ', \Reflection::getModifierNames($this->getModifiers())),
97 1
            $this->getName()
98 1
        );
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     */
104 3
    public function getDeclaringClass()
105
    {
106 3
        return new ReflectionClass($this->className);
107
    }
108
109
    /**
110
     * @inheritDoc
111
     */
112 1
    public function getDocComment()
113
    {
114 1
        $docBlock = $this->propertyTypeNode->getDocComment();
115
116 1
        return $docBlock ? $docBlock->getText() : false;
117
    }
118
119
    /**
120
     * {@inheritDoc}
121
     */
122 2
    public function getModifiers()
123
    {
124 2
        $modifiers = 0;
125 2
        if ($this->isPublic()) {
126 2
            $modifiers += self::IS_PUBLIC;
127 2
        }
128 2
        if ($this->isProtected()) {
129 2
            $modifiers += self::IS_PROTECTED;
130 2
        }
131 2
        if ($this->isPrivate()) {
132 2
            $modifiers += self::IS_PRIVATE;
133 2
        }
134 2
        if ($this->isStatic()) {
135 2
            $modifiers += self::IS_STATIC;
136 2
        }
137
138 2
        return $modifiers;
139
    }
140
141
    /**
142
     * @inheritDoc
143
     */
144 4
    public function getName()
145
    {
146 4
        return $this->propertyNode->name;
147
    }
148
149
    /**
150
     * @inheritDoc
151
     */
152 4
    public function getValue($object = null)
153
    {
154 4
        if (!isset($object)) {
155 3
            $solver = new NodeExpressionResolver($this->getDeclaringClass());
156 3
            if (!isset($this->propertyNode->default)) {
157
                return null;
158
            }
159 3
            $solver->process($this->propertyNode->default);
160
161 3
            return $solver->getValue();
162
        }
163
164 1
        $this->initializeInternalReflection();
165
166 1
        return parent::getValue($object);
167
    }
168
169
    /**
170
     * @inheritDoc
171
     */
172 1
    public function isDefault()
173
    {
174 1
        return isset($this->propertyNode->default);
175
    }
176
177
    /**
178
     * {@inheritDoc}
179
     */
180 2
    public function isPrivate()
181
    {
182 2
        return $this->propertyTypeNode->isPrivate();
183
    }
184
185
    /**
186
     * {@inheritDoc}
187
     */
188 2
    public function isProtected()
189
    {
190 2
        return $this->propertyTypeNode->isProtected();
191
    }
192
193
    /**
194
     * {@inheritDoc}
195
     */
196 2
    public function isPublic()
197
    {
198 2
        return $this->propertyTypeNode->isPublic();
199
    }
200
201
    /**
202
     * {@inheritDoc}
203
     */
204 2
    public function isStatic()
205
    {
206 2
        return $this->propertyTypeNode->isStatic();
207
    }
208
209
    /**
210
     * {@inheritDoc}
211
     */
212 2
    public function setAccessible($accessible)
213
    {
214 2
        $this->initializeInternalReflection();
215
216 2
        parent::setAccessible($accessible);
217 2
    }
218
219
    /**
220
     * @inheritDoc
221
     */
222 1
    public function setValue($object, $value = null)
223
    {
224 1
        $this->initializeInternalReflection();
225
226 1
        parent::setValue($object, $value);
227 1
    }
228
229
    /**
230
     * Parses properties from the concrete class node
231
     *
232
     * @param ClassLike $classLikeNode Class-like node
233
     * @param string    $fullClassName FQN of the class
234
     *
235
     * @return array|ReflectionProperty[]
236
     */
237 5
    public static function collectFromClassNode(ClassLike $classLikeNode, $fullClassName)
238
    {
239 5
        $properties = [];
240
241 5
        foreach ($classLikeNode->stmts as $classLevelNode) {
242 5
            if ($classLevelNode instanceof Property) {
243 4
                foreach ($classLevelNode->props as $classPropertyNode) {
244 4
                    $propertyName = $classPropertyNode->name;
245 4
                    $properties[$propertyName] = new static(
246 4
                        $fullClassName,
247 4
                        $propertyName,
248 4
                        $classLevelNode,
249
                        $classPropertyNode
250 4
                    );
251 4
                }
252 4
            }
253 5
        }
254
255 5
        return $properties;
256
    }
257
258
    /**
259
     * Implementation of internal reflection initialization
260
     *
261
     * @return void
262
     */
263 2
    protected function __initialize()
264
    {
265 2
        parent::__construct($this->className, $this->getName());
266 2
    }
267
}
268