ValidVariableNameSniff::_getVariablePosition()   D
last analyzed

Complexity

Conditions 9
Paths 22

Size

Total Lines 37
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 19
nc 22
nop 2
dl 0
loc 37
rs 4.909
c 0
b 0
f 0
1
<?php
2
/**
3
 * CodeIgniter_Sniffs_NamingConventions_ValidVariableNameSniff.
4
 *
5
 * PHP version 5
6
 *
7
 * @category  PHP
8
 * @package   PHP_CodeSniffer
9
 * @author    Thomas Ernest <[email protected]>
10
 * @copyright 2010 Thomas Ernest
11
 * @license   http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
12
 * @link      http://pear.php.net/package/PHP_CodeSniffer
13
 */
14
/**
15
 * CodeIgniter_Sniffs_NamingConventions_ValidVariableNameSniff.
16
 *
17
 * Ensures that variable names contain only lowercase letters,
18
 * use underscore separators.
19
 * Ensures that class attribute names are prefixed with an underscore,
20
 * only when they are private.
21
 * Ensure that variable names are longer than 3 chars except those declared
22
 * in for loops.
23
 *
24
 * @todo Try to avoid overly long and verbose names in using property rule and
25
 * configuration variable to set limits. Have a look at
26
 * CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
27
 * @todo Use a property rule or a configuration variable to allow users to set
28
 * minimum variable name length. Have a look at
29
 * CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff and application root.
30
 *
31
 * @category  PHP
32
 * @package   PHP_CodeSniffer
33
 * @author    Thomas Ernest <[email protected]>
34
 * @copyright 2010 Thomas Ernest
35
 * @license   http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
36
 * @link      http://pear.php.net/package/PHP_CodeSniffer
37
 */
38
namespace CodeIgniter\Sniffs\NamingConventions;
39
40
use PHP_CodeSniffer\Sniffs\AbstractVariableSniff;
41
use PHP_CodeSniffer\Files\File;
42
43
class ValidVariableNameSniff extends AbstractVariableSniff
44
{
45
46
47
    /**
48
     * Processes class member variables.
49
     *
50
     * @param File $phpcsFile The file being scanned.
51
     * @param int                  $stackPtr  The position of the current token
52
     *                                        in the stack passed in $tokens.
53
     *
54
     * @return void
55
     */
56
    protected function processMemberVar(File $phpcsFile, $stackPtr)
57
    {
58
        // get variable name and properties
59
        $tokens = $phpcsFile->getTokens();
60
        $varTk = $tokens[$stackPtr];
61
        $varName = substr($varTk['content'], 1);
62
        $varProps = $phpcsFile->getMemberProperties($stackPtr);
63
        // check(s)
64
        if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName) ) {
65
            return;
66
        }
67
        if ( ! $this->checkVisibilityPrefix($phpcsFile, $stackPtr, $varName, $varProps)) {
68
            return;
69
        }
70
        if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) {
71
            return;
72
        }
73
74
    }//end processMemberVar()
75
76
77
    /**
78
     * Processes normal variables.
79
     *
80
     * @param File $phpcsFile The file where this token was found.
81
     * @param int                  $stackPtr  The position where the token was found.
82
     *
83
     * @return void
84
     */
85
    protected function processVariable(File $phpcsFile, $stackPtr)
86
    {
87
        // get variable name
88
        $tokens = $phpcsFile->getTokens();
89
        $varTk = $tokens[$stackPtr];
90
        $varName = substr($varTk['content'], 1);
91
        // skip the current object variable, i.e. $this
92
        if (0 === strcmp($varName, 'this')) {
93
            return;
94
        }
95
        // check(s)
96
        if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName)) {
97
            return;
98
        }
99
        if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) {
100
            return;
101
        }
102
103
    }//end processVariable()
104
105
106
    /**
107
     * Processes variables in double quoted strings.
108
     *
109
     * @param File $phpcsFile The file where this token was found.
110
     * @param int                  $stackPtr  The position where the token was found.
111
     *
112
     * @return void
113
     */
114
    protected function processVariableInString(File $phpcsFile, $stackPtr)
