Completed
Pull Request — master (#9)
by Tomáš
16:51 queued 12:18
created

PHP   D

Complexity

Total Complexity 261

Size/Duplication

Total Lines 1720
Duplicated Lines 15.76 %

Coupling/Cohesion

Components 2
Dependencies 4

Importance

Changes 0
Metric Value
dl 271
loc 1720
rs 4.4102
c 0
b 0
f 0
wmc 261
lcom 2
cbo 4

4 Methods

Rating   Name   Duplication   Size   Complexity  
C standardiseToken() 18 68 15
D resolveSimpleToken() 0 95 27
F tokenize() 114 680 129
F processAdditional() 139 403 90

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PHP often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PHP, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Tokenizes PHP code.
4
 *
5
 * @author    Greg Sherwood <[email protected]>
6
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
7
 * @license   https://github.com/squizlabs/Symplify\PHP7_CodeSniffer/blob/master/licence.txt BSD Licence
8
 */
9
10
namespace Symplify\PHP7_CodeSniffer\Tokenizers;
11
12
use Symplify\PHP7_CodeSniffer\Util;
13
14
class PHP extends Tokenizer
15
{
16
17
18
    /**
19
     * A list of tokens that are allowed to open a scope.
20
     *
21
     * This array also contains information about what kind of token the scope
22
     * opener uses to open and close the scope, if the token strictly requires
23
     * an opener, if the token can share a scope closer, and who it can be shared
24
     * with. An example of a token that shares a scope closer is a CASE scope.
25
     *
26
     * @var array
27
     */
28
    public $scopeOpeners = array(
29
                            T_IF            => array(
30
                                                'start'  => array(
31
                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
32
                                                             T_COLON              => T_COLON,
33
                                                            ),
34
                                                'end'    => array(
35
                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
36
                                                             T_ENDIF               => T_ENDIF,
37
                                                             T_ELSE                => T_ELSE,
38
                                                             T_ELSEIF              => T_ELSEIF,
39
                                                            ),
40
                                                'strict' => false,
41
                                                'shared' => false,
42
                                                'with'   => array(
43
                                                             T_ELSE   => T_ELSE,
44
                                                             T_ELSEIF => T_ELSEIF,
45
                                                            ),
46
                                               ),
47
                            T_TRY           => array(
48
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
49
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
50
                                                'strict' => true,
51
                                                'shared' => false,
52
                                                'with'   => array(),
53
                                               ),
54
                            T_CATCH         => array(
55
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
56
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
57
                                                'strict' => true,
58
                                                'shared' => false,
59
                                                'with'   => array(),
60
                                               ),
61
                            T_FINALLY       => array(
62
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
63
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
64
                                                'strict' => true,
65
                                                'shared' => false,
66
                                                'with'   => array(),
67
                                               ),
68
                            T_ELSE          => array(
69
                                                'start'  => array(
70
                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
71
                                                             T_COLON              => T_COLON,
72
                                                            ),
73
                                                'end'    => array(
74
                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
75
                                                             T_ENDIF               => T_ENDIF,
76
                                                            ),
77
                                                'strict' => false,
78
                                                'shared' => false,
79
                                                'with'   => array(
80
                                                             T_IF     => T_IF,
81
                                                             T_ELSEIF => T_ELSEIF,
82
                                                            ),
83
                                               ),
84
                            T_ELSEIF        => array(
85
                                                'start'  => array(
86
                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
87
                                                             T_COLON              => T_COLON,
88
                                                            ),
89
                                                'end'    => array(
90
                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
91
                                                             T_ENDIF               => T_ENDIF,
92
                                                             T_ELSE                => T_ELSE,
93
                                                             T_ELSEIF              => T_ELSEIF,
94
                                                            ),
95
                                                'strict' => false,
96
                                                'shared' => false,
97
                                                'with'   => array(
98
                                                             T_IF   => T_IF,
99
                                                             T_ELSE => T_ELSE,
100
                                                            ),
101
                                               ),
102
                            T_FOR           => array(
103
                                                'start'  => array(
104
                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
105
                                                             T_COLON              => T_COLON,
106
                                                            ),
107
                                                'end'    => array(
108
                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
109
                                                             T_ENDFOR              => T_ENDFOR,
110
                                                            ),
111
                                                'strict' => false,
112
                                                'shared' => false,
113
                                                'with'   => array(),
114
                                               ),
115
                            T_FOREACH       => array(
116
                                                'start'  => array(
117
                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
118
                                                             T_COLON              => T_COLON,
119
                                                            ),
120
                                                'end'    => array(
121
                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
122
                                                             T_ENDFOREACH          => T_ENDFOREACH,
123
                                                            ),
124
                                                'strict' => false,
125
                                                'shared' => false,
126
                                                'with'   => array(),
127
                                               ),
128
                            T_INTERFACE     => array(
129
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
130
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
131
                                                'strict' => true,
132
                                                'shared' => false,
133
                                                'with'   => array(),
134
                                               ),
135
                            T_FUNCTION      => array(
136
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
137
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
138
                                                'strict' => true,
139
                                                'shared' => false,
140
                                                'with'   => array(),
141
                                               ),
142
                            T_CLASS         => array(
143
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
144
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
145
                                                'strict' => true,
146
                                                'shared' => false,
147
                                                'with'   => array(),
148
                                               ),
149
                            T_TRAIT         => array(
150
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
151
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
152
                                                'strict' => true,
153
                                                'shared' => false,
154
                                                'with'   => array(),
155
                                               ),
156
                            T_USE           => array(
157
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
158
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
159
                                                'strict' => false,
160
                                                'shared' => false,
161
                                                'with'   => array(),
162
                                               ),
163
                            T_DECLARE       => array(
164
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
165
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
166
                                                'strict' => false,
167
                                                'shared' => false,
168
                                                'with'   => array(),
169
                                               ),
170
                            T_NAMESPACE     => array(
171
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
172
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
173
                                                'strict' => false,
174
                                                'shared' => false,
175
                                                'with'   => array(),
176
                                               ),
177
                            T_WHILE         => array(
178
                                                'start'  => array(
179
                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
180
                                                             T_COLON              => T_COLON,
181
                                                            ),
182
                                                'end'    => array(
183
                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
184
                                                             T_ENDWHILE            => T_ENDWHILE,
185
                                                            ),
186
                                                'strict' => false,
187
                                                'shared' => false,
188
                                                'with'   => array(),
189
                                               ),
190
                            T_DO            => array(
191
                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
192
                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
193
                                                'strict' => true,
194
                                                'shared' => false,
195
                                                'with'   => array(),
196
                                               ),
197
                            T_SWITCH        => array(
198
                                                'start'  => array(
199
                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
200
                                                             T_COLON              => T_COLON,
201
                                                            ),
202
                                                'end'    => array(
203
                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
204
                                                             T_ENDSWITCH           => T_ENDSWITCH,
205
                                                            ),
206
                                                'strict' => true,
207
                                                'shared' => false,
208
                                                'with'   => array(),
209
                                               ),
210
                            T_CASE          => array(
211
                                                'start'  => array(
212
                                                             T_COLON     => T_COLON,
213
                                                             T_SEMICOLON => T_SEMICOLON,
214
                                                            ),
215
                                                'end'    => array(
216
                                                             T_BREAK    => T_BREAK,
217
                                                             T_RETURN   => T_RETURN,
218
                                                             T_CONTINUE => T_CONTINUE,
219
                                                             T_THROW    => T_THROW,
220
                                                             T_EXIT     => T_EXIT,
221
                                                            ),
222
                                                'strict' => true,
223
                                                'shared' => true,
224
                                                'with'   => array(
225
                                                             T_DEFAULT => T_DEFAULT,
226
                                                             T_CASE    => T_CASE,
227
                                                             T_SWITCH  => T_SWITCH,
228
                                                            ),
229
                                               ),
230
                            T_DEFAULT       => array(
231
                                                'start'  => array(
232
                                                             T_COLON     => T_COLON,
233
                                                             T_SEMICOLON => T_SEMICOLON,
234
                                                            ),
235
                                                'end'    => array(
236
                                                             T_BREAK    => T_BREAK,
237
                                                             T_RETURN   => T_RETURN,
238
                                                             T_CONTINUE => T_CONTINUE,
239
                                                             T_THROW    => T_THROW,
240
                                                             T_EXIT     => T_EXIT,
241
                                                            ),
242
                                                'strict' => true,
243
                                                'shared' => true,
244
                                                'with'   => array(
245
                                                             T_CASE   => T_CASE,
246
                                                             T_SWITCH => T_SWITCH,
247
                                                            ),
248
                                               ),
249
                            T_START_HEREDOC => array(
250
                                                'start'  => array(T_START_HEREDOC => T_START_HEREDOC),
251
                                                'end'    => array(T_END_HEREDOC => T_END_HEREDOC),
252
                                                'strict' => true,
253
                                                'shared' => false,
254
                                                'with'   => array(),
255
                                               ),
256
                           );
257
258
    /**
259
     * A list of tokens that end the scope.
260
     *
261
     * This array is just a unique collection of the end tokens
262
     * from the _scopeOpeners array. The data is duplicated here to
263
     * save time during parsing of the file.
264
     *
265
     * @var array
266
     */
267
    public $endScopeTokens = array(
268
                              T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
269
                              T_ENDIF               => T_ENDIF,
270
                              T_ENDFOR              => T_ENDFOR,
271
                              T_ENDFOREACH          => T_ENDFOREACH,
272
                              T_ENDWHILE            => T_ENDWHILE,
273
                              T_ENDSWITCH           => T_ENDSWITCH,
274
                              T_BREAK               => T_BREAK,
275
                              T_END_HEREDOC         => T_END_HEREDOC,
276
                             );
277
278
    /**
279
     * Known lengths of tokens.
280
     *
281
     * @var array<int, int>
282
     */
283
    public $knownLengths = array(
284
                            T_ABSTRACT                 => 8,
285
                            T_AND_EQUAL                => 2,
286
                            T_ARRAY                    => 5,
287
                            T_AS                       => 2,
288
                            T_BOOLEAN_AND              => 2,
289
                            T_BOOLEAN_OR               => 2,
290
                            T_BREAK                    => 5,
291
                            T_CALLABLE                 => 8,
292
                            T_CASE                     => 4,
293
                            T_CATCH                    => 5,
294
                            T_CLASS                    => 5,
295
                            T_CLASS_C                  => 9,
296
                            T_CLONE                    => 5,
297
                            T_CONCAT_EQUAL             => 2,
298
                            T_CONST                    => 5,
299
                            T_CONTINUE                 => 8,
300
                            T_CURLY_OPEN               => 2,
301
                            T_DEC                      => 2,
302
                            T_DECLARE                  => 7,
303
                            T_DEFAULT                  => 7,
304
                            T_DIR                      => 7,
305
                            T_DIV_EQUAL                => 2,
306
                            T_DO                       => 2,
307
                            T_DOLLAR_OPEN_CURLY_BRACES => 2,
308
                            T_DOUBLE_ARROW             => 2,
309
                            T_DOUBLE_COLON             => 2,
310
                            T_ECHO                     => 4,
311
                            T_ELSE                     => 4,
312
                            T_ELSEIF                   => 6,
313
                            T_EMPTY                    => 5,
314
                            T_ENDDECLARE               => 10,
315
                            T_ENDFOR                   => 6,
316
                            T_ENDFOREACH               => 10,
317
                            T_ENDIF                    => 5,
318
                            T_ENDSWITCH                => 9,
319
                            T_ENDWHILE                 => 8,
320
                            T_EVAL                     => 4,
321
                            T_EXTENDS                  => 7,
322
                            T_FILE                     => 8,
323
                            T_FINAL                    => 5,
324
                            T_FINALLY                  => 7,
325
                            T_FOR                      => 3,
326
                            T_FOREACH                  => 7,
327
                            T_FUNCTION                 => 8,
328
                            T_FUNC_C                   => 12,
329
                            T_GLOBAL                   => 6,
330
                            T_GOTO                     => 4,
331
                            T_HALT_COMPILER            => 15,
332
                            T_IF                       => 2,
333
                            T_IMPLEMENTS               => 10,
334
                            T_INC                      => 2,
335
                            T_INCLUDE                  => 7,
336
                            T_INCLUDE_ONCE             => 12,
337
                            T_INSTANCEOF               => 10,
338
                            T_INSTEADOF                => 9,
339
                            T_INTERFACE                => 9,
340
                            T_ISSET                    => 5,
341
                            T_IS_EQUAL                 => 2,
342
                            T_IS_GREATER_OR_EQUAL      => 2,
343
                            T_IS_IDENTICAL             => 3,
344
                            T_IS_NOT_EQUAL             => 2,
345
                            T_IS_NOT_IDENTICAL         => 3,
346
                            T_IS_SMALLER_OR_EQUAL      => 2,
347
                            T_LINE                     => 8,
348
                            T_LIST                     => 4,
349
                            T_LOGICAL_AND              => 3,
350
                            T_LOGICAL_OR               => 2,
351
                            T_LOGICAL_XOR              => 3,
352
                            T_METHOD_C                 => 10,
353
                            T_MINUS_EQUAL              => 2,
354
                            T_POW_EQUAL                => 3,
355
                            T_MOD_EQUAL                => 2,
356
                            T_MUL_EQUAL                => 2,
357
                            T_NAMESPACE                => 9,
358
                            T_NS_C                     => 13,
359
                            T_NS_SEPARATOR             => 1,
360
                            T_NEW                      => 3,
361
                            T_OBJECT_OPERATOR          => 2,
362
                            T_OPEN_TAG_WITH_ECHO       => 3,
363
                            T_OR_EQUAL                 => 2,
364
                            T_PLUS_EQUAL               => 2,
365
                            T_PRINT                    => 5,
366
                            T_PRIVATE                  => 7,
367
                            T_PUBLIC                   => 6,
368
                            T_PROTECTED                => 9,
369
                            T_REQUIRE                  => 7,
370
                            T_REQUIRE_ONCE             => 12,
371
                            T_RETURN                   => 6,
372
                            T_STATIC                   => 6,
373
                            T_SWITCH                   => 6,
374
                            T_THROW                    => 5,
375
                            T_TRAIT                    => 5,
376
                            T_TRAIT_C                  => 9,
377
                            T_TRY                      => 3,
378
                            T_UNSET                    => 5,
379
                            T_USE                      => 3,
380
                            T_VAR                      => 3,
381
                            T_WHILE                    => 5,
382
                            T_XOR_EQUAL                => 2,
383
                            T_YIELD                    => 5,
384
                            T_OPEN_CURLY_BRACKET       => 1,
385
                            T_CLOSE_CURLY_BRACKET      => 1,
386
                            T_OPEN_SQUARE_BRACKET      => 1,
387
                            T_CLOSE_SQUARE_BRACKET     => 1,
388
                            T_OPEN_PARENTHESIS         => 1,
389
                            T_CLOSE_PARENTHESIS        => 1,
390
                            T_COLON                    => 1,
391
                            T_STRING_CONCAT            => 1,
392
                            T_INLINE_THEN              => 1,
393
                            T_INLINE_ELSE              => 1,
394
                            T_NULL                     => 4,
395
                            T_FALSE                    => 5,
396
                            T_TRUE                     => 4,
397
                            T_SEMICOLON                => 1,
398
                            T_EQUAL                    => 1,
399
                            T_MULTIPLY                 => 1,
400
                            T_DIVIDE                   => 1,
401
                            T_PLUS                     => 1,
402
                            T_MINUS                    => 1,
403
                            T_MODULUS                  => 1,
404
                            T_POW                      => 2,
405
                            T_SPACESHIP                => 3,
406
                            T_COALESCE                 => 2,
407
                            T_BITWISE_AND              => 1,
408
                            T_BITWISE_OR               => 1,
409
                            T_BITWISE_XOR              => 1,
410
                            T_SL                       => 2,
411
                            T_SR                       => 2,
412
                            T_SL_EQUAL                 => 3,
413
                            T_SR_EQUAL                 => 3,
414
                            T_ARRAY_HINT               => 5,
415
                            T_GREATER_THAN             => 1,
416
                            T_LESS_THAN                => 1,
417
                            T_BOOLEAN_NOT              => 1,
418
                            T_SELF                     => 4,
419
                            T_PARENT                   => 6,
420
                            T_COMMA                    => 1,
421
                            T_THIS                     => 4,
422
                            T_CLOSURE                  => 8,
423
                            T_BACKTICK                 => 1,
424
                            T_OPEN_SHORT_ARRAY         => 1,
425
                            T_CLOSE_SHORT_ARRAY        => 1,
426
                           );
427
428
429
    /**
430
     * A cache of different token types, resolved into arrays.
431
     *
432
     * @var array
433
     * @see standardiseToken()
434
     */
435
    private static $_resolveTokenCache = array();
436
437
438
    /**
439
     * Creates an array of tokens when given some PHP code.
440
     *
441
     * Starts by using token_get_all() but does a lot of extra processing
442
     * to insert information about the context of the token.
443
     *
444
     * @param string $string The string to tokenize.
445
     *
446
     * @return array
447
     */
448
    protected function tokenize($string)
449
    {
450
        if (PHP_CodeSniffer_VERBOSITY > 1) {
451
            echo "\t*** START PHP TOKENIZING ***".PHP_EOL;
452
            $isWin = false;
453
            if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
454
                $isWin = true;
455
            }
456
        }
457
458
        $tokens      = @token_get_all($string);
459
        $finalTokens = array();
460
461
        $newStackPtr       = 0;
462
        $numTokens         = count($tokens);
463
        $lastNotEmptyToken = 0;
464
465
        $insideInlineIf = array();
466
        $insideUseGroup = false;
467
468
        $commentTokenizer = new Comment();
469
470
        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
471
            $token        = (array) $tokens[$stackPtr];
472
            $tokenIsArray = isset($token[1]);
473
474
            if (PHP_CodeSniffer_VERBOSITY > 1) {
475
                if ($tokenIsArray === true) {
476
                    $type    = token_name($token[0]);
477
                    $content = Util\Common::prepareForOutput($token[1]);
478
                } else {
479
                    $newToken = self::resolveSimpleToken($token[0]);
480
                    $type     = $newToken['type'];
481
                    $content  = Util\Common::prepareForOutput($token[0]);
482
                }
483
484
                echo "\tProcess token ";
485
                if ($tokenIsArray === true) {
486
                    echo "[$stackPtr]";
487
                } else {
488
                    echo " $stackPtr ";
489
                }
490
491
                echo ": $type => $content";
492
            }//end if
493
494
            if ($newStackPtr > 0 && $finalTokens[($newStackPtr - 1)]['code'] !== T_WHITESPACE) {
495
                $lastNotEmptyToken = ($newStackPtr - 1);
496
            }
497
498
            /*
499
                If we are using \r\n newline characters, the \r and \n are sometimes
500
                split over two tokens. This normally occurs after comments. We need
501
                to merge these two characters together so that our line endings are
502
                consistent for all lines.
503
            */
504
505
            if ($tokenIsArray === true && substr($token[1], -1) === "\r") {
506
                if (isset($tokens[($stackPtr + 1)]) === true
507
                    && is_array($tokens[($stackPtr + 1)]) === true
508
                    && $tokens[($stackPtr + 1)][1][0] === "\n"
509
                ) {
510
                    $token[1] .= "\n";
511
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
512
                        if ($isWin === true) {
0 ignored issues
show
Bug introduced by
The variable $isWin 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

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
513
                            echo '\n';
514
                        } else {
515
                            echo "\033[30;1m\\n\033[0m";
516
                        }
517
                    }
518
519
                    if ($tokens[($stackPtr + 1)][1] === "\n") {
520
                        // This token's content has been merged into the previous,
521
                        // so we can skip it.
522
                        $tokens[($stackPtr + 1)] = '';
523
                    } else {
524
                        $tokens[($stackPtr + 1)][1] = substr($tokens[($stackPtr + 1)][1], 1);
525
                    }
526
                }
527
            }//end if
528
529
            if (PHP_CodeSniffer_VERBOSITY > 1) {
530
                echo PHP_EOL;
531
            }
532
533
            /*
534
                Parse doc blocks into something that can be easily iterated over.
535
            */
536
537
            if ($tokenIsArray === true && $token[0] === T_DOC_COMMENT) {
538
                $commentTokens = $commentTokenizer->tokenizeString($token[1], $this->eolChar, $newStackPtr);
539
                foreach ($commentTokens as $commentToken) {
540
                    $finalTokens[$newStackPtr] = $commentToken;
541
                    $newStackPtr++;
542
                }
543
544
                continue;
545
            }
546
547
            /*
548
                If this is a double quoted string, PHP will tokenize the whole
549
                thing which causes problems with the scope map when braces are
550
                within the string. So we need to merge the tokens together to
551
                provide a single string.
552
            */
553
554
            if ($tokenIsArray === false && ($token[0] === '"' || $token[0] === 'b"')) {
555
                // Binary casts need a special token.
556 View Code Duplication
                if ($token[0] === 'b"') {
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...
557
                    $finalTokens[$newStackPtr] = array(
558
                                                  'code'    => T_BINARY_CAST,
559
                                                  'type'    => 'T_BINARY_CAST',
560
                                                  'content' => 'b',
561
                                                 );
562
                    $newStackPtr++;
563
                }
564
565
                $tokenContent = '"';
566
                $nestedVars   = array();
567
                for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
568
                    $subToken        = (array) $tokens[$i];
569
                    $subTokenIsArray = isset($subToken[1]);
570
571
                    if ($subTokenIsArray === true) {
572
                        $tokenContent .= $subToken[1];
573
                        if ($subToken[1] === '{'
574
                            && $subToken[0] !== T_ENCAPSED_AND_WHITESPACE
575
                        ) {
576
                            $nestedVars[] = $i;
577
                        }
578
                    } else {
579
                        $tokenContent .= $subToken[0];
580
                        if ($subToken[0] === '}') {
581
                            array_pop($nestedVars);
582
                        }
583
                    }
584
585
                    if ($subTokenIsArray === false
586
                        && $subToken[0] === '"'
587
                        && empty($nestedVars) === true
588
                    ) {
589
                        // We found the other end of the double quoted string.
590
                        break;
591
                    }
592
                }//end for
593
594
                $stackPtr = $i;
595
596
                // Convert each line within the double quoted string to a
597
                // new token, so it conforms with other multiple line tokens.
598
                $tokenLines = explode($this->eolChar, $tokenContent);
599
                $numLines   = count($tokenLines);
600
                $newToken   = array();
601
602
                for ($j = 0; $j < $numLines; $j++) {
603
                    $newToken['content'] = $tokenLines[$j];
604 View Code Duplication
                    if ($j === ($numLines - 1)) {
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...
605
                        if ($tokenLines[$j] === '') {
606
                            break;
607
                        }
608
                    } else {
609
                        $newToken['content'] .= $this->eolChar;
610
                    }
611
612
                    $newToken['code']          = T_DOUBLE_QUOTED_STRING;
613
                    $newToken['type']          = 'T_DOUBLE_QUOTED_STRING';
614
                    $finalTokens[$newStackPtr] = $newToken;
615
                    $newStackPtr++;
616
                }
617
618
                // Continue, as we're done with this token.
619
                continue;
620
            }//end if
