This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * \AppserverIo\Doppelgaenger\Parser\FunctionParser |
||
5 | * |
||
6 | * NOTICE OF LICENSE |
||
7 | * |
||
8 | * This source file is subject to the Open Software License (OSL 3.0) |
||
9 | * that is available through the world-wide-web at this URL: |
||
10 | * http://opensource.org/licenses/osl-3.0.php |
||
11 | * |
||
12 | * PHP version 5 |
||
13 | * |
||
14 | * @author Bernhard Wick <[email protected]> |
||
15 | * @copyright 2015 TechDivision GmbH - <[email protected]> |
||
16 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
||
17 | * @link https://github.com/appserver-io/doppelgaenger |
||
18 | * @link http://www.appserver.io/ |
||
19 | */ |
||
20 | |||
21 | namespace AppserverIo\Doppelgaenger\Parser; |
||
22 | |||
23 | use AppserverIo\Doppelgaenger\Entities\Definitions\ParameterDefinition; |
||
24 | use AppserverIo\Doppelgaenger\Entities\Definitions\Structure; |
||
25 | use AppserverIo\Doppelgaenger\Entities\Joinpoint; |
||
26 | use AppserverIo\Doppelgaenger\Entities\Lists\FunctionDefinitionList; |
||
27 | use AppserverIo\Doppelgaenger\Entities\Definitions\FunctionDefinition; |
||
28 | use AppserverIo\Doppelgaenger\Entities\Lists\ParameterDefinitionList; |
||
29 | use AppserverIo\Doppelgaenger\Dictionaries\ReservedKeywords; |
||
30 | use AppserverIo\Psr\MetaobjectProtocol\Dbc\Annotations\Ensures; |
||
31 | use AppserverIo\Psr\MetaobjectProtocol\Dbc\Annotations\Requires; |
||
32 | use AppserverIo\Doppelgaenger\Utils\Parser; |
||
33 | |||
34 | /** |
||
35 | * This class implements a parser to find all useful information in function definitions |
||
36 | * |
||
37 | * @author Bernhard Wick <[email protected]> |
||
38 | * @copyright 2015 TechDivision GmbH - <[email protected]> |
||
39 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
||
40 | * @link https://github.com/appserver-io/doppelgaenger |
||
41 | * @link http://www.appserver.io/ |
||
42 | */ |
||
43 | class FunctionParser extends AbstractParser |
||
44 | { |
||
45 | |||
46 | /** |
||
47 | * Token representing the structure this parser is used for |
||
48 | * |
||
49 | * @var integer TOKEN |
||
50 | */ |
||
51 | const TOKEN = T_FUNCTION; |
||
52 | |||
53 | /** |
||
54 | * Will return the token representing the construct |
||
55 | * |
||
56 | * @return integer |
||
57 | */ |
||
58 | public function getToken() |
||
59 | { |
||
60 | return self::TOKEN; |
||
61 | } |
||
62 | |||
63 | /** |
||
64 | * Will return a list of function definition objects extracted from a given token array |
||
65 | * |
||
66 | * @param array $tokens The token array |
||
67 | * @param boolean $getRecursive Do we have to get the ancestral contents as well? |
||
68 | * |
||
69 | * @return boolean|\AppserverIo\Doppelgaenger\Entities\Lists\FunctionDefinitionList |
||
70 | */ |
||
71 | public function getDefinitionListFromTokens(array $tokens, $getRecursive = true) |
||
72 | { |
||
73 | // First of all we need to get the function tokens |
||
74 | $tokens = $this->getFunctionTokens($tokens); |
||
75 | |||
76 | // Did we get something valuable? |
||
77 | $functionDefinitionList = new FunctionDefinitionList(); |
||
78 | $tokenCount = count($tokens); |
||
79 | if ($tokens === false) { |
||
80 | return false; |
||
81 | |||
0 ignored issues
–
show
Coding Style
introduced
by
![]() |
|||
82 | View Code Duplication | } elseif ($tokenCount === 1) { |
|
83 | // We got what we came for, or did we? |
||
84 | if (isset($tokens[0])) { |
||
85 | $functionDefinitionList->add($this->getDefinitionFromTokens($tokens[0], $getRecursive)); |
||
86 | } |
||
87 | |||
88 | return $functionDefinitionList; |
||
89 | |||
0 ignored issues
–
show
|
|||
90 | } elseif ($tokenCount > 1) { |
||
91 | // We are still here, but got a function name to look for |
||
92 | foreach ($tokens as $token) { |
||
0 ignored issues
–
show
The expression
$tokens of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
93 | try { |
||
94 | $functionDefinitionList->add($this->getDefinitionFromTokens($token, $getRecursive)); |
||
95 | |||
0 ignored issues
–
show
|
|||
96 | } catch (\UnexpectedValueException $e) { |
||
97 | // Just try the next one |
||
98 | continue; |
||
99 | } |
||
100 | } |
||
101 | } |
||
102 | |||
103 | return $functionDefinitionList; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Will return a function definition objects for a certain function |
||
108 | * |
||
109 | * @param string $functionName The name of the function to parse |
||
110 | * @param boolean $getRecursive Do we have to get the ancestral contents as well? |
||
111 | * |
||
112 | * @return boolean|\AppserverIo\Doppelgaenger\Entities\Definitions\FunctionDefinition |
||
113 | */ |
||
114 | public function getDefinition($functionName, $getRecursive = true) |
||
115 | { |
||
116 | // First of all we need to get the function tokens |
||
117 | $tokens = $this->getFunctionTokens($this->tokens); |
||
118 | $tokenCount = count($tokens); |
||
119 | |||
120 | // Did we get something valuable? |
||
121 | if ($tokens === false) { |
||
122 | return false; |
||
123 | |||
0 ignored issues
–
show
|
|||
124 | View Code Duplication | } elseif ($tokenCount === 1) { |
|
125 | // We got what we came for, or did we? |
||
126 | if (isset($tokens[0])) { |
||
127 | return $this->getDefinitionFromTokens($tokens[0], $getRecursive); |
||
128 | } |
||
129 | |||
0 ignored issues
–
show
|
|||
130 | } elseif ($tokenCount > 1) { |
||
131 | // We are still here, but got a function name to look for |
||
132 | View Code Duplication | foreach ($tokens as $token) { |
|
0 ignored issues
–
show
The expression
$tokens of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
133 | // Now iterate over the array and search for the class we want |
||
134 | for ($i = 0; $i < count($token); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
135 | if (is_array($token[$i]) && $token[$i] === T_FUNCTION && $token[$i + 2] === $functionName) { |
||
136 | return $this->getDefinitionFromTokens($token, $getRecursive); |
||
137 | } |
||
138 | } |
||
139 | } |
||
140 | } |
||
141 | |||
142 | // Still here? That sounds bad |
||
143 | return false; |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * Returns a FunctionDefinition from a token array. |
||
148 | * |
||
149 | * This method will use a set of other methods to parse a token array and retrieve any |
||
150 | * possible information from it. This information will be entered into a FunctionDefinition object. |
||
151 | * |
||
152 | * @param array $tokens The token array |
||
153 | * @param boolean $getRecursive Do we have to get the ancestral conditions as well? |
||
154 | * |
||
155 | * @return \AppserverIo\Doppelgaenger\Entities\Definitions\FunctionDefinition |
||
156 | */ |
||
157 | protected function getDefinitionFromTokens(array $tokens, $getRecursive) |
||
158 | { |
||
159 | // First of all we need a new FunctionDefinition to fill |
||
160 | $functionDefinition = new FunctionDefinition(); |
||
161 | |||
162 | // For our next step we would like to get the doc comment (if any) |
||
163 | $functionDefinition->setDocBlock($this->getDocBlock($tokens, T_FUNCTION)); |
||
164 | |||
165 | // Get start and end line |
||
166 | $functionDefinition->setStartLine($this->getStartLine($tokens)); |
||
167 | $functionDefinition->setEndLine($this->getEndLine($tokens)); |
||
168 | |||
169 | // Get the function signature |
||
170 | $functionDefinition->setIsFinal($this->hasSignatureToken($tokens, T_FINAL, T_FUNCTION)); |
||
171 | $functionDefinition->setIsAbstract($this->hasSignatureToken($tokens, T_ABSTRACT, T_FUNCTION)); |
||
172 | $functionDefinition->setVisibility($this->getFunctionVisibility($tokens)); |
||
173 | $functionDefinition->setIsStatic($this->hasSignatureToken($tokens, T_STATIC, T_FUNCTION)); |
||
174 | $functionDefinition->setName($this->getFunctionName($tokens)); |
||
175 | $functionDefinition->setStructureName($this->currentDefinition->getQualifiedName()); |
||
176 | |||
177 | // Lets also get out parameters |
||
178 | $functionDefinition->setParameterDefinitions($this->getParameterDefinitionList($tokens)); |
||
179 | |||
180 | // Do we have a private context here? If so we have to tell the annotation parser |
||
181 | $privateContext = false; |
||
182 | if ($functionDefinition->getVisibility() === 'private') { |
||
183 | $privateContext = true; |
||
184 | } |
||
185 | |||
186 | // So we got our docBlock, now we can parse the precondition annotations from it |
||
187 | $annotationParser = new AnnotationParser($this->file, $this->config, $this->tokens, $this->currentDefinition); |
||
188 | $functionDefinition->setPreconditions($annotationParser->getConditions( |
||
0 ignored issues
–
show
It seems like
$annotationParser->getCo...ATION, $privateContext) targeting AppserverIo\Doppelgaenge...Parser::getConditions() can also be of type false ; however, AppserverIo\Doppelgaenge...ion::setPreconditions() does only seem to accept object<AppserverIo\Doppe...es\Lists\AssertionList> , did you maybe forget to handle an error condition?
![]() |
|||
189 | $functionDefinition->getDocBlock(), |
||
190 | Requires::ANNOTATION, |
||
191 | $privateContext |
||
192 | )); |
||
193 | |||
194 | // get the advices |
||
195 | $functionDefinition->getPointcutExpressions()->attach($annotationParser->getPointcutExpressions( |
||
196 | $functionDefinition->getDocBlock(), |
||
197 | Joinpoint::TARGET_METHOD, |
||
198 | $functionDefinition->getName() |
||
199 | )); |
||
200 | |||
201 | // Does this method require the use of our "old" mechanism? |
||
202 | $functionDefinition->setUsesOld($this->usesKeyword($functionDefinition->getDocBlock(), ReservedKeywords::OLD)); |
||
203 | |||
204 | // We have to get the body of the function, so we can recreate it |
||
205 | $functionDefinition->setBody($this->getFunctionBody($tokens)); |
||
206 | |||
207 | // So we got our docBlock, now we can parse the postcondition annotations from it |
||
208 | $functionDefinition->setPostconditions($annotationParser->getConditions( |
||
0 ignored issues
–
show
It seems like
$annotationParser->getCo...ATION, $privateContext) targeting AppserverIo\Doppelgaenge...Parser::getConditions() can also be of type false ; however, AppserverIo\Doppelgaenge...on::setPostconditions() does only seem to accept object<AppserverIo\Doppe...es\Lists\AssertionList> , did you maybe forget to handle an error condition?
![]() |
|||
209 | $functionDefinition->getDocBlock(), |
||
210 | Ensures::ANNOTATION, |
||
211 | $privateContext |
||
212 | )); |
||
213 | |||
214 | // If we have to parse the definition in a recursive manner, we have to get the parent invariants |
||
215 | if ($getRecursive === true) { |
||
216 | // Add all the assertions we might get from ancestral dependencies |
||
217 | $this->addAncestralAssertions($functionDefinition); |
||
218 | } |
||
219 | |||
220 | return $functionDefinition; |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * This method will add all assertions any ancestral structures (parent classes, implemented interfaces) might have |
||
225 | * to the passed class definition. |
||
226 | * |
||
227 | * @param \AppserverIo\Doppelgaenger\Entities\Definitions\FunctionDefinition $functionDefinition The function definition |
||
228 | * we are working on |
||
229 | * |
||
230 | * @return void |
||
231 | */ |
||
232 | protected function addAncestralAssertions(FunctionDefinition $functionDefinition) |
||
233 | { |
||
234 | $dependencies = $this->currentDefinition->getDependencies(); |
||
235 | foreach ($dependencies as $dependency) { |
||
236 | // freshly set the dependency definition to avoid side effects |
||
237 | $dependencyDefinition = null; |
||
0 ignored issues
–
show
$dependencyDefinition is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
238 | |||
239 | $fileEntry = $this->structureMap->getEntry($dependency); |
||
240 | if (!$fileEntry instanceof Structure) { |
||
241 | // Continue, don't fail as we might have dependencies which are not under Doppelgaenger surveillance |
||
242 | continue; |
||
243 | } |
||
244 | |||
245 | // Get the needed parser |
||
246 | $structureParserFactory = new StructureParserFactory(); |
||
247 | $parser = $structureParserFactory->getInstance( |
||
248 | $fileEntry->getType(), |
||
249 | $fileEntry->getPath(), |
||
250 | $this->config, |
||
251 | $this->structureMap, |
||
252 | $this->structureDefinitionHierarchy |
||
253 | ); |
||
254 | |||
255 | // Get the definition |
||
256 | $dependencyDefinition = $parser->getDefinition( |
||
257 | $dependency, |
||
258 | true |
||
259 | ); |
||
260 | |||
261 | // Get the function definitions of the dependency structure |
||
262 | $dependencyFunctionDefinitions = $dependencyDefinition->getFunctionDefinitions(); |
||
263 | |||
264 | // If we have a method with the name of the current one we have to get the conditions as ancestrals |
||
265 | if ($dependencyFunctionDefinitions->entryExists($functionDefinition->getName())) { |
||
266 | // Get the definition |
||
267 | $dependencyFunctionDefinition = $dependencyFunctionDefinitions->get($functionDefinition->getName()); |
||
268 | // If the ancestral function uses the old keyword we have to do too |
||
269 | if ($dependencyFunctionDefinition->usesOld() !== false) { |
||
270 | $functionDefinition->setUsesOld(true); |
||
271 | } |
||
272 | |||
273 | // Get the conditions |
||
274 | $functionDefinition->setAncestralPreconditions($dependencyFunctionDefinition->getAllPreconditions(true)); |
||
275 | $functionDefinition->setAncestralPostconditions($dependencyFunctionDefinition->getAllPostconditions(true)); |
||
276 | } |
||
277 | } |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Will return a list of parameter definition objects extracted from a given token array |
||
282 | * |
||
283 | * @param array $tokens The token array |
||
284 | * |
||
285 | * @return \AppserverIo\Doppelgaenger\Entities\Lists\ParameterDefinitionList |
||
286 | * |
||
287 | * TODO Does this have to be this long? |
||
0 ignored issues
–
show
|
|||
288 | */ |
||
289 | public function getParameterDefinitionList( |
||
290 | array $tokens |
||
291 | ) { |
||
292 | // Check the tokens |
||
293 | $parameterString = ''; |
||
294 | $parameterDefinitionList = new ParameterDefinitionList(); |
||
295 | $tokenCount = count($tokens); |
||
296 | for ($i = 0; $i < $tokenCount; $i++) { |
||
297 | // If we got the function definition, no scan everything from the first ( to the next ) |
||
298 | if ($tokens[$i][0] === T_FUNCTION) { |
||
299 | $bracketPassed = null; |
||
300 | for ($j = $i; $j < $tokenCount; $j++) { |
||
301 | // If we got the function definition, no scan everything from the first ( to the closing ) |
||
302 | if ($tokens[$j] === '(') { |
||
303 | if ($bracketPassed === null) { |
||
304 | $bracketPassed = 1; |
||
305 | // We do not want to get this token as well. |
||
306 | continue; |
||
307 | |||
0 ignored issues
–
show
|
|||
308 | } else { |
||
309 | $bracketPassed++; |
||
310 | } |
||
311 | } |
||
312 | |||
313 | // We got A closing bracket, decrease the counter |
||
314 | if ($tokens[$j] === ')') { |
||
315 | $bracketPassed--; |
||
316 | } |
||
317 | |||
318 | if ($bracketPassed > 0 && $bracketPassed !== null) { |
||
319 | // Collect what we get |
||
320 | if (is_array($tokens[$j])) { |
||
321 | $parameterString .= $tokens[$j][1]; |
||
322 | |||
0 ignored issues
–
show
|
|||
323 | } else { |
||
324 | $parameterString .= $tokens[$j]; |
||
325 | } |
||
326 | } elseif ($bracketPassed !== null) { |
||
327 | // If we got the closing bracket we can leave both loops |
||
328 | break 2; |
||
329 | } |
||
330 | } |
||
331 | } |
||
332 | } |
||
333 | |||
334 | // Now lets analyse what we got |
||
335 | $parameterStrings = explode(',', $parameterString); |
||
336 | $parserUtils = new Parser(); |
||
337 | foreach ($parameterStrings as $key => $param) { |
||
338 | if ($parserUtils->getBracketCount($param, '(') > 0) { |
||
339 | $param = $param . ', ' . $parameterStrings[$key + 1]; |
||
340 | unset($parameterStrings[$key + 1]); |
||
341 | } |
||
342 | |||
343 | $param = trim($param); |
||
344 | $paramPieces = explode('$', $param); |
||
345 | |||
346 | // Get a new ParameterDefinition |
||
347 | $parameterDefinition = new ParameterDefinition(); |
||
348 | |||
349 | // we either get one or two pieces |
||
350 | if (count($paramPieces) === 1) { |
||
351 | continue; |
||
352 | |||
0 ignored issues
–
show
|
|||
353 | } elseif (count($paramPieces) === 2) { |
||
354 | $parameterDefinition->type = trim($paramPieces[0]); |
||
355 | |||
356 | // We might have an overload going on |
||
357 | $nameArray = explode('=', $paramPieces[1]); |
||
358 | $parameterDefinition->name = '$' . trim($nameArray[0]); |
||
359 | |||
360 | // check if we got a default value for overloading |
||
361 | if (isset($nameArray[1])) { |
||
362 | unset($nameArray[0]); |
||
363 | $parameterDefinition->defaultValue = trim(implode('=', $nameArray)); |
||
364 | } |
||
365 | } |
||
366 | |||
367 | // Add the definition to the list |
||
368 | $parameterDefinitionList->add($parameterDefinition); |
||
369 | } |
||
370 | |||
371 | return $parameterDefinitionList; |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * Will return the name of the function passed as a token array |
||
376 | * |
||
377 | * @param array $tokens The token array |
||
378 | * |
||
379 | * @return string |
||
380 | */ |
||
381 | public function getFunctionName( |
||
382 | array $tokens |
||
383 | ) { |
||
384 | // Check the tokens |
||
385 | $functionName = ''; |
||
386 | for ($i = 0; $i < count($tokens); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
387 | // If we got the function name |
||
388 | if ($tokens[$i][0] === T_FUNCTION && $tokens[$i + 2][0] === T_STRING) { |
||
389 | $functionName = $tokens[$i + 2][1]; |
||
390 | } |
||
391 | } |
||
392 | |||
393 | // Return what we did or did not found |
||
394 | return $functionName; |
||
395 | } |
||
396 | |||
397 | /** |
||
398 | * Will return the body of the function passed as a token array |
||
399 | * |
||
400 | * @param array $tokens The token array |
||
401 | * |
||
402 | * @return string |
||
403 | */ |
||
404 | public function getFunctionBody( |
||
405 | array $tokens |
||
406 | ) { |
||
407 | // We will iterate over the token array and collect everything |
||
408 | // from the first opening curly bracket until the last |
||
409 | $functionBody = ''; |
||
410 | for ($i = 0; $i < count($tokens); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
411 | // If we passed the function token |
||
412 | if ($tokens[$i][0] === T_FUNCTION) { |
||
413 | $passedFunction = true; |
||
414 | } |
||
415 | |||
416 | // If we got the curly bracket that opens the function |
||
417 | if ($tokens[$i] === '{' && $passedFunction === true) { |
||
0 ignored issues
–
show
The variable
$passedFunction does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
418 | // Get everything until we reach the closing bracket |
||
419 | $bracketCounter = 1; |
||
420 | for ($j = $i + 1; $j < count($tokens); $j++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
421 | // We have to count brackets. When they are even again we will break. |
||
422 | if ($tokens[$j] === '{' || $tokens[$j][0] === T_CURLY_OPEN) { |
||
423 | $bracketCounter++; |
||
424 | |||
0 ignored issues
–
show
|
|||
425 | } elseif ($tokens[$j] === '}') { |
||
426 | $bracketCounter--; |
||
427 | } |
||
428 | |||
429 | // Do we have an even amount of brackets yet? |
||
430 | if ($bracketCounter === 0) { |
||
431 | return $functionBody; |
||
432 | } |
||
433 | |||
434 | // Collect what we get |
||
435 | if (is_array($tokens[$j])) { |
||
436 | $functionBody .= $tokens[$j][1]; |
||
437 | |||
0 ignored issues
–
show
|
|||
438 | } else { |
||
439 | $functionBody .= $tokens[$j]; |
||
440 | } |
||
441 | } |
||
442 | } |
||
443 | } |
||
444 | |||
445 | // Return what we did or did not found |
||
446 | return $functionBody; |
||
447 | } |
||
448 | |||
449 | /** |
||
450 | * Will extract tokens belonging to one function (and one function only) |
||
451 | * |
||
452 | * @param array $tokens The token array |
||
453 | * |
||
454 | * @return array|boolean |
||
455 | */ |
||
456 | protected function getFunctionTokens(array $tokens) |
||
457 | { |
||
458 | // Iterate over all the tokens and filter the different function portions out |
||
459 | $result = array(); |
||
460 | for ($i = 0; $i < count($tokens); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
461 | // If we got a function keyword, we have to check how far the function extends, |
||
462 | // then copy the array within that bounds, but first of all we have to check if we got |
||
463 | // a function name. |
||
464 | // Otherwise anonymous functions will make us go crazy. |
||
465 | if (is_array($tokens[$i]) && $tokens[$i][0] === T_FUNCTION && |
||
466 | !empty($tokens[$i + 2]) && $tokens[$i + 2] !== '(' && $tokens[$i + 1] !== '(' |
||
467 | ) { |
||
468 | // The lower bound should be the last semicolon|closing curly bracket|PHP tag before the function |
||
469 | $lowerBound = 0; |
||
470 | for ($j = $i - 1; $j >= 0; $j--) { |
||
471 | if ($tokens[$j] === ';' || $tokens[$j] === '{' || |
||
472 | (is_array($tokens[$j]) && $tokens[$j][0] === T_OPEN_TAG) || |
||
473 | $tokens[$j][0] === T_CURLY_OPEN |
||
474 | ) { |
||
475 | $lowerBound = $j + 1; |
||
476 | break; |
||
477 | } |
||
478 | } |
||
479 | |||
480 | // The upper bound should be the first time the curly brackets are even again or the first occurrence |
||
481 | // of the semicolon. The semicolon is important, as we have to get function declarations in interfaces |
||
482 | // as well. |
||
483 | $upperBound = count($tokens) - 1; |
||
484 | $bracketCounter = null; |
||
485 | for ($j = $i + 1; $j < count($tokens); $j++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
486 | if ($tokens[$j] === '{' || $tokens[$j][0] === T_CURLY_OPEN) { |
||
487 | // If we still got null set to 0 |
||
488 | if ($bracketCounter === null) { |
||
489 | $bracketCounter = 0; |
||
490 | } |
||
491 | |||
492 | $bracketCounter++; |
||
493 | |||
0 ignored issues
–
show
|
|||
494 | View Code Duplication | } elseif ($tokens[$j] === '}') { |
|
495 | // If we still got null set to 0 |
||
496 | if ($bracketCounter === null) { |
||
497 | $bracketCounter = 0; |
||
498 | } |
||
499 | |||
500 | $bracketCounter--; |
||
501 | } |
||
502 | |||
503 | // Did we reach a semicolon before reaching a opening curly bracket? |
||
504 | View Code Duplication | if ($bracketCounter === null && $tokens[$j] === ';') { |
|
505 | $upperBound = $j + 1; |
||
506 | break; |
||
507 | } |
||
508 | |||
509 | // Do we have an even amount of brackets yet? |
||
510 | if ($bracketCounter === 0) { |
||
511 | $upperBound = $j + 1; |
||
512 | break; |
||
513 | } |
||
514 | } |
||
515 | |||
516 | $result[] = array_slice($tokens, $lowerBound, $upperBound - $lowerBound); |
||
517 | } |
||
518 | } |
||
519 | |||
520 | return $result; |
||
521 | } |
||
522 | |||
523 | /** |
||
524 | * Will return the visibility of the function passed as a token array |
||
525 | * |
||
526 | * @param array $tokens The token array |
||
527 | * |
||
528 | * @return string |
||
529 | * |
||
530 | * TODO I am sure this can be done more generally usable |
||
0 ignored issues
–
show
|
|||
531 | */ |
||
532 | public function getFunctionVisibility( |
||
533 | array $tokens |
||
534 | ) { |
||
535 | // Check out all the tokens and look if we find the right thing. We can do that as these keywords are not valid |
||
536 | // within a function definition. Public is default. |
||
537 | $visibility = 'public'; |
||
538 | for ($i = 0; $i < count($tokens); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
539 | // Search for the visibility |
||
540 | View Code Duplication | if (is_array($tokens[$i]) && ($tokens[$i][0] === T_PRIVATE || $tokens[$i][0] === T_PROTECTED)) { |
|
541 | // Got it! |
||
542 | $visibility = $tokens[$i][1]; |
||
543 | } |
||
544 | |||
545 | // Did we reach the function already? |
||
546 | if ($tokens[$i][0] === T_FUNCTION) { |
||
547 | break; |
||
548 | } |
||
549 | } |
||
550 | |||
551 | return $visibility; |
||
552 | } |
||
553 | } |
||
554 |