115
    {
116
        $tokens = $phpcsFile->getTokens();
117
        $stringTk = $tokens[$stackPtr];
118
        $stringString = $stringTk['content'];
119
        $varAt = self::_getVariablePosition($stringString, 0);
120
        while (false !== $varAt) {
121
            // get variable name
122
            $matches = array();
123
            preg_match('/^\$\{?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}?/', substr($stringString, $varAt), $matches);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
124
            $varName = $matches[1];
125
            // check(s)
126
            if ( ! $this->checkLowerCase($phpcsFile, $stackPtr, $varName)) {
127
                return;
128
            }
129
            if ( ! $this->checkLength($phpcsFile, $stackPtr, $varName)) {
130
                return;
131
            }
132
            // prepare checking next variable
133
            $varAt = self::_getVariablePosition($stringString, $varAt + 1);
134
        }
135
136
    }//end processVariableInString()
137
138
139
    /**
140
     * Checks that the variable name is all in lower case, else it add an error
141
     * to $phpcsFile. Returns true if variable name is all in lower case, false
142
     * otherwise.
143
     *
144
     * @param File $phpcsFile The current file being processed.
145
     * @param int                  $stackPtr  The position of the current token
146
     *                                        in the stack passed in $tokens.
147
     * @param string               $varName   The name of the variable to
148
     *                                        procced without $, { nor }.
149
     *
150
     * @return bool true if variable name is all in lower case, false otherwise.
151
     */
152
    protected function checkLowerCase(File $phpcsFile, $stackPtr, $varName)
153
    {
154
        $isInLowerCase = true;
155
        if (0 !== strcmp($varName, strtolower($varName))) {
156
            // get the expected variable name
157
            $varNameWithUnderscores = preg_replace('/([A-Z])/', '_${1}', $varName);
158
            $expectedVarName = strtolower(ltrim($varNameWithUnderscores, '_'));
159
            // adapts the error message to the error case
160
            if (strlen($varNameWithUnderscores) > strlen($varName)) {
161
                $error = 'Variables should not use CamelCasing or start with a Capital.';
162
            } else {
163
                $error = 'Variables should be entirely lowercased.';
164
            }
165
            $error = $error . 'Please consider "' . $expectedVarName
166
                . '" instead of "' . $varName . '".';
167
            // adds the error and changes return value
168
            $phpcsFile->addError($error, $stackPtr);
0 ignored issues
show
Bug introduced by
The call to addError() misses a required argument $code.

This check looks for function calls that miss required arguments.

Loading history...
169
            $isInLowerCase = false;
170
        }
171
        return $isInLowerCase;
172
    }//end checkLowerCase()
173
174
    /**
175
     * Checks that an underscore is used at the beginning of a variable only if
176
     * it is about a private variable. If it isn't a private variable, then it
177
     * must not be prefixed with an underscore. Returns true if $varName is
178
     * properly prefixed according to the variable visibility provided in
179
     * $varProps, false otherwise.
180
     *
181
     * @param File $phpcsFile The current file being processed.
182
     * @param int                  $stackPtr  The position of the current token
183
     *                                        in the stack passed in $tokens.
184
     * @param string               $varName   The name of the variable to
185
     *                                        procced without $, { nor }.
186
     * @param array                $varProps  Member variable properties like
187
     *                                        its visibility.
188
     *
189
     * @return bool true if variable name is prefixed with an underscore only
190
     * when it is about a private variable, false otherwise.
191
     */
192
    protected function checkVisibilityPrefix(File $phpcsFile, $stackPtr, $varName, $varProps)
193
    {
194
        $isVisibilityPrefixRight = true;
195
        $scope = $varProps['scope'];
196
        // If it's a private variable, it must have an underscore on the front.
197
        if ($scope === 'private' && $varName{0} !== '_') {
198
            $error = "Private variable name \"$varName\" must be prefixed with an underscore";
199
            $phpcsFile->addError($error, $stackPtr);
0 ignored issues
show
Bug introduced by
The call to addError() misses a required argument $code.

This check looks for function calls that miss required arguments.

Loading history...
200
            $isVisibilityPrefixRight = false;
201 View Code Duplication
        } else if ($scope !== 'private' && $varName{0} === '_') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
202
            // If it's not a private variable,
203
            // then it must not start with an underscore.
204
            if (isset ($scopeSpecified) && true === $scopeSpecified) {
0 ignored issues
show
Bug introduced by
The variable $scopeSpecified seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
205
                $error = "Public variable name \"$varName\" must not be prefixed with an underscore";
206
            } else {
207
                $error = ucfirst($scope) . " variable name \"$varName\" must not be prefixed with an underscore";
208
            }
209
            $phpcsFile->addError($error, $stackPtr);
0 ignored issues
show
Bug introduced by
The call to addError() misses a required argument $code.

This check looks for function calls that miss required arguments.

Loading history...
210
            $isVisibilityPrefixRight = false;
211
        }