621
622
            /*
623
                If this is a heredoc, PHP will tokenize the whole
624
                thing which causes problems when heredocs don't
625
                contain real PHP code, which is almost never.
626
                We want to leave the start and end heredoc tokens
627
                alone though.
628
            */
629
630
            if ($tokenIsArray === true && $token[0] === T_START_HEREDOC) {
631
                // Add the start heredoc token to the final array.
632
                $finalTokens[$newStackPtr] = self::standardiseToken($token);
633
634
                // Check if this is actually a nowdoc and use a different token
635
                // to help the sniffs.
636
                $nowdoc = false;
637
                if ($token[1][3] === "'") {
638
                    $finalTokens[$newStackPtr]['code'] = T_START_NOWDOC;
639
                    $finalTokens[$newStackPtr]['type'] = 'T_START_NOWDOC';
640
                    $nowdoc = true;
641
                }
642
643
                $tokenContent = '';
644
                for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
645
                    $subTokenIsArray = is_array($tokens[$i]);
646
                    if ($subTokenIsArray === true
647
                        && $tokens[$i][0] === T_END_HEREDOC
648
                    ) {
649
                        // We found the other end of the heredoc.
650
                        break;
651
                    }
652
653
                    if ($subTokenIsArray === true) {
654
                        $tokenContent .= $tokens[$i][1];
655
                    } else {
656
                        $tokenContent .= $tokens[$i];
657
                    }
658
                }
