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\NullableType; |
||
22 | use PhpParser\Node\Stmt\ClassMethod; |
||
23 | use PhpParser\Node\Stmt\Function_; |
||
24 | use PhpParser\NodeTraverser; |
||
25 | |||
26 | /** |
||
27 | * General trait for all function-like reflections |
||
28 | */ |
||
29 | trait ReflectionFunctionLikeTrait |
||
30 | { |
||
31 | use InitializationTrait; |
||
32 | |||
33 | /** |
||
34 | * @var FunctionLike |
||
35 | */ |
||
36 | protected $functionLikeNode; |
||
37 | |||
38 | /** |
||
39 | * Namespace name |
||
40 | * |
||
41 | * @var string |
||
42 | */ |
||
43 | protected $namespaceName = ''; |
||
44 | |||
45 | /** |
||
46 | * @var array|ReflectionParameter[] |
||
47 | */ |
||
48 | protected $parameters; |
||
49 | |||
50 | /** |
||
51 | * {@inheritDoc} |
||
52 | */ |
||
53 | 64 | public function getClosureScopeClass() |
|
54 | { |
||
55 | 64 | $this->initializeInternalReflection(); |
|
56 | |||
57 | 64 | return forward_static_call('parent::getClosureScopeClass'); |
|
58 | } |
||
59 | |||
60 | /** |
||
61 | * {@inheritDoc} |
||
62 | */ |
||
63 | 64 | public function getClosureThis() |
|
64 | { |
||
65 | 64 | $this->initializeInternalReflection(); |
|
66 | |||
67 | 64 | return forward_static_call('parent::getClosureThis'); |
|
68 | } |
||
69 | |||
70 | 127 | public function getDocComment() |
|
71 | { |
||
72 | 127 | $docComment = $this->functionLikeNode->getDocComment(); |
|
73 | |||
74 | 127 | return $docComment ? $docComment->getText() : false; |
|
75 | } |
||
76 | |||
77 | 127 | public function getEndLine() |
|
78 | { |
||
79 | 127 | return $this->functionLikeNode->getAttribute('endLine'); |
|
80 | } |
||
81 | |||
82 | 64 | public function getExtension() |
|
83 | { |
||
84 | 64 | return null; |
|
85 | } |
||
86 | |||
87 | 64 | public function getExtensionName() |
|
88 | { |
||
89 | 64 | return false; |
|
90 | } |
||
91 | |||
92 | 70 | public function getFileName() |
|
93 | { |
||
94 | 70 | return $this->functionLikeNode->getAttribute('fileName'); |
|
95 | } |
||
96 | |||
97 | /** |
||
98 | * {@inheritDoc} |
||
99 | */ |
||
100 | 1997 | public function getName() |
|
101 | { |
||
102 | 1997 | if ($this->functionLikeNode instanceof Function_ || $this->functionLikeNode instanceof ClassMethod) { |
|
103 | 1997 | $functionName = $this->functionLikeNode->name; |
|
104 | |||
105 | 1997 | return $this->namespaceName ? $this->namespaceName . '\\' . $functionName : $functionName; |
|
106 | } |
||
107 | |||
108 | return false; |
||
109 | } |
||
110 | |||
111 | /** |
||
112 | * {@inheritDoc} |
||
113 | */ |
||
114 | 70 | public function getNamespaceName() |
|
115 | { |
||
116 | 70 | return $this->namespaceName; |
|
117 | } |
||
118 | |||
119 | /** |
||
120 | * Get the number of parameters that a function defines, both optional and required. |
||
121 | * |
||
122 | * @link http://php.net/manual/en/reflectionfunctionabstract.getnumberofparameters.php |
||
123 | * |
||
124 | * @return int |
||
125 | */ |
||
126 | 113 | public function getNumberOfParameters() |
|
127 | { |
||
128 | 113 | return count($this->functionLikeNode->getParams()); |
|
129 | } |
||
130 | |||
131 | /** |
||
132 | * Get the number of required parameters that a function defines. |
||
133 | * |
||
134 | * @link http://php.net/manual/en/reflectionfunctionabstract.getnumberofrequiredparameters.php |
||
135 | * |
||
136 | * @return int |
||
137 | */ |
||
138 | 64 | public function getNumberOfRequiredParameters() |
|
139 | { |
||
140 | 64 | $requiredParameters = 0; |
|
141 | 64 | foreach ($this->getParameters() as $parameter) { |
|
142 | 17 | if (!$parameter->isOptional()) { |
|
143 | 17 | $requiredParameters++; |
|
144 | } |
||
145 | } |
||
146 | |||
147 | 64 | return $requiredParameters; |
|
148 | } |
||
149 | |||
150 | /** |
||
151 | * {@inheritDoc} |
||
152 | */ |
||
153 | 204 | public function getParameters() |
|
154 | { |
||
155 | 204 | if (!isset($this->parameters)) { |
|
156 | 78 | $parameters = []; |
|
157 | |||
158 | 78 | foreach ($this->functionLikeNode->getParams() as $parameterIndex => $parameterNode) { |
|
159 | 31 | $reflectionParameter = new ReflectionParameter( |
|
160 | 31 | $this->getName(), |
|
161 | 31 | $parameterNode->name, |
|
162 | $parameterNode, |
||
163 | $parameterIndex, |
||
164 | $this |
||
165 | ); |
||
166 | 31 | $parameters[] = $reflectionParameter; |
|
167 | } |
||
168 | |||
169 | 78 | $this->parameters = $parameters; |
|
170 | } |
||
171 | |||
172 | 204 | return $this->parameters; |
|
173 | } |
||
174 | |||
175 | /** |
||
176 | * Gets the specified return type of a function |
||
177 | * |
||
178 | * @return \ReflectionType |
||
179 | * |
||
180 | * @link http://php.net/manual/en/reflectionfunctionabstract.getreturntype.php |
||
181 | */ |
||
182 | 15 | public function getReturnType() |
|
183 | { |
||
184 | 15 | $isBuiltin = false; |
|
185 | 15 | $returnType = $this->functionLikeNode->getReturnType(); |
|
186 | 15 | $isNullable = $returnType instanceof NullableType; |
|
187 | |||
188 | 15 | if ($isNullable) { |
|
189 | 6 | $returnType = $returnType->type; |
|
190 | } |
||
191 | 15 | if (is_object($returnType)) { |
|
192 | 5 | $returnType = $returnType->toString(); |
|
193 | 11 | } elseif (is_string($returnType)) { |
|
194 | 11 | $isBuiltin = true; |
|
195 | } else { |
||
196 | 1 | return null; |
|
197 | } |
||
198 | |||
199 | 15 | return new ReflectionType($returnType, $isNullable, $isBuiltin); |
|
200 | } |
||
201 | |||
202 | /** |
||
203 | * {@inheritDoc} |
||
204 | */ |
||
205 | 64 | public function getShortName() |
|
206 | { |
||
207 | 64 | if ($this->functionLikeNode instanceof Function_ || $this->functionLikeNode instanceof ClassMethod) { |
|
208 | 64 | return $this->functionLikeNode->name; |
|
209 | } |
||
210 | |||
211 | return false; |
||
212 | } |
||
213 | |||
214 | 127 | public function getStartLine() |
|
215 | { |
||
216 | 127 | return $this->functionLikeNode->getAttribute('startLine'); |
|
217 | } |
||
218 | |||
219 | /** |
||
220 | * {@inheritDoc} |
||
221 | */ |
||
222 | 64 | public function getStaticVariables() |
|
223 | { |
||
224 | 64 | $nodeTraverser = new NodeTraverser(false); |
|
0 ignored issues
–
show
|
|||
225 | 64 | $variablesCollector = new StaticVariablesCollector($this); |
|
226 | 64 | $nodeTraverser->addVisitor($variablesCollector); |
|
227 | |||
228 | /* @see https://github.com/nikic/PHP-Parser/issues/235 */ |
||
229 | 64 | $nodeTraverser->traverse($this->functionLikeNode->getStmts() ?: array()); |
|
230 | |||
231 | 64 | return $variablesCollector->getStaticVariables(); |
|
232 | } |
||
233 | |||
234 | /** |
||
235 | * Checks if the function has a specified return type |
||
236 | * |
||
237 | * @return bool |
||
238 | * |
||
239 | * @link http://php.net/manual/en/reflectionfunctionabstract.hasreturntype.php |
||
240 | */ |
||
241 | 128 | public function hasReturnType() |
|
242 | { |
||
243 | 128 | $returnType = $this->functionLikeNode->getReturnType(); |
|
244 | |||
245 | 128 | return isset($returnType); |
|
246 | } |
||
247 | |||
248 | /** |
||
249 | * {@inheritDoc} |
||
250 | */ |
||
251 | 64 | public function inNamespace() |
|
252 | { |
||
253 | 64 | return !empty($this->namespaceName); |
|
254 | } |
||
255 | |||
256 | /** |
||
257 | * {@inheritDoc} |
||
258 | */ |
||
259 | 63 | public function isClosure() |
|
260 | { |
||
261 | 63 | return $this->functionLikeNode instanceof Closure; |
|
262 | } |
||
263 | |||
264 | /** |
||
265 | * {@inheritDoc} |
||
266 | */ |
||
267 | 63 | public function isDeprecated() |
|
268 | { |
||
269 | // userland method/function/closure can not be deprecated |
||
270 | 63 | return false; |
|
271 | } |
||
272 | |||
273 | /** |
||
274 | * {@inheritDoc} |
||
275 | */ |
||
276 | 63 | public function isGenerator() |
|
277 | { |
||
278 | 63 | $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
Loading history...
|
|||
279 | 63 | $nodeDetector = new GeneratorDetector(); |
|
280 | 63 | $nodeTraverser->addVisitor($nodeDetector); |
|
281 | |||
282 | /* @see https://github.com/nikic/PHP-Parser/issues/235 */ |
||
283 | 63 | $nodeTraverser->traverse($this->functionLikeNode->getStmts() ?: array()); |
|
284 | |||
285 | 63 | return $nodeDetector->isGenerator(); |
|
286 | } |
||
287 | |||
288 | /** |
||
289 | * {@inheritDoc} |
||
290 | */ |
||
291 | 63 | public function isInternal() |
|
292 | { |
||
293 | // never can be an internal method |
||
294 | 63 | return false; |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * {@inheritDoc} |
||
299 | */ |
||
300 | 63 | public function isUserDefined() |
|
301 | { |
||
302 | // always defined by user, because we parse the source code |
||
303 | 63 | return true; |
|
304 | } |
||
305 | |||
306 | /** |
||
307 | * {@inheritDoc} |
||
308 | */ |
||
309 | 63 | public function isVariadic() |
|
310 | { |
||
311 | 63 | foreach ($this->getParameters() as $parameter) { |
|
312 | 16 | if ($parameter->isVariadic()) { |
|
313 | 16 | return true; |
|
314 | } |
||
315 | } |
||
316 | |||
317 | 61 | return false; |
|
318 | } |
||
319 | |||
320 | /** |
||
321 | * {@inheritDoc} |
||
322 | */ |
||
323 | 64 | public function returnsReference() |
|
324 | { |
||
325 | 64 | return $this->functionLikeNode->returnsByRef(); |
|
326 | } |
||
327 | } |
||
328 |
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.