212
        return $isVisibilityPrefixRight;
213
    }//end checkVisibilityPrefix()
214
215
    /**
216
     * Checks that variable name length is not too short. Returns true, if it
217
     * meets minimum length requirement, false otherwise.
218
     *
219
     * A variable name is too short if it is shorter than the minimal
220
     * length and it isn't in the list of allowed short names nor declared in a
221
     * for loop (in which it would be nested).
222
     * The minimal length is defined in the function. It is 3 chars now.
223
     * The list of allowed short names is defined in the function.
224
     * It is case-sensitive. It contains only 'ci' now.
225
     *
226
     * @param File $phpcsFile The current file being processed.
227
     * @param int                  $stackPtr  The position of the current token
228
     *                                        in the stack passed in $tokens.
229
     * @param string               $varName   The name of the variable to
230
     *                                        procced without $, { nor }.
231
     *
232
     * @return bool false if variable name $varName is shorter than the minimal
233
     * length and it isn't in the list of allowed short names nor declared in a
234
     * for loop (in which it would be nested), otherwise true.
235
     */
236
    protected function checkLength(File $phpcsFile, $stackPtr, $varName)
237
    {
238
        $minLength = 3;
239
        $allowedShortName = array('ci');
240
241
        $isLengthRight = true;
242
        // cleans variable name
243
        $varName = ltrim($varName, '_');
244
        if (strlen($varName) <= $minLength) {
245
            // skips adding an error, if it is a specific variable name
246
            if (in_array($varName, $allowedShortName)) {
247
                return $isLengthRight;
248
            }
249
            // skips adding an error, if the variable is in a for loop
250
            if (false !== self::_isInForLoop($phpcsFile, $stackPtr, $varName)) {
251
                return $isLengthRight;
252
            }
253
            // adds the error message finally
254
            $error = 'Very short'
255
                . (
256
                    $minLength > 0 ?
257
                    ' (i.e. less than ' . ($minLength + 1) . ' chars)'
258
                    : ''
259
                )
260
                . ', non-word variables like "' . $varName
261
                . '" should only be used as iterators in for() loops.';
262
            $phpcsFile->addError($error, $stackPtr);
0 ignored issues
show
Bug introduced by
The call to addError() misses a required argument $code.

This check looks for function calls that miss required arguments.

Loading history...
263
            $isLengthRight = false;
264
        }
265
        return $isLengthRight;
266
    }//end checkLength()
267
268
    /**
269
     * Returns the position of closest previous T_FOR, if token associated with
270
     * $stackPtr in $phpcsFile is in a for loop, otherwise false.
271
     *
272
     * @param File $phpcsFile The current file being processed.
273
     * @param int                  $stackPtr  The position of the current token
274
     *                                        in the stack passed in $tokens.
275
     * @param string               $varName   The name of the variable to
276
     *                                        procced without $, { nor }.
277
     *
278
     * @return int|bool Position of T_FOR if token associated with $stackPtr in
279
     *                  $phpcsFile is in the head of a for loop, otherwise false.
280
     */
281
    private static function _isInForLoop(File $phpcsFile, $stackPtr, $varName)
282
    {
283
        $keepLookingFromPtr = $stackPtr;
284
        while (false !== $keepLookingFromPtr) {
285
            // looks if it is in (head or body) of a for loop
286
            $forPtr = self::_isInForLoopHead($phpcsFile, $keepLookingFromPtr);
0 ignored issues
show
Bug introduced by
It seems like $keepLookingFromPtr can also be of type boolean; however, CodeIgniter\Sniffs\Namin...iff::_isInForLoopHead() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
287
            if (false === $forPtr) {
288
                $forPtr = self::_isInForLoopBody($phpcsFile, $keepLookingFromPtr);
0 ignored issues
show
Bug introduced by
It seems like $keepLookingFromPtr can also be of type boolean; however, CodeIgniter\Sniffs\Namin...iff::_isInForLoopBody() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
289
            }
290
            // checks if it is declared in here and prepares next step
291
            if (false !== $forPtr) {
292
                if (false !== self::_isDeclaredInForLoop($phpcsFile, $forPtr, $varName)) {
0 ignored issues
show
Bug introduced by
It seems like $forPtr can also be of type boolean; however, CodeIgniter\Sniffs\Namin...:_isDeclaredInForLoop() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
293
                    return $forPtr;
294
                }
295
                $keepLookingFromPtr = $forPtr;
296
            } else {
297
                $keepLookingFromPtr = false;
298
            }
299
        }
300
        return false;
301
    }//end _isInForLoop()