659
660
                if ($i === $numTokens) {
661
                    // We got to the end of the file and never
662
                    // found the closing token, so this probably wasn't
663
                    // a heredoc.
664
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
665
                        $type = $finalTokens[$newStackPtr]['type'];
666
                        echo "\t\t* failed to find the end of the here/nowdoc".PHP_EOL;
667
                        echo "\t\t* token $stackPtr changed from $type to T_STRING".PHP_EOL;
668
                    }
669
670
                    $finalTokens[$newStackPtr]['code'] = T_STRING;
671
                    $finalTokens[$newStackPtr]['type'] = 'T_STRING';
672
                    $newStackPtr++;
673
                    continue;
674
                }
675
676
                $stackPtr = $i;
677
                $newStackPtr++;
678
679
                // Convert each line within the heredoc to a
680
                // new token, so it conforms with other multiple line tokens.
681
                $tokenLines = explode($this->eolChar, $tokenContent);
682
                $numLines   = count($tokenLines);
683
                $newToken   = array();
684
685
                for ($j = 0; $j < $numLines; $j++) {
686
                    $newToken['content'] = $tokenLines[$j];
687 View Code Duplication
                    if ($j === ($numLines - 1)) {
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...
688
                        if ($tokenLines[$j] === '') {
689
                            break;
690
                        }
691
                    } else {
692
                        $newToken['content'] .= $this->eolChar;
693
                    }
694
695
                    if ($nowdoc === true) {
696
                        $newToken['code'] = T_NOWDOC;
697
                        $newToken['type'] = 'T_NOWDOC';
698
                    } else {
699
                        $newToken['code'] = T_HEREDOC;
700
                        $newToken['type'] = 'T_HEREDOC';
701
                    }
702
703
                    $finalTokens[$newStackPtr] = $newToken;
704
                    $newStackPtr++;
705
                }//end for
