Completed
Push — master ( 253768...f248bf )
by Alexander
02:29
created

ReflectionMethod::collectFromClassNode()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
ccs 12
cts 12
cp 1
rs 9.4286
cc 3
eloc 10
nc 3
nop 2
crap 3
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\ReflectionFunctionLikeTrait;
14
use PhpParser\Node\Stmt\ClassLike;
15
use PhpParser\Node\Stmt\ClassMethod;
16
use ReflectionMethod as BaseReflectionMethod;
17
18
/**
19
 * AST-based reflection for the method in a class
20
 */
21
class ReflectionMethod extends BaseReflectionMethod
22
{
23
    use ReflectionFunctionLikeTrait;
24
25
    /**
26
     * Name of the class
27
     *
28
     * @var string
29
     */
30
    private $className;
31
32
    /**
33
     * Initializes reflection instance for the method node
34
     *
35
     * @param string $className Name of the class
36
     * @param string $methodName Name of the method
37
     * @param ClassMethod $classMethodNode AST-node for method
38
     */
39 4
    public function __construct($className, $methodName, ClassMethod $classMethodNode = null)
40
    {
41
        //for some reason, ReflectionMethod->getNamespaceName in php always returns '', so we shouldn't use it too
42 4
        $this->className        = $className;
43 4
        $this->functionLikeNode = $classMethodNode ?: ReflectionEngine::parseClassMethod($className, $methodName);
44 4
    }
45
46
    /**
47
     * Emulating original behaviour of reflection
48
     */
49
    public function __debugInfo()
50
    {
51
        return [
52
            'name'  => $this->getClassMethodNode()->name,
53
            'class' => $this->className
54
        ];
55
    }
56
57
    /**
58
     * Returns the string representation of the Reflection method object.
59
     *
60
     * @link http://php.net/manual/en/reflectionmethod.tostring.php
61
     *
62
     * @return string
63
     */
64 1
    public function __toString()
65
    {
66 1
        $paramFormat      = ($this->getNumberOfParameters() > 0) ? "\n\n  - Parameters [%d] {%s\n  }" : '';
67 1
        $methodParameters = $this->getParameters();
68
69 1
        $paramString = '';
70 1
        $identation  = str_repeat(' ', 4);
71 1
        foreach ($methodParameters as $methodParameter) {
72 1
            $paramString .= "\n{$identation}" . $methodParameter;
73 1
        }
74
75 1
        return sprintf(
76 1
            "%sMethod [ <user%s%s>%s%s%s %s method %s ] {\n  @@ %s %d - %d{$paramFormat}\n}\n",
77 1
            $this->getDocComment() ? $this->getDocComment() . "\n" : '',
78 1
            $this->isConstructor() ? ', ctor' : '',
79 1
            $this->isDestructor() ? ', dtor' : '',
80 1
            $this->isFinal() ? ' final' : '',
81 1
            $this->isStatic() ? ' static' : '',
82 1
            $this->isAbstract() ? ' abstract' : '',
83 1
            join(' ', \Reflection::getModifierNames($this->getModifiers() & 1792)),
84 1
            $this->getName(),
85 1
            $this->getFileName(),
86 1
            $this->getStartLine(),
87 1
            $this->getEndLine(),
88 1
            count($methodParameters),
89
            $paramString
90 1
        );
91
    }
92
93
    /**
94
     * {@inheritDoc}
95
     */
96
    public function getClosure($object)
97
    {
98
        $this->initializeInternalReflection();
99
100
        return parent::getClosure($object);
101
    }
102
103
    /**
104
     * {@inheritDoc}
105
     */
106 2
    public function getDeclaringClass()
107
    {
108 2
        return new ReflectionClass($this->className);
109
    }
110
111
    /**
112
     * {@inheritDoc}
113
     */
114 1
    public function getModifiers()
115
    {
116 1
        $modifiers = 0;
117 1
        if ($this->isPublic()) {
118 1
            $modifiers += self::IS_PUBLIC;
119 1
        }
120 1
        if ($this->isProtected()) {
121 1
            $modifiers += self::IS_PROTECTED;
122 1
        }
123 1
        if ($this->isPrivate()) {
124 1
            $modifiers += self::IS_PRIVATE;
125 1
        }
126 1
        if ($this->isAbstract()) {
127 1
            $modifiers += self::IS_ABSTRACT;
128 1
        }
129 1
        if ($this->isFinal()) {
130 1
            $modifiers += self::IS_FINAL;
131 1
        }
132 1
        if ($this->isStatic()) {
133 1
            $modifiers += self::IS_STATIC;
134 1
        }
135
136 1
        return $modifiers;
137
    }
138
139
    /**
140
     * {@inheritDoc}
141
     */
142
    public function getPrototype()
143
    {
144
        $parent = $this->getDeclaringClass()->getParentClass();
145
        if (!$parent) {
146
            throw new ReflectionException("No prototype");
147
        }
148
149
        $prototypeMethod = $parent->getMethod($this->getName());
150
        if (!$prototypeMethod) {
151
            throw new ReflectionException("No prototype");
152
        }
153
154
        return $prototypeMethod;
155
    }
156
157
    /**
158
     * {@inheritDoc}
159
     */
160
    public function invoke($object, $args = null)
161
    {
162
        $this->initializeInternalReflection();
163
164
        return call_user_func_array('parent::invoke', func_get_args());
165
    }
166
167
    /**
168
     * {@inheritDoc}
169
     */
170
    public function invokeArgs($object, array $args)
171
    {
172
        $this->initializeInternalReflection();
173
174
        return parent::invokeArgs($object, $args);
175
    }
176
177
    /**
178
     * {@inheritDoc}
179
     */
180 1
    public function isAbstract()
181
    {
182 1
        return $this->getClassMethodNode()->isAbstract();
183
    }
184
185
    /**
186
     * {@inheritDoc}
187
     */
188 1
    public function isConstructor()
189
    {
190 1
        return $this->getClassMethodNode()->name == '__construct';
191
    }
192
193
    /**
194
     * {@inheritDoc}
195
     */
196 1
    public function isDestructor()
197
    {
198 1
        return $this->getClassMethodNode()->name == '__destruct';
199
    }
200
201
    /**
202
     * {@inheritDoc}
203
     */
204 1
    public function isFinal()
205
    {
206 1
        return $this->getClassMethodNode()->isFinal();
207
    }
208
209
    /**
210
     * {@inheritDoc}
211
     */
212 1
    public function isPrivate()
213
    {
214 1
        return $this->getClassMethodNode()->isPrivate();
215
    }
216
217
    /**
218
     * {@inheritDoc}
219
     */
220 1
    public function isProtected()
221
    {
222 1
        return $this->getClassMethodNode()->isProtected();
223
    }
224
225
    /**
226
     * {@inheritDoc}
227
     */
228 2
    public function isPublic()
229
    {
230 2
        return $this->getClassMethodNode()->isPublic();
231
    }
232
233
    /**
234
     * {@inheritDoc}
235
     */
236 1
    public function isStatic()
237
    {
238 1
        return $this->getClassMethodNode()->isStatic();
239
    }
240
241
    /**
242
     * {@inheritDoc}
243
     */
244
    public function setAccessible($accessible)
245
    {
246
        $this->initializeInternalReflection();
247
248
        parent::setAccessible($accessible);
249
    }
250
251
    /**
252
     * Parses methods 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|ReflectionMethod[]
258
     */
259 6
    public static function collectFromClassNode(ClassLike $classLikeNode, $fullClassName)
260
    {
261 6
        $methods = [];
262
263 6
        foreach ($classLikeNode->stmts as $classLevelNode) {
264 6
            if ($classLevelNode instanceof ClassMethod) {
265 4
                $classLevelNode->setAttribute('fileName', $classLikeNode->getAttribute('fileName'));
266
267 4
                $methods[] = new ReflectionMethod(
268 4
                    $fullClassName,
269 4
                    $classLevelNode->name,
270
                    $classLevelNode
271 4
                );
272 4
            }
273 6
        }
274
275 6
        return $methods;
276
    }
277
278
    /**
279
     * Implementation of internal reflection initialization
280
     *
281
     * @return void
282
     */
283
    protected function __initialize()
284
    {
285
        parent::__construct($this->className, $this->getName());
286
    }
287
288
    /**
289
     * Returns ClassMethod node to prevent all possible type checks with instanceof
290
     *
291
     * @return ClassMethod
292
     */
293 2
    private function getClassMethodNode()
294
    {
295 2
        return $this->functionLikeNode;
296
    }
297
}
298