302
303
    /**
304
     * Returns the position of closest previous T_FOR, if token associated with
305
     * $stackPtr in $phpcsFile is in the head of a for loop, otherwise false.
306
     * The head is the code placed between parenthesis next to the key word
307
     * 'for' : for (<loop_head>) {<loop_body>}.
308
     *
309
     * @param File $phpcsFile The current file being processed.
310
     * @param int                  $stackPtr  The position of the current token
311
     *                                        in the stack passed in $tokens.
312
     *
313
     * @return int|bool Position of T_FOR if token associated with $stackPtr in
314
     *                  $phpcsFile is in the head of a for loop, otherwise false.
315
     */
316
    private static function _isInForLoopHead(File $phpcsFile, $stackPtr)
317
    {
318
        $isInForLoop = false;
319
        $tokens = $phpcsFile->getTokens();
320
        $currentTk = $tokens[$stackPtr];
321
        if (array_key_exists('nested_parenthesis', $currentTk)) {
322
            $nestedParenthesis = $currentTk['nested_parenthesis'];
323
            foreach ( $nestedParenthesis as $openParPtr => $closeParPtr) {
324
                $nonWhitspacePtr = $phpcsFile->findPrevious(
325
                    array(T_WHITESPACE),
326
                    $openParPtr - 1,
327
                    null,
328
                    true,
329
                    null,
330
                    true
331
                );
332
                if (false !== $nonWhitspacePtr) {
333
                    $isFor = T_FOR === $tokens[$nonWhitspacePtr]['code'];
334
                    if ($isFor) {
335
                        $isInForLoop = $nonWhitspacePtr;
336
                        break;
337
                    }
338
                }
339
            }
340
        }
341
        return $isInForLoop;
342
    }//end _isInForLoopHead()
343
344
    /**
345
     * Returns the position of closest previous T_FOR, if token associated with
346
     * $stackPtr in $phpcsFile is in the body of a for loop, otherwise false.
347
     * The body are the instructions placed after parenthesis of a 'for'
348
     * declaration, enclosed with curly brackets usually.
349
     * 'for' : for (<loop_head>) {<loop_body>}.
350
     *
351
     * @param File $phpcsFile The current file being processed.
352
     * @param int                  $stackPtr  The position of the current token
353
     *                                        in the stack passed in $tokens.
354
     *
355
     * @return int|bool Position of T_FOR if token associated with $stackPtr in
356
     *                  $phpcsFile is in the body of a for loop, otherwise false.
357
     */
358
    private static function _isInForLoopBody(File $phpcsFile, $stackPtr)