706
707
                // Add the end heredoc token to the final array.
708
                $finalTokens[$newStackPtr] = self::standardiseToken($tokens[$stackPtr]);
709
710
                if ($nowdoc === true) {
711
                    $finalTokens[$newStackPtr]['code'] = T_END_NOWDOC;
712
                    $finalTokens[$newStackPtr]['type'] = 'T_END_NOWDOC';
713
                    $nowdoc = true;
0 ignored issues
show
Unused Code introduced by
$nowdoc 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...
714
                }
715
716
                $newStackPtr++;
717
718
                // Continue, as we're done with this token.
719
                continue;
720
            }//end if
721
722
            /*
723
                Before PHP 5.6, the ... operator was tokenized as three
724
                T_STRING_CONCAT tokens in a row. So look for and combine
725
                these tokens in earlier versions.
726
            */
727
728
            if ($tokenIsArray === false
729
                && $token[0] === '.'
730
                && isset($tokens[($stackPtr + 1)]) === true
731
                && isset($tokens[($stackPtr + 2)]) === true
732
                && $tokens[($stackPtr + 1)] === '.'
733
                && $tokens[($stackPtr + 2)] === '.'
734
            ) {
735
                $newToken            = array();
736
                $newToken['code']    = T_ELLIPSIS;
737
                $newToken['type']    = 'T_ELLIPSIS';
738
                $newToken['content'] = '...';
739
                $finalTokens[$newStackPtr] = $newToken;
740
741
                $newStackPtr++;
742
                $stackPtr += 2;
743
                continue;
744
            }
745
746
            /*
747
                Before PHP 5.6, the ** operator was tokenized as two
748
                T_MULTIPLY tokens in a row. So look for and combine
749
                these tokens in earlier versions.
750
            */
751
752 View Code Duplication
            if ($tokenIsArray === false
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...
753
                && $token[0] === '*'
754
                && isset($tokens[($stackPtr + 1)]) === true
755
                && $tokens[($stackPtr + 1)] === '*'
756
            ) {
757
                $newToken            = array();
758
                $newToken['code']    = T_POW;
759
                $newToken['type']    = 'T_POW';
760
                $newToken['content'] = '**';
761
                $finalTokens[$newStackPtr] = $newToken;
762
763
                $newStackPtr++;
764
                $stackPtr++;
765
                continue;
766
            }
767
768
            /*
769
                Before PHP 5.6, the **= operator was tokenized as
770
                T_MULTIPLY followed by T_MUL_EQUAL. So look for and combine
771
                these tokens in earlier versions.
772
            */
773
774
            if ($tokenIsArray === false
775
                && $token[0] === '*'
776
                && isset($tokens[($stackPtr + 1)]) === true
777
                && is_array($tokens[($stackPtr + 1)]) === true
778
                && $tokens[($stackPtr + 1)][1] === '*='
779
            ) {
780
                $newToken            = array();
781
                $newToken['code']    = T_POW_EQUAL;
782
                $newToken['type']    = 'T_POW_EQUAL';
783
                $newToken['content'] = '**=';
784
                $finalTokens[$newStackPtr] = $newToken;
785
786
                $newStackPtr++;
787
                $stackPtr++;
788
                continue;
789
            }
790
791
            /*
792
                Before PHP 7, the ?? operator was tokenized as
793
                T_INLINE_THEN followed by T_INLINE_THEN.
794
                So look for and combine these tokens in earlier versions.
795
            */
796
797 View Code Duplication
            if ($tokenIsArray === false
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...
798
                && $token[0] === '?'
799
                && isset($tokens[($stackPtr + 1)]) === true
800
                && $tokens[($stackPtr + 1)][0] === '?'
801
            ) {
802
                $newToken            = array();
803
                $newToken['code']    = T_COALESCE;
804
                $newToken['type']    = 'T_COALESCE';
805
                $newToken['content'] = '??';
806
                $finalTokens[$newStackPtr] = $newToken;
807
808
                $newStackPtr++;
809
                $stackPtr++;
810
                continue;
811
            }
812
813
            /*
814
                Before PHP 7, the <=> operator was tokenized as
815
                T_IS_SMALLER_OR_EQUAL followed by T_GREATER_THAN.
816
                So look for and combine these tokens in earlier versions.
817
            */
818
819 View Code Duplication
            if ($tokenIsArray === true
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...
820
                && $token[0] === T_IS_SMALLER_OR_EQUAL
821
                && isset($tokens[($stackPtr + 1)]) === true
822
                && $tokens[($stackPtr + 1)][0] === '>'
823
            ) {
824
                $newToken            = array();
825
                $newToken['code']    = T_SPACESHIP;
826
                $newToken['type']    = 'T_SPACESHIP';
827
                $newToken['content'] = '<=>';
828
                $finalTokens[$newStackPtr] = $newToken;
829
830
                $newStackPtr++;
831
                $stackPtr++;
832
                continue;
833
            }
834
835
            /*
836
                Emulate traits in PHP versions less than 5.4.
837
            */
838
839
            if ($tokenIsArray === true
840
                && $token[0] === T_STRING
841
                && strtolower($token[1]) === 'trait'
842
                && $tokens[($stackPtr - 1)][0] !== T_OBJECT_OPERATOR
843
            ) {
844
                $finalTokens[$newStackPtr] = array(
845
                                              'content' => $token[1],
846
                                              'code'    => T_TRAIT,
847
                                              'type'    => 'T_TRAIT',
848
                                             );
849
850
                if (PHP_CodeSniffer_VERBOSITY > 1) {
851
                    echo "\t\t* token $stackPtr changed from T_STRING to T_TRAIT".PHP_EOL;
852
                }
853
854
                $newStackPtr++;
855
                continue;
856
            }
857
858
            /*
859
                PHP doesn't assign a token to goto labels, so we have to.
860
                These are just string tokens with a single colon after them. Double
861
                colons are already tokenized and so don't interfere with this check.
862
                But we do have to account for CASE statements, that look just like
863
                goto labels.
864
            */
865
866
            if ($tokenIsArray === true
867
                && $token[0] === T_STRING
868
                && isset($tokens[($stackPtr + 1)]) === true
869
                && $tokens[($stackPtr + 1)] === ':'
870
                && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM
871
            ) {
872
                $stopTokens = array(
873
                               T_CASE               => true,
874
                               T_SEMICOLON          => true,
875
                               T_OPEN_CURLY_BRACKET => true,
876
                               T_INLINE_THEN        => true,
877
                              );
878
879
                for ($x = ($newStackPtr - 1); $x > 0; $x--) {
880
                    if (isset($stopTokens[$finalTokens[$x]['code']]) === true) {
881
                        break;
882
                    }
883
                }
884
885
                if ($finalTokens[$x]['code'] !== T_CASE
886
                    && $finalTokens[$x]['code'] !== T_INLINE_THEN
887
                ) {
888
                    $finalTokens[$newStackPtr] = array(
889
                                                  'content' => $token[1].':',
890
                                                  'code'    => T_GOTO_LABEL,
891
                                                  'type'    => 'T_GOTO_LABEL',
892
                                                 );
893
894
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
895
                        echo "\t\t* token $stackPtr changed from T_STRING to T_GOTO_LABEL".PHP_EOL;
896
                        echo "\t\t* skipping T_COLON token ".($stackPtr + 1).PHP_EOL;
897
                    }
898
899
                    $newStackPtr++;
900
                    $stackPtr++;
901
                    continue;
902
                }
903
            }//end if
904
905
            /*
906
                HHVM 3.5 tokenizes "else[\s]+if" as a T_ELSEIF token while PHP
907
                proper only tokenizes "elseif" as a T_ELSEIF token. So split
908
                up the HHVM token to make it looks like proper PHP.
909
            */
910
911
            if ($tokenIsArray === true
912
                && $token[0] === T_ELSEIF
913
                && strtolower($token[1]) !== 'elseif'
914
            ) {
915
                $finalTokens[$newStackPtr] = array(
916
                                              'content' => substr($token[1], 0, 4),
917
                                              'code'    => T_ELSE,
918
                                              'type'    => 'T_ELSE',
919
                                             );
920
921
                $newStackPtr++;
922
                $finalTokens[$newStackPtr] = array(
923
                                              'content' => substr($token[1], 4, -2),
924
                                              'code'    => T_WHITESPACE,
925
                                              'type'    => 'T_WHITESPACE',
926
                                             );
927
928
                $newStackPtr++;
929
                $finalTokens[$newStackPtr] = array(
930
                                              'content' => substr($token[1], -2),
931
                                              'code'    => T_IF,
932
                                              'type'    => 'T_IF',
933
                                             );
934
935
                if (PHP_CodeSniffer_VERBOSITY > 1) {
936
                    echo "\t\t* token $stackPtr changed from T_ELSEIF to T_ELSE/T_WHITESPACE/T_IF".PHP_EOL;
937
                }
938
939
                $newStackPtr++;
940
                continue;
941
            }//end if
