Completed
Pull Request — master (#25)
by Alexander
02:46
created

ReflectionProperty::getDocComment()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
crap 2
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 19
    public function __construct(
58
        $className,
59
        $propertyName,
60
        Property $propertyType = null,
61
        PropertyProperty $propertyNode = null
62
    ) {
63 19
        $this->className    = $className;
64 19
        if (!$propertyType || !$propertyNode) {
65 2
            list ($propertyType, $propertyNode) = ReflectionEngine::parseClassProperty($className, $propertyName);
66
        }
67
68 19
        $this->propertyTypeNode = $propertyType;
69 19
        $this->propertyNode     = $propertyNode;
70
71
        // Let's unset original read-only properties to have a control over them via __get
72 19
        unset($this->name, $this->class);
73 19
    }
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
        );
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
        );
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     */
104 9
    public function getDeclaringClass()
105
    {
106 9
        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 8
    public function getModifiers()
123
    {
124 8
        $modifiers = 0;
125 8
        if ($this->isPublic()) {
126 8
            $modifiers += self::IS_PUBLIC;
127
        }
128 8
        if ($this->isProtected()) {
129 5
            $modifiers += self::IS_PROTECTED;
130
        }
131 8
        if ($this->isPrivate()) {
132 6
            $modifiers += self::IS_PRIVATE;
133
        }
134 8
        if ($this->isStatic()) {
135 5
            $modifiers += self::IS_STATIC;
136
        }
137
138 8
        return $modifiers;
139
    }
140
141
    /**
142
     * @inheritDoc
143
     */
144 10
    public function getName()
145
    {
146 10
        return $this->propertyNode->name;
147
    }
148
149
    /**
150
     * @inheritDoc
151
     */
152 10
    public function getValue($object = null)
153
    {
154 10
        if (!isset($object)) {
155 9
            $solver = new NodeExpressionResolver($this->getDeclaringClass());
156 9
            if (!isset($this->propertyNode->default)) {
157 1
                return null;
158
            }
159 8
            $solver->process($this->propertyNode->default);
160
161 8
            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 8
    public function isPrivate()
181
    {
182 8
        return $this->propertyTypeNode->isPrivate();
183
    }
184
185
    /**
186
     * {@inheritDoc}
187
     */
188 8
    public function isProtected()
189
    {
190 8
        return $this->propertyTypeNode->isProtected();
191
    }
192
193
    /**
194
     * {@inheritDoc}
195
     */
196 8
    public function isPublic()
197
    {
198 8
        return $this->propertyTypeNode->isPublic();
199
    }
200
201
    /**
202
     * {@inheritDoc}
203
     */
204 8
    public function isStatic()
205
    {
206 8
        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 46
    public static function collectFromClassNode(ClassLike $classLikeNode, $fullClassName)
238
    {
239 46
        $properties = [];
240
241 46
        foreach ($classLikeNode->stmts as $classLevelNode) {
242 38
            if ($classLevelNode instanceof Property) {
243 17
                foreach ($classLevelNode->props as $classPropertyNode) {
244 17
                    $propertyName = $classPropertyNode->name;
245 38
                    $properties[$propertyName] = new static(
246
                        $fullClassName,
247
                        $propertyName,
248
                        $classLevelNode,
249
                        $classPropertyNode
250
                    );
251
                }
252
            }
253
        }
254
255 46
        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