359
    {
360
        $isInForLoop = false;
0 ignored issues
show
Unused Code introduced by
$isInForLoop 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
361
        $tokens = $phpcsFile->getTokens();
362
        // get englobing hierarchy
363
        $parentPtrAndCode = $tokens[$stackPtr]['conditions'];
364
        krsort($parentPtrAndCode);
365
366
        // looks for a for loop having a body not enclosed with curly brackets,
367
        // which involves that its body contains only one instruction.
368
        if (is_array($parentPtrAndCode) && ! empty($parentPtrAndCode)) {
369
            $parentCode = reset($parentPtrAndCode);
370
            $parentPtr = key($parentPtrAndCode);
371
            $openBracketPtr = $tokens[$parentPtr]['scope_opener'];
372
        } else {
373
            $parentCode = 0;
374
            $parentPtr = 0;
375
            $openBracketPtr = 0;
376
        }
377
        $openResearchScopePtr = $stackPtr;
378
        // recursive search, since a for statement may englobe other inline
379
        // control statement or may be near to function calls, etc...
380
        while (false !== $openResearchScopePtr) {
381
            $closeParPtr = $phpcsFile->findPrevious(
382
                array(T_CLOSE_PARENTHESIS),
383
                $openResearchScopePtr,
384
                null,
385
                false,
386
                null,
387
                true
388
            );
389
            // is there a closing parenthesis with a control statement before
390
            // the previous instruction ?
391
            if (false !== $closeParPtr) {
392
                // is there no opening curly bracket specific to
393
                // set of instructions, between the closing parenthesis
394
                // and the current token ?
395
                if ($openBracketPtr < $closeParPtr) {
396
                    // starts the search from the token before the closing
397
                    // parenthesis, if it isn't a for statement
398
                    $openResearchScopePtr = $closeParPtr - 1;
399
                    // is this parenthesis associated with a for statement ?
400
                    $closeParenthesisTk = $tokens[$closeParPtr];
401
                    if (array_key_exists('parenthesis_owner', $closeParenthesisTk)) {
402
                        $mayBeForPtr = $closeParenthesisTk['parenthesis_owner'];
403
                        $mayBeForTk = $tokens[$mayBeForPtr];
404
                        if (T_FOR === $mayBeForTk['code']) {
405
                            return $mayBeForPtr;
406
                        }
407
                    }
408
                } else {
409
                    // if it is about a for loop, don't go further
410
                    // and detect it after one more loop execution, do it now
411
                    if (T_FOR === $parentCode) {
412
                        return $parentPtr;
413
                    }
414
                    // starts the search from the token before the one
415
                    // englobing the current statement
416
                    $openResearchScopePtr = $parentPtr - 1;
417
                    // re-initialize variables about the englobing structure
418
                    if (is_array($parentPtrAndCode)) {
419
                        $parentCode = next($parentPtrAndCode);
420
                        $parentPtr = key($parentPtrAndCode);
421
                        $openBracketPtr = $tokens[$parentPtr]['scope_opener'];
422
                    }
423
                }
424
            } else {
425
                $openResearchScopePtr = false;
426
            }
427
        }
428
        // looks for a for loop having a body enclosed with curly brackets
429
        foreach ($parentPtrAndCode as $parentPtr => $parentCode) {
430
            if (T_FOR === $parentCode) {
431
                return $parentPtr;
432
            }
433
        }
434
        return false;
435
    }//end _isInForLoopBody()
436
437
    /**
438
     * Returns true if a variable declared in the head of the for loop pointed
439
     * by $forPtr in file $phpcsFile has the name $varName.
440
     *
441
     * @param File $phpcsFile The current file being processed.
442
     * @param int                  $forPtr    The position of the 'for' token
443
     *                                        in the stack passed in $tokens.
444
     * @param string               $varName   The name of the variable to
445
     *                                        procced without $, { nor }.
446
     *
447
     * @return int|bool true if a variable declared in the head of the for loop
448
     * pointed by $forPtr in file $phpcsFile has the name $varName.
449
     */
450
    private static function _isDeclaredInForLoop(File $phpcsFile, $forPtr, $varName)
451
    {
452
        $isDeclaredInFor = false;
453
        $tokens = $phpcsFile->getTokens();
454
        $forVarPtrs = self::_getVarDeclaredInFor($phpcsFile, $forPtr);
455
        foreach ($forVarPtrs as $forVarPtr) {
456
            $forVarTk = $tokens[$forVarPtr];
457
            // get variable name
458
            $matches = array();
459
            preg_match('/^\$\{?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}?/', $forVarTk['content'], $matches);
460
            $forVarName = $matches[1];
461
            if (0 === strcmp($forVarName, $varName)) {
462
                $isDeclaredInFor = $forVarPtr;
463
                break;
464
            }
465
        }
466
        return $isDeclaredInFor;
467
    }//end _isDeclaredInForLoop()
468
469
    /**
470
     * Returns list of pointers to variables declared in for loop associated to
471
     * $forPtr in file $phpcsFile.
472
     *
473
     * All pointers in the result list are pointing to token with code
474
     * T_VARIABLE. An exception is raised, if $forPtr doesn't point a token with
475
     * code T_FOR.
476
     *
477
     * @param File $phpcsFile The current file being processed.
478
     * @param int                  $forPtr    The position of the current token
479
     *                                        in the stack passed in $tokens.
480
     *
481
     * @return array List of pointers to variables declared in for loop $forPtr.
482
     */