942
943
            /*
944
                HHVM 3.5 and 3.6 tokenizes a hashbang line such as #!/usr/bin/php
945
                as T_HASHANG while PHP proper uses T_INLINE_HTML.
946
            */
947
948
            if ($tokenIsArray === true && token_name($token[0]) === 'T_HASHBANG') {
949
                $finalTokens[$newStackPtr] = array(
950
                                              'content' => $token[1],
951
                                              'code'    => T_INLINE_HTML,
952
                                              'type'    => 'T_INLINE_HTML',
953
                                             );
954
955
                if (PHP_CodeSniffer_VERBOSITY > 1) {
956
                    echo "\t\t* token $stackPtr changed from T_HASHBANG to T_INLINE_HTML".PHP_EOL;
957
                }
958
959
                $newStackPtr++;
960
                continue;
961
            }//end if
962
963
            /*
964
                If this token has newlines in its content, split each line up
965
                and create a new token for each line. We do this so it's easier
966
                to ascertain where errors occur on a line.
967
                Note that $token[1] is the token's content.
968
            */
969
970
            if ($tokenIsArray === true && strpos($token[1], $this->eolChar) !== false) {
971
                $tokenLines = explode($this->eolChar, $token[1]);
972
                $numLines   = count($tokenLines);
973
                $newToken   = array(
974
                               'type'    => token_name($token[0]),
975
                               'code'    => $token[0],
976
                               'content' => '',
977
                              );
978
979
                for ($i = 0; $i < $numLines; $i++) {
980
                    $newToken['content'] = $tokenLines[$i];
981 View Code Duplication
                    if ($i === ($numLines - 1)) {
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...
982
                        if ($tokenLines[$i] === '') {
983
                            break;
984
                        }
985
                    } else {
986
                        $newToken['content'] .= $this->eolChar;
987
                    }
988
989
                    $finalTokens[$newStackPtr] = $newToken;
990
                    $newStackPtr++;
991
                }
992
            } else {
993
                if ($tokenIsArray === true && $token[0] === T_STRING) {
994
                    // Some T_STRING tokens should remain that way
995
                    // due to their context.
996
                    $context = array(
997
                                T_OBJECT_OPERATOR      => true,
998
                                T_FUNCTION             => true,
999
                                T_CLASS                => true,
1000
                                T_EXTENDS              => true,
1001
                                T_IMPLEMENTS           => true,
1002
                                T_NEW                  => true,
1003
                                T_CONST                => true,
1004
                                T_NS_SEPARATOR         => true,
1005
                                T_USE                  => true,
1006
                                T_NAMESPACE            => true,
1007
                                T_PAAMAYIM_NEKUDOTAYIM => true,
1008
                               );
1009 View Code Duplication
                    if (isset($context[$finalTokens[$lastNotEmptyToken]['code']]) === true) {
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...
1010
                        $finalTokens[$newStackPtr] = array(
1011
                                                      'content' => $token[1],
1012
                                                      'code'    => T_STRING,
1013
                                                      'type'    => 'T_STRING',
1014
                                                     );
1015
                        $newStackPtr++;
1016
                        continue;
1017
                    }
1018
                }//end if
1019
1020
                $newToken = null;
1021 View Code Duplication
                if ($tokenIsArray === false) {
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...
1022
                    if (isset(self::$_resolveTokenCache[$token[0]]) === true) {
1023
                        $newToken = self::$_resolveTokenCache[$token[0]];
1024
                    }
1025
                } else {
1026
                    $cacheKey = null;
1027
                    if ($token[0] === T_STRING) {
1028
                        $cacheKey = strtolower($token[1]);
1029
                    } else if ($token[0] !== T_CURLY_OPEN) {
1030
                        $cacheKey = $token[0];
1031
                    }
1032
1033
                    if ($cacheKey !== null && isset(self::$_resolveTokenCache[$cacheKey]) === true) {
1034
                        $newToken            = self::$_resolveTokenCache[$cacheKey];
1035
                        $newToken['content'] = $token[1];
1036
                    }
1037
                }
1038
1039
                if ($newToken === null) {
1040
                    $newToken = self::standardiseToken($token);
1041
                }
1042
1043
                // Convert colons that are actually the ELSE component of an
1044
                // inline IF statement.
1045
                if ($newToken['code'] === T_INLINE_THEN) {
1046
                    $insideInlineIf[] = $stackPtr;
1047
                } else if (empty($insideInlineIf) === false && $newToken['code'] === T_COLON) {
1048
                    array_pop($insideInlineIf);
1049
                    $newToken['code'] = T_INLINE_ELSE;
1050
                    $newToken['type'] = 'T_INLINE_ELSE';
1051
                }
1052
1053
                // This is a special condition for T_ARRAY tokens used for
1054
                // type hinting function arguments as being arrays. We want to keep
1055
                // the parenthesis map clean, so let's tag these tokens as
1056
                // T_ARRAY_HINT.
1057
                if ($newToken['code'] === T_ARRAY) {
1058
                    // Recalculate number of tokens.
1059
                    for ($i = $stackPtr; $i < $numTokens; $i++) {
1060
                        if ($tokens[$i] === '(') {
1061
                            break;
1062
                        } else if ($tokens[$i][0] === T_VARIABLE) {
1063
                            $newToken['code'] = T_ARRAY_HINT;
1064
                            $newToken['type'] = 'T_ARRAY_HINT';
1065
                            break;
1066
                        }
1067
                    }
1068
                }
1069
1070
                // This is a special case when checking PHP 5.5+ code in PHP < 5.5
1071
                // where "finally" should be T_FINALLY instead of T_STRING.
1072
                if ($newToken['code'] === T_STRING
1073
                    && strtolower($newToken['content']) === 'finally'
1074
                ) {
1075
                    $newToken['code'] = T_FINALLY;
1076
                    $newToken['type'] = 'T_FINALLY';
1077
                }
1078
1079
                // This is a special case for the PHP 5.5 classname::class syntax
1080
                // where "class" should be T_STRING instead of T_CLASS.
1081
                if ($newToken['code'] === T_CLASS
1082
                    && $finalTokens[($newStackPtr - 1)]['code'] === T_DOUBLE_COLON
1083
                ) {
1084
                    $newToken['code'] = T_STRING;
1085
                    $newToken['type'] = 'T_STRING';
1086
                }
1087
1088
                // This is a special case for PHP 5.6 use function and use const
1089
                // where "function" and "const" should be T_STRING instead of T_FUNCTION
1090
                // and T_CONST.
1091 View Code Duplication
                if (($newToken['code'] === T_FUNCTION
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...
1092
                    || $newToken['code'] === T_CONST)
1093
                    && $finalTokens[$lastNotEmptyToken]['code'] === T_USE
1094
                ) {
1095
                    $newToken['code'] = T_STRING;
1096
                    $newToken['type'] = 'T_STRING';
1097
                }
1098
1099
                // This is a special case for use groups in PHP 7+ where leaving
1100
                // the curly braces as their normal tokens would confuse
1101
                // the scope map and sniffs.
1102 View Code Duplication
                if ($newToken['code'] === T_OPEN_CURLY_BRACKET
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...
1103
                    && $finalTokens[$lastNotEmptyToken]['code'] === T_NS_SEPARATOR
1104
                ) {
1105
                    $newToken['code'] = T_OPEN_USE_GROUP;
1106
                    $newToken['type'] = 'T_OPEN_USE_GROUP';
1107
                    $insideUseGroup   = true;
1108
                }
1109
1110
                if ($insideUseGroup === true && $newToken['code'] === T_CLOSE_CURLY_BRACKET) {
1111
                    $newToken['code'] = T_CLOSE_USE_GROUP;
1112
                    $newToken['type'] = 'T_CLOSE_USE_GROUP';
1113
                    $insideUseGroup   = false;
1114
                }
1115
1116
                $finalTokens[$newStackPtr] = $newToken;
1117
                $newStackPtr++;
1118
            }//end if
1119
        }//end for
1120
1121
        if (PHP_CodeSniffer_VERBOSITY > 1) {
1122
            echo "\t*** END PHP TOKENIZING ***".PHP_EOL;
1123
        }
1124
1125
        return $finalTokens;
1126
1127
    }//end tokenize()
