Completed
Push — master ( 5ecb26...a15224 )
by Alexander
10s
created

src/Traits/ReflectionFunctionLikeTrait.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Traits;
12
13
14
use Go\ParserReflection\NodeVisitor\GeneratorDetector;
15
use Go\ParserReflection\NodeVisitor\StaticVariablesCollector;
16
use Go\ParserReflection\ReflectionFileNamespace;
17
use Go\ParserReflection\ReflectionParameter;
18
use Go\ParserReflection\ReflectionType;
19
use PhpParser\Node\Expr\Closure;
20
use PhpParser\Node\FunctionLike;
21
use PhpParser\Node\Stmt\ClassMethod;
22
use PhpParser\Node\Stmt\Function_;
23
use PhpParser\NodeTraverser;
24
25
/**
26
 * General trait for all function-like reflections
27
 */
28
trait ReflectionFunctionLikeTrait
29
{
30
    use InitializationTrait;
31
32
    /**
33
     * @var FunctionLike
34
     */
35
    protected $functionLikeNode;
36
37
    /**
38
     * Namespace name
39
     *
40
     * @var string
41
     */
42
    protected $namespaceName = '';
43
44
    /**
45
     * @var array|ReflectionParameter[]
46
     */
47
    protected $parameters;
48
49
    /**
50
     * {@inheritDoc}
51
     */
52 50
    public function getClosureScopeClass()
53
    {
54 50
        $this->initializeInternalReflection();
55
56 50
        return forward_static_call('parent::getClosureScopeClass');
57
    }
58
59
    /**
60
     * {@inheritDoc}
61
     */
62 50
    public function getClosureThis()
63
    {
64 50
        $this->initializeInternalReflection();
65
66 50
        return forward_static_call('parent::getClosureThis');
67
    }
68
69 99
    public function getDocComment()
70
    {
71 99
        $docComment = $this->functionLikeNode->getDocComment();
72
73 99
        return $docComment ? $docComment->getText() : false;
74
    }
75
76 99
    public function getEndLine()
77
    {
78 99
        return $this->functionLikeNode->getAttribute('endLine');
79
    }
80
81 50
    public function getExtension()
82
    {
83 50
        return null;
84
    }
85
86 50
    public function getExtensionName()
87
    {
88 50
        return false;
89
    }
90
91 56
    public function getFileName()
92
    {
93 56
        return $this->functionLikeNode->getAttribute('fileName');
94
    }
95
96
    /**
97
     * {@inheritDoc}
98
     */
99 1557
    public function getName()
100
    {
101 1557
        if ($this->functionLikeNode instanceof Function_ || $this->functionLikeNode instanceof ClassMethod) {
102 1557
            $functionName = $this->functionLikeNode->name;
103
104 1557
            return $this->namespaceName ? $this->namespaceName . '\\' . $functionName : $functionName;
105
        }
106
107
        return false;
108
    }
109
110
    /**
111
     * {@inheritDoc}
112
     */
113 56
    public function getNamespaceName()
114
    {
115 56
        return $this->namespaceName;
116
    }
117
118
    /**
119
     * Get the number of parameters that a function defines, both optional and required.
120
     *
121
     * @link http://php.net/manual/en/reflectionfunctionabstract.getnumberofparameters.php
122
     *
123
     * @return int
124
     */
125 93
    public function getNumberOfParameters()
126
    {
127 93
        return count($this->functionLikeNode->getParams());
128
    }
129
130
    /**
131
     * Get the number of required parameters that a function defines.
132
     *
133
     * @link http://php.net/manual/en/reflectionfunctionabstract.getnumberofrequiredparameters.php
134
     *
135
     * @return int
136
     */
137 50
    public function getNumberOfRequiredParameters()
138
    {
139 50
        $requiredParameters = 0;
140 50
        foreach ($this->getParameters() as $parameter) {
141 10
            if (!$parameter->isOptional()) {
142 10
                $requiredParameters++;
143
            }
144
        }
145
146 50
        return $requiredParameters;
147
    }
148
149
    /**
150
     * {@inheritDoc}
151
     */
152 162
    public function getParameters()
153
    {
154 162
        if (!isset($this->parameters)) {
155 64
            $parameters = [];
156
157 64
            foreach ($this->functionLikeNode->getParams() as $parameterIndex => $parameterNode) {
158 24
                $reflectionParameter = new ReflectionParameter(
159 24
                    $this->getName(),
160 24
                    $parameterNode->name,
161
                    $parameterNode,
162
                    $parameterIndex,
163
                    $this
164
                );
165 24
                $parameters[] = $reflectionParameter;
166
            }
167
168 64
            $this->parameters = $parameters;
169
        }
170
171 162
        return $this->parameters;
172
    }
173
174
    /**
175
     * Gets the specified return type of a function
176
     *
177
     * @return \ReflectionType
178
     *
179
     * @link http://php.net/manual/en/reflectionfunctionabstract.getreturntype.php
180
     */
181 7
    public function getReturnType()
182
    {
183 7
        $isBuiltin  = false;
184 7
        $returnType = $this->functionLikeNode->getReturnType();
185 7
        if (is_object($returnType)) {
186 3
            $returnType = $returnType->toString();
187 5
        } elseif (is_string($returnType)) {
188 5
            $isBuiltin = true;
189
        } else {
190 1
            return null;
191
        }
192
193 7
        return new ReflectionType($returnType, false, $isBuiltin);
194
    }
195
196
    /**
197
     * {@inheritDoc}
198
     */
199 50
    public function getShortName()
200
    {
201 50
        if ($this->functionLikeNode instanceof Function_ || $this->functionLikeNode instanceof ClassMethod) {
202 50
            return $this->functionLikeNode->name;
203
        }
204
205
        return false;
206
    }
207
208 99
    public function getStartLine()
209
    {
210 99
        return $this->functionLikeNode->getAttribute('startLine');
211
    }
212
213
    /**
214
     * {@inheritDoc}
215
     */
216 50
    public function getStaticVariables()
217
    {
218 50
        $nodeTraverser      = new NodeTraverser(false);
0 ignored issues
show
The call to NodeTraverser::__construct() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
219 50
        $variablesCollector = new StaticVariablesCollector($this);
220 50
        $nodeTraverser->addVisitor($variablesCollector);
221
222
        /* @see https://github.com/nikic/PHP-Parser/issues/235 */
223 50
        $nodeTraverser->traverse($this->functionLikeNode->getStmts() ?: array());
224
225 50
        return $variablesCollector->getStaticVariables();
226
    }
227
228
    /**
229
     * Checks if the function has a specified return type
230
     *
231
     * @return bool
232
     *
233
     * @link http://php.net/manual/en/reflectionfunctionabstract.hasreturntype.php
234
     */
235 100
    public function hasReturnType()
236
    {
237 100
        $returnType = $this->functionLikeNode->getReturnType();
238
239 100
        return isset($returnType);
240
    }
241
242
    /**
243
     * {@inheritDoc}
244
     */
245 50
    public function inNamespace()
246
    {
247 50
        return !empty($this->namespaceName);
248
    }
249
250
    /**
251
     * {@inheritDoc}
252
     */
253 49
    public function isClosure()
254
    {
255 49
        return $this->functionLikeNode instanceof Closure;
256
    }
257
258
    /**
259
     * {@inheritDoc}
260
     */
261 49
    public function isDeprecated()
262
    {
263
        // userland method/function/closure can not be deprecated
264 49
        return false;
265
    }
266
267
    /**
268
     * {@inheritDoc}
269
     */
270 49
    public function isGenerator()
271
    {
272 49
        $nodeTraverser = new NodeTraverser(false);
0 ignored issues
show
The call to NodeTraverser::__construct() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
273 49
        $nodeDetector  = new GeneratorDetector();
274 49
        $nodeTraverser->addVisitor($nodeDetector);
275
276
        /* @see https://github.com/nikic/PHP-Parser/issues/235 */
277 49
        $nodeTraverser->traverse($this->functionLikeNode->getStmts() ?: array());
278
279 49
        return $nodeDetector->isGenerator();
280
    }
281
282
    /**
283
     * {@inheritDoc}
284
     */
285 49
    public function isInternal()
286
    {
287
        // never can be an internal method
288 49
        return false;
289
    }
290
291
    /**
292
     * {@inheritDoc}
293
     */
294 49
    public function isUserDefined()
295
    {
296
        // always defined by user, because we parse the source code
297 49
        return true;
298
    }
299
300
    /**
301
     * {@inheritDoc}
302
     */
303 49
    public function isVariadic()
304
    {
305 49
        foreach ($this->getParameters() as $parameter) {
306 9
            if ($parameter->isVariadic()) {
307 9
                return true;
308
            }
309
        }
310
311 48
        return false;
312
    }
313
314
    /**
315
     * {@inheritDoc}
316
     */
317 50
    public function returnsReference()
318
    {
319 50
        return $this->functionLikeNode->returnsByRef();
320
    }
321
}
322