483
    private static function _getVarDeclaredInFor(File $phpcsFile, $forPtr)
484
    {
485
        $tokens = $phpcsFile->getTokens();
486
        $forTk = $tokens[$forPtr];
487
        if (T_FOR !== $forTk['code']) {
488
            throw new PHP_CodeSniffer_Exception('$forPtr must be of type T_FOR');
489
        }
490
        $openParPtr = $forTk['parenthesis_opener'];
491
        $openParenthesisTk = $tokens[$openParPtr];
0 ignored issues
show
Unused Code introduced by
$openParenthesisTk 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
492
        $endOfDeclPtr = $phpcsFile->findNext(array(T_SEMICOLON), $openParPtr);
493
        $forVarPtrs = array();
494
        $varPtr = $phpcsFile->findNext(
495
            array(T_VARIABLE),
496
            $openParPtr + 1,
497
            $endOfDeclPtr
0 ignored issues
show
Security Bug introduced by
It seems like $endOfDeclPtr defined by $phpcsFile->findNext(arr...EMICOLON), $openParPtr) on line 492 can also be of type false; however, PHP_CodeSniffer\Files\File::findNext() does only seem to accept integer|null, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
498
        );
499
        while (false !== $varPtr) {
500
            $forVarPtrs [] = $varPtr;
501
            $varPtr = $phpcsFile->findNext(
502
                array(T_VARIABLE),
503
                $varPtr + 1,
504
                $endOfDeclPtr
0 ignored issues
show
Security Bug introduced by
It seems like $endOfDeclPtr defined by $phpcsFile->findNext(arr...EMICOLON), $openParPtr) on line 492 can also be of type false; however, PHP_CodeSniffer\Files\File::findNext() does only seem to accept integer|null, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
505
            );
506
        }
507
        return $forVarPtrs;
508
    }//end _getVarDeclaredInFor()
509
510
    /**
511
     * Returns the position of first occurrence of a PHP variable starting with
512
     * $ in $haystack from $offset.
513
     *
514
     * @param string $haystack The string to search in.
515
     * @param int    $offset   The optional offset parameter allows you to
516
     *                         specify which character in haystack to start
517
     *                         searching. The returned position is still
518
     *                         relative to the beginning of haystack.
519
     *
520
     * @return mixed The position as an integer
521
     *               or the boolean false, if no variable is found.
522
     */
523
    private static function _getVariablePosition($haystack, $offset = 0)
524
    {
525
        $var_starts_at = strpos($haystack, '$', $offset);
526
        $is_a_var = false;
527
        while (false !== $var_starts_at && ! $is_a_var) {
528
            // makes sure that $ is used for a variable and not as a symbol,
529
            // if $ is protected with the escape char, then it is a symbol.
530
            if (0 !== strcmp($haystack[$var_starts_at - 1], '\\')) {
531
                if (0 === strcmp($haystack[$var_starts_at + 1], '{')) {
532
                    // there is an opening brace in the right place
533
                    // so it looks for the closing brace in the right place
534
                    $hsChunk2 = substr($haystack, $var_starts_at + 2);
535
                    if (1 === preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\}/', $hsChunk2)) {
536
                        $is_a_var = true;
537
                    }
538
                } else {
539
                    $hsChunk1 = substr($haystack, $var_starts_at + 1);
540
                    if (1 === preg_match('/^[a-zA-Z_\x7f-\xff]/', $hsChunk1)) {
541
                        // $ is used for a variable and not as a symbol,
542
                        // since what follows $ matchs the definition of
543
                        // a variable label for PHP.
544
                        $is_a_var = true;
545
                    }
546
                }
547
            }
548
            // update $var_starts_at for the next variable
549
            // only if no variable was found, since it is returned otherwise.
550
            if ( ! $is_a_var) {
551
                $var_starts_at = strpos($haystack, '$', $var_starts_at + 1);
552
            }
553
        }
554
        if ($is_a_var) {
555
            return $var_starts_at;
556
        } else {
557
            return false;
558
        }
559
    }//end _getVariablePosition()
560
}//end class
561
562
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
Coding Style introduced by
As per coding style, files should not end with a newline character.

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
563