1128
1129
1130
    /**
1131
     * Performs additional processing after main tokenizing.
1132
     *
1133
     * This additional processing checks for CASE statements that are using curly
1134
     * braces for scope openers and closers. It also turns some T_FUNCTION tokens
1135
     * into T_CLOSURE when they are not standard function definitions. It also
1136
     * detects short array syntax and converts those square brackets into new tokens.
1137
     * It also corrects some usage of the static and class keywords. It also
1138
     * assigns tokens to function return types.
1139
     *
1140
     * @return void
1141
     */
1142
    protected function processAdditional()
1143
    {
1144
        if (PHP_CodeSniffer_VERBOSITY > 1) {
1145
            echo "\t*** START ADDITIONAL PHP PROCESSING ***".PHP_EOL;
1146
        }
1147
1148
        $numTokens = count($this->tokens);
1149
        for ($i = ($numTokens - 1); $i >= 0; $i--) {
1150
            // Check for any unset scope conditions due to alternate IF/ENDIF syntax.
1151 View Code Duplication
            if (isset($this->tokens[$i]['scope_opener']) === true
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...
1152
                && isset($this->tokens[$i]['scope_condition']) === false
1153
            ) {
1154
                $this->tokens[$i]['scope_condition'] = $this->tokens[$this->tokens[$i]['scope_opener']]['scope_condition'];
1155
            }
1156
1157
            if ($this->tokens[$i]['code'] === T_FUNCTION) {
1158
                // Context sensitive keywords support.
1159 View Code Duplication
                for ($x = ($i + 1); $x < $numTokens; $x++) {
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...
1160
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1161
                        // Non-whitespace content.
1162
                        break;
1163
                    }
1164
                }
1165
1166
                if ($x === $numTokens) {
1167
                    // We got to the end without finding any more
1168
                    // non-whitespace content.
1169
                    continue;
1170
                }
1171
1172 View Code Duplication
                if (in_array($this->tokens[$x]['code'], array(T_STRING, T_OPEN_PARENTHESIS, T_BITWISE_AND), true) === false) {
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...
1173
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1174
                        $line = $this->tokens[$x]['line'];
1175
                        $type = $this->tokens[$x]['type'];
1176
                        echo "\t* token $x on line $line changed from $type to T_STRING".PHP_EOL;
1177
                    }
1178
1179
                    $this->tokens[$x]['code'] = T_STRING;
1180
                    $this->tokens[$x]['type'] = 'T_STRING';
1181
                }
1182
1183
                /*
1184
                    Detect functions that are actually closures and
1185
                    assign them a different token.
1186
                */
1187
1188
                if (isset($this->tokens[$i]['scope_opener']) === true) {
1189
                    for ($x = ($i + 1); $x < $numTokens; $x++) {
1190
                        if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false
1191
                            && $this->tokens[$x]['code'] !== T_BITWISE_AND
1192
                        ) {
1193
                            break;
1194
                        }
1195
                    }
1196
1197
                    if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
1198
                        $this->tokens[$i]['code'] = T_CLOSURE;
1199
                        $this->tokens[$i]['type'] = 'T_CLOSURE';
1200 View Code Duplication
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
1201
                            $line = $this->tokens[$i]['line'];
1202
                            echo "\t* token $i on line $line changed from T_FUNCTION to T_CLOSURE".PHP_EOL;
1203
                        }
1204
1205 View Code Duplication
                        for ($x = ($this->tokens[$i]['scope_opener'] + 1); $x < $this->tokens[$i]['scope_closer']; $x++) {
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...
1206
                            if (isset($this->tokens[$x]['conditions'][$i]) === false) {
1207
                                continue;
1208
                            }
1209
1210
                            $this->tokens[$x]['conditions'][$i] = T_CLOSURE;
1211
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
1212
                                $type = $this->tokens[$x]['type'];
1213
                                echo "\t\t* cleaned $x ($type) *".PHP_EOL;
1214
                            }
1215
                        }
1216
                    }
1217
1218
                    $tokenAfterReturnTypeHint = $this->tokens[$i]['scope_opener'];
1219
                } else if (isset($this->tokens[$i]['parenthesis_closer']) === true) {
1220
                    $tokenAfterReturnTypeHint = null;
1221
                    for ($x = ($this->tokens[$i]['parenthesis_closer'] + 1); $x < $numTokens; $x++) {
1222
                        if ($this->tokens[$x]['code'] === T_SEMICOLON) {
1223
                            $tokenAfterReturnTypeHint = $x;
1224
                            break;
1225
                        }
1226
                    }
1227
1228
                    if ($tokenAfterReturnTypeHint === null) {
1229
                        // Probably a syntax error.
1230
                        continue;
1231
                    }
1232
                } else {
1233
                    // Probably a syntax error.
1234
                    continue;
1235
                }//end if
1236
1237
                /*
1238
                    Detect function return values and assign them
1239
                    a special token, because PHP doesn't.
1240
                */
1241
1242
                for ($x = ($tokenAfterReturnTypeHint - 1); $x > $i; $x--) {
1243
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1244
                        if (in_array($this->tokens[$x]['code'], array(T_STRING, T_ARRAY, T_CALLABLE, T_SELF, T_PARENT), true) === true) {
1245
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
1246
                                $line = $this->tokens[$x]['line'];
1247
                                $type = $this->tokens[$x]['type'];
1248
                                echo "\t* token $x on line $line changed from $type to T_RETURN_TYPE".PHP_EOL;
1249
                            }
1250
1251
                            $this->tokens[$x]['code'] = T_RETURN_TYPE;
1252
                            $this->tokens[$x]['type'] = 'T_RETURN_TYPE';
1253
                        }
1254
1255
                        break;
1256
                    }
1257
                }
1258
1259
                continue;
1260
            } else if ($this->tokens[$i]['code'] === T_CLASS && isset($this->tokens[$i]['scope_opener']) === true) {
1261
                /*
1262
                    Detect anonymous classes and assign them a different token.
1263
                */
1264
1265 View Code Duplication
                for ($x = ($i + 1); $x < $numTokens; $x++) {
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...
1266
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1267
                        break;
1268
                    }
1269
                }
1270
1271
                if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS
1272
                    || $this->tokens[$x]['code'] === T_OPEN_CURLY_BRACKET
1273
                    || $this->tokens[$x]['code'] === T_EXTENDS
1274
                    || $this->tokens[$x]['code'] === T_IMPLEMENTS
1275
                ) {
1276
                    $this->tokens[$i]['code'] = T_ANON_CLASS;
1277
                    $this->tokens[$i]['type'] = 'T_ANON_CLASS';
1278 View Code Duplication
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
1279
                        $line = $this->tokens[$i]['line'];
1280
                        echo "\t* token $i on line $line changed from T_CLASS to T_ANON_CLASS".PHP_EOL;
1281
                    }
1282
1283 View Code Duplication
                    for ($x = ($this->tokens[$i]['scope_opener'] + 1); $x < $this->tokens[$i]['scope_closer']; $x++) {
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...
1284
                        if (isset($this->tokens[$x]['conditions'][$i]) === false) {
1285
                            continue;
1286
                        }
1287
1288
                        $this->tokens[$x]['conditions'][$i] = T_ANON_CLASS;
1289
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
1290
                            $type = $this->tokens[$x]['type'];
1291
                            echo "\t\t* cleaned $x ($type) *".PHP_EOL;
1292
                        }
1293
                    }
1294
                }
1295
1296
                continue;
1297
            } else if ($this->tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) {
1298
                // Unless there is a variable or a bracket before this token,
1299
                // it is the start of an array being defined using the short syntax.
1300 View Code Duplication
                for ($x = ($i - 1); $x > 0; $x--) {
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...
1301
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1302
                        break;
1303
                    }
1304
                }
1305
1306
                $allowed = array(
1307
                            T_CLOSE_CURLY_BRACKET  => T_CLOSE_CURLY_BRACKET,
1308
                            T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET,
1309
                            T_CLOSE_PARENTHESIS    => T_CLOSE_PARENTHESIS,
1310
                            T_VARIABLE             => T_VARIABLE,
1311
                            T_STRING               => T_STRING,
1312
                           );
1313
1314
                if (isset($allowed[$this->tokens[$x]['code']]) === false
1315
                    && isset($this->tokens[$i]['bracket_closer']) === true
1316
                ) {
1317
                    $this->tokens[$i]['code'] = T_OPEN_SHORT_ARRAY;
1318
                    $this->tokens[$i]['type'] = 'T_OPEN_SHORT_ARRAY';
1319
1320
                    $closer = $this->tokens[$i]['bracket_closer'];
1321
                    $this->tokens[$closer]['code'] = T_CLOSE_SHORT_ARRAY;
1322
                    $this->tokens[$closer]['type'] = 'T_CLOSE_SHORT_ARRAY';
1323 View Code Duplication
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
1324
                        $line = $this->tokens[$i]['line'];
1325
                        echo "\t* token $i on line $line changed from T_OPEN_SQUARE_BRACKET to T_OPEN_SHORT_ARRAY".PHP_EOL;
1326
                        $line = $this->tokens[$closer]['line'];
1327
                        echo "\t* token $closer on line $line changed from T_CLOSE_SQUARE_BRACKET to T_CLOSE_SHORT_ARRAY".PHP_EOL;
1328
                    }
