Completed
Push — master ( f248bf...b86f33 )
by Alexander
03:13
created

ReflectionProperty::getValue()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.0123

Importance

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