1329
                }
1330
1331
                continue;
1332
            } else if ($this->tokens[$i]['code'] === T_STATIC) {
1333 View Code Duplication
                for ($x = ($i - 1); $x > 0; $x--) {
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...
1334
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1335
                        break;
1336
                    }
1337
                }
1338
1339
                if ($this->tokens[$x]['code'] === T_INSTANCEOF) {
1340
                    $this->tokens[$i]['code'] = T_STRING;
1341
                    $this->tokens[$i]['type'] = 'T_STRING';
1342
1343 View Code Duplication
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
1344
                        $line = $this->tokens[$i]['line'];
1345
                        echo "\t* token $i on line $line changed from T_STATIC to T_STRING".PHP_EOL;
1346
                    }
1347
                }
1348
1349
                continue;
1350
            } else if ($this->tokens[$i]['code'] === T_ECHO && $this->tokens[$i]['content'] === '<?=') {
1351
                // HHVM tokenizes <?= as T_ECHO but it should be T_OPEN_TAG_WITH_ECHO.
1352
                $this->tokens[$i]['code'] = T_OPEN_TAG_WITH_ECHO;
1353
                $this->tokens[$i]['type'] = 'T_OPEN_TAG_WITH_ECHO';
1354
1355 View Code Duplication
                if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
1356
                    $line = $this->tokens[$i]['line'];
1357
                    echo "\t* token $i on line $line changed from T_ECHO to T_OPEN_TAG_WITH_ECHO".PHP_EOL;
1358
                }
1359
            } else if ($this->tokens[$i]['code'] === T_TRUE
1360
                || $this->tokens[$i]['code'] === T_FALSE
1361
                || $this->tokens[$i]['code'] === T_NULL
1362
            ) {
1363 View Code Duplication
                for ($x = ($i + 1); $i < $numTokens; $x++) {
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...
1364
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1365
                        // Non-whitespace content.
1366
                        break;
1367
                    }
1368
                }
1369
1370
                $context = array(
1371
                            T_OBJECT_OPERATOR      => true,
1372
                            T_NS_SEPARATOR         => true,
1373
                            T_PAAMAYIM_NEKUDOTAYIM => true,
1374
                           );
1375 View Code Duplication
                if (isset($context[$this->tokens[$x]['code']]) === true) {
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...
1376
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1377
                        $line = $this->tokens[$i]['line'];
1378
                        $type = $this->tokens[$i]['type'];
1379
                        echo "\t* token $i on line $line changed from $type to T_STRING".PHP_EOL;
1380
                    }
1381
1382
                    $this->tokens[$i]['code'] = T_STRING;
1383
                    $this->tokens[$i]['type'] = 'T_STRING';
1384
                }
1385
            } else if ($this->tokens[$i]['code'] === T_CONST) {
1386
                // Context sensitive keywords support.
1387 View Code Duplication
                for ($x = ($i + 1); $i < $numTokens; $x++) {
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...
1388
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1389
                        // Non-whitespace content.
1390
                        break;
1391
                    }
1392
                }
1393
1394 View Code Duplication
                if ($this->tokens[$x]['code'] !== T_STRING) {
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...
1395
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1396
                        $line = $this->tokens[$x]['line'];
1397
                        $type = $this->tokens[$x]['type'];
1398
                        echo "\t* token $x on line $line changed from $type to T_STRING".PHP_EOL;
1399
                    }
1400
1401
                    $this->tokens[$x]['code'] = T_STRING;
1402
                    $this->tokens[$x]['type'] = 'T_STRING';
1403
                }
1404
            } else if ($this->tokens[$i]['code'] === T_PAAMAYIM_NEKUDOTAYIM) {
1405
                // Context sensitive keywords support.
1406 View Code Duplication
                for ($x = ($i + 1); $i < $numTokens; $x++) {
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...
1407
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1408
                        // Non-whitespace content.
1409
                        break;
1410
                    }
1411
                }
1412
1413 View Code Duplication
                if (in_array($this->tokens[$x]['code'], array(T_STRING, T_VARIABLE, T_DOLLAR), true) === false) {
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...
1414
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1415
                        $line = $this->tokens[$x]['line'];
1416
                        $type = $this->tokens[$x]['type'];
1417
                        echo "\t* token $x on line $line changed from $type to T_STRING".PHP_EOL;
1418
                    }
1419
1420
                    $this->tokens[$x]['code'] = T_STRING;
1421
                    $this->tokens[$x]['type'] = 'T_STRING';
1422
                }
1423
            }//end if
1424
1425
            if (($this->tokens[$i]['code'] !== T_CASE
1426
                && $this->tokens[$i]['code'] !== T_DEFAULT)
1427
                || isset($this->tokens[$i]['scope_opener']) === false
1428
            ) {
1429
                // Only interested in CASE and DEFAULT statements from here on in.
1430
                continue;
1431
            }
1432
1433
            $scopeOpener = $this->tokens[$i]['scope_opener'];
1434
            $scopeCloser = $this->tokens[$i]['scope_closer'];
1435
1436
            // If the first char after the opener is a curly brace
1437
            // and that brace has been ignored, it is actually
1438
            // opening this case statement and the opener and closer are
1439
            // probably set incorrectly.
1440 View Code Duplication
            for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) {
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...
1441
                if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1442
                    // Non-whitespace content.
1443
                    break;
1444
                }
1445
            }
1446
1447
            if ($this->tokens[$x]['code'] === T_CASE || $this->tokens[$x]['code'] === T_DEFAULT) {
1448
                // Special case for multiple CASE statements that share the same
1449
                // closer. Because we are going backwards through the file, this next
1450
                // CASE statement is already fixed, so just use its closer and don't
1451
                // worry about fixing anything.
1452
                $newCloser = $this->tokens[$x]['scope_closer'];
1453
                $this->tokens[$i]['scope_closer'] = $newCloser;
1454
                if (PHP_CodeSniffer_VERBOSITY > 1) {
1455
                    $oldType = $this->tokens[$scopeCloser]['type'];
1456
                    $newType = $this->tokens[$newCloser]['type'];
1457
                    $line    = $this->tokens[$i]['line'];
1458
                    echo "\t* token $i (T_CASE) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
1459
                }
1460
1461
                continue;
1462
            }
1463
1464
            if ($this->tokens[$x]['code'] !== T_OPEN_CURLY_BRACKET
1465
                || isset($this->tokens[$x]['scope_condition']) === true
1466
            ) {
1467
                // Not a CASE/DEFAULT with a curly brace opener.
1468
                continue;
1469
            }
1470
1471
            // The closer for this CASE/DEFAULT should be the closing curly brace and
1472
            // not whatever it already is. The opener needs to be the opening curly
1473
            // brace so everything matches up.
1474
            $newCloser = $this->tokens[$x]['bracket_closer'];
1475 View Code Duplication
            foreach (array($i, $x, $newCloser) as $index) {
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...
1476
                $this->tokens[$index]['scope_condition'] = $i;
1477
                $this->tokens[$index]['scope_opener']    = $x;
1478
                $this->tokens[$index]['scope_closer']    = $newCloser;
1479
            }
1480
1481
            unset($this->tokens[$scopeOpener]['scope_condition']);
1482
            unset($this->tokens[$scopeOpener]['scope_opener']);
1483
            unset($this->tokens[$scopeOpener]['scope_closer']);
1484
            unset($this->tokens[$scopeCloser]['scope_condition']);
1485
            unset($this->tokens[$scopeCloser]['scope_opener']);
1486
            unset($this->tokens[$scopeCloser]['scope_closer']);
1487
            unset($this->tokens[$x]['bracket_opener']);
1488
            unset($this->tokens[$x]['bracket_closer']);
1489
            unset($this->tokens[$newCloser]['bracket_opener']);
1490
            unset($this->tokens[$newCloser]['bracket_closer']);
1491
            $this->tokens[$scopeCloser]['conditions'][] = $i;
1492
1493
            if (PHP_CodeSniffer_VERBOSITY > 1) {
1494
                $line      = $this->tokens[$i]['line'];
1495
                $tokenType = $this->tokens[$i]['type'];
1496
1497
                $oldType = $this->tokens[$scopeOpener]['type'];
1498
                $newType = $this->tokens[$x]['type'];
1499
                echo "\t* token $i ($tokenType) on line $line opener changed from $scopeOpener ($oldType) to $x ($newType)".PHP_EOL;
1500
1501
                $oldType = $this->tokens[$scopeCloser]['type'];
1502
                $newType = $this->tokens[$newCloser]['type'];
1503
                echo "\t* token $i ($tokenType) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
1504
            }
1505
1506
            // Now fix up all the tokens that think they are
1507
            // inside the CASE/DEFAULT statement when they are really outside.
1508
            for ($x = $newCloser; $x < $scopeCloser; $x++) {
1509
                foreach ($this->tokens[$x]['conditions'] as $num => $oldCond) {
1510
                    if ($oldCond === $this->tokens[$i]['code']) {
1511
                        $oldConditions = $this->tokens[$x]['conditions'];
1512
                        unset($this->tokens[$x]['conditions'][$num]);
1513
1514
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
1515
                            $type     = $this->tokens[$x]['type'];
1516
                            $oldConds = '';
1517
                            foreach ($oldConditions as $condition) {
1518
                                $oldConds .= token_name($condition).',';
1519
                            }
1520
1521
                            $oldConds = rtrim($oldConds, ',');
1522
1523
                            $newConds = '';
1524
                            foreach ($this->tokens[$x]['conditions'] as $condition) {
1525
                                $newConds .= token_name($condition).',';
1526
                            }
1527
1528
                            $newConds = rtrim($newConds, ',');
1529
1530
                            echo "\t\t* cleaned $x ($type) *".PHP_EOL;
1531
                            echo "\t\t\t=> conditions changed from $oldConds to $newConds".PHP_EOL;
1532
                        }
1533
1534
                        break;
1535
                    }//end if
1536
                }//end foreach
1537
            }//end for
1538
        }//end for
1539
1540
        if (PHP_CodeSniffer_VERBOSITY > 1) {
1541
            echo "\t*** END ADDITIONAL PHP PROCESSING ***".PHP_EOL;
1542
        }
1543
1544
    }//end processAdditional()
1545
1546
1547
    /**
1548
     * Takes a token produced from <code>token_get_all()</code> and produces a
1549
     * more uniform token.
1550
     *
1551
     * @param string|array $token The token to convert.
1552
     *
1553
     * @return array The new token.
1554
     */
1555
    public static function standardiseToken($token)
1556
    {
1557 View Code Duplication
        if (isset($token[1]) === false) {
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...
1558
            if (isset(self::$_resolveTokenCache[$token[0]]) === true) {
1559
                return self::$_resolveTokenCache[$token[0]];
1560
            }
1561
        } else {
1562
            $cacheKey = null;
1563
            if ($token[0] === T_STRING) {
1564
                $cacheKey = strtolower($token[1]);
1565
            } else if ($token[0] !== T_CURLY_OPEN) {
1566
                $cacheKey = $token[0];
1567
            }
1568
1569
            if ($cacheKey !== null && isset(self::$_resolveTokenCache[$cacheKey]) === true) {
1570
                $newToken            = self::$_resolveTokenCache[$cacheKey];
1571
                $newToken['content'] = $token[1];
1572
                return $newToken;
1573
            }
1574
        }
1575
1576
        if (isset($token[1]) === false) {
1577
            return self::resolveSimpleToken($token[0]);
1578
        }
1579
1580
        if ($token[0] === T_STRING) {
1581
            switch ($cacheKey) {
0 ignored issues
show
Bug introduced by
The variable $cacheKey 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

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1582
            case 'false':
1583
                $newToken['type'] = 'T_FALSE';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$newToken was never initialized. Although not strictly required by PHP, it is generally a good practice to add $newToken = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1584
                break;
1585
            case 'true':
1586
                $newToken['type'] = 'T_TRUE';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$newToken was never initialized. Although not strictly required by PHP, it is generally a good practice to add $newToken = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1587
                break;
1588
            case 'null':
1589
                $newToken['type'] = 'T_NULL';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$newToken was never initialized. Although not strictly required by PHP, it is generally a good practice to add $newToken = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1590
                break;
1591
            case 'self':
1592
                $newToken['type'] = 'T_SELF';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$newToken was never initialized. Although not strictly required by PHP, it is generally a good practice to add $newToken = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1593
                break;
1594
            case 'parent':
1595
                $newToken['type'] = 'T_PARENT';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$newToken was never initialized. Although not strictly required by PHP, it is generally a good practice to add $newToken = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1596
                break;
1597
            default:
1598
                $newToken['type'] = 'T_STRING';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$newToken was never initialized. Although not strictly required by PHP, it is generally a good practice to add $newToken = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1599
                break;
1600
            }
1601
1602
            $newToken['code'] = constant($newToken['type']);
1603
1604
            self::$_resolveTokenCache[$cacheKey] = $newToken;
1605
        } else if ($token[0] === T_CURLY_OPEN) {
1606
            $newToken = array(
1607
                         'code' => T_OPEN_CURLY_BRACKET,
1608
                         'type' => 'T_OPEN_CURLY_BRACKET',
1609
                        );
1610
        } else {
1611
            $newToken = array(
1612
                         'code' => $token[0],
1613
                         'type' => token_name($token[0]),
1614
                        );
1615
1616
            self::$_resolveTokenCache[$token[0]] = $newToken;
1617
        }//end if
1618
1619
        $newToken['content'] = $token[1];
1620
        return $newToken;
1621
1622
    }//end standardiseToken()
1623
1624
1625
    /**
1626
     * Converts simple tokens into a format that conforms to complex tokens
1627
     * produced by token_get_all().
1628
     *
1629
     * Simple tokens are tokens that are not in array form when produced from
1630
     * token_get_all().
1631
     *
1632
     * @param string $token The simple token to convert.
1633
     *
1634
     * @return array The new token in array format.
1635
     */
1636
    public static function resolveSimpleToken($token)
1637
    {
1638
        $newToken = array();
1639
1640
        switch ($token) {
1641
        case '{':
1642
            $newToken['type'] = 'T_OPEN_CURLY_BRACKET';
1643
            break;
1644
        case '}':
1645
            $newToken['type'] = 'T_CLOSE_CURLY_BRACKET';
1646
            break;
1647
        case '[':
1648
            $newToken['type'] = 'T_OPEN_SQUARE_BRACKET';
1649
            break;
1650
        case ']':
1651
            $newToken['type'] = 'T_CLOSE_SQUARE_BRACKET';
1652
            break;
1653
        case '(':
1654
            $newToken['type'] = 'T_OPEN_PARENTHESIS';
1655
            break;
1656
        case ')':
1657
            $newToken['type'] = 'T_CLOSE_PARENTHESIS';
1658
            break;
1659
        case ':':
1660
            $newToken['type'] = 'T_COLON';
1661
            break;
1662
        case '.':
1663
            $newToken['type'] = 'T_STRING_CONCAT';
1664
            break;
1665
        case '?':
1666
            $newToken['type'] = 'T_INLINE_THEN';
1667
            break;
1668
        case ';':
1669
            $newToken['type'] = 'T_SEMICOLON';
1670
            break;
1671
        case '=':
1672
            $newToken['type'] = 'T_EQUAL';
1673
            break;
1674
        case '*':
1675
            $newToken['type'] = 'T_MULTIPLY';
1676
            break;
1677
        case '/':
1678
            $newToken['type'] = 'T_DIVIDE';
1679
            break;
1680
        case '+':
1681
            $newToken['type'] = 'T_PLUS';
1682
            break;
1683
        case '-':
1684
            $newToken['type'] = 'T_MINUS';
1685
            break;
1686
        case '%':
1687
            $newToken['type'] = 'T_MODULUS';
1688
            break;
1689
        case '^':
1690
            $newToken['type'] = 'T_BITWISE_XOR';
1691
            break;
1692
        case '&':
1693
            $newToken['type'] = 'T_BITWISE_AND';
1694
            break;
1695
        case '|':
1696
            $newToken['type'] = 'T_BITWISE_OR';
1697
            break;
1698
        case '<':
1699
            $newToken['type'] = 'T_LESS_THAN';
1700
            break;
1701
        case '>':
1702
            $newToken['type'] = 'T_GREATER_THAN';
1703
            break;
1704
        case '!':
1705
            $newToken['type'] = 'T_BOOLEAN_NOT';
1706
            break;
1707
        case ',':
1708
            $newToken['type'] = 'T_COMMA';
1709
            break;
1710
        case '@':
1711
            $newToken['type'] = 'T_ASPERAND';
1712
            break;
1713
        case '$':
1714
            $newToken['type'] = 'T_DOLLAR';
1715
            break;
1716
        case '`':
1717
            $newToken['type'] = 'T_BACKTICK';
1718
            break;
1719
        default:
1720
            $newToken['type'] = 'T_NONE';
1721
            break;
1722
        }//end switch
1723
1724
        $newToken['code']    = constant($newToken['type']);
1725
        $newToken['content'] = $token;
1726
1727
        self::$_resolveTokenCache[$token] = $newToken;
1728
        return $newToken;
1729
1730
    }//end resolveSimpleToken()
1731
1732
1733
}//end class
1734