Completed
Push — master ( da65dc...5751ed )
by Tomáš
20:43 queued 16:49
created

JS::getRegexToken()   F

Complexity

Conditions 20
Paths 1803

Size

Total Lines 124
Code Lines 71

Duplication

Lines 23
Ratio 18.55 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 23
loc 124
rs 2
cc 20
eloc 71
nc 1803
nop 4

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Tokenizes JS 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
use Symplify\PHP7_CodeSniffer\Exceptions\TokenizerException;
14
use Symplify\PHP7_CodeSniffer\Config;
15
16
class JS extends Tokenizer
17
{
18
19
20
    /**
21
     * A list of tokens that are allowed to open a scope.
22
     *
23
     * This array also contains information about what kind of token the scope
24
     * opener uses to open and close the scope, if the token strictly requires
25
     * an opener, if the token can share a scope closer, and who it can be shared
26
     * with. An example of a token that shares a scope closer is a CASE scope.
27
     *
28
     * @var array
29
     */
30
    public $scopeOpeners = array(
31
                            T_IF       => array(
32
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
33
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
34
                                           'strict' => false,
35
                                           'shared' => false,
36
                                           'with'   => array(),
37
                                          ),
38
                            T_TRY      => array(
39
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
40
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
41
                                           'strict' => true,
42
                                           'shared' => false,
43
                                           'with'   => array(),
44
                                          ),
45
                            T_CATCH    => array(
46
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
47
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
48
                                           'strict' => true,
49
                                           'shared' => false,
50
                                           'with'   => array(),
51
                                          ),
52
                            T_ELSE     => array(
53
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
54
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
55
                                           'strict' => false,
56
                                           'shared' => false,
57
                                           'with'   => array(),
58
                                          ),
59
                            T_FOR      => array(
60
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
61
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
62
                                           'strict' => false,
63
                                           'shared' => false,
64
                                           'with'   => array(),
65
                                          ),
66
                            T_FUNCTION => array(
67
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
68
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
69
                                           'strict' => false,
70
                                           'shared' => false,
71
                                           'with'   => array(),
72
                                          ),
73
                            T_WHILE    => array(
74
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
75
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
76
                                           'strict' => false,
77
                                           'shared' => false,
78
                                           'with'   => array(),
79
                                          ),
80
                            T_DO       => array(
81
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
82
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
83
                                           'strict' => true,
84
                                           'shared' => false,
85
                                           'with'   => array(),
86
                                          ),
87
                            T_SWITCH   => array(
88
                                           'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
89
                                           'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
90
                                           'strict' => true,
91
                                           'shared' => false,
92
                                           'with'   => array(),
93
                                          ),
94
                            T_CASE     => array(
95
                                           'start'  => array(T_COLON => T_COLON),
96
                                           'end'    => array(
97
                                                        T_BREAK    => T_BREAK,
98
                                                        T_RETURN   => T_RETURN,
99
                                                        T_CONTINUE => T_CONTINUE,
100
                                                        T_THROW    => T_THROW,
101
                                                       ),
102
                                           'strict' => true,
103
                                           'shared' => true,
104
                                           'with'   => array(
105
                                                        T_DEFAULT => T_DEFAULT,
106
                                                        T_CASE    => T_CASE,
107
                                                        T_SWITCH  => T_SWITCH,
108
                                                       ),
109
                                          ),
110
                            T_DEFAULT  => array(
111
                                           'start'  => array(T_COLON => T_COLON),
112
                                           'end'    => array(
113
                                                        T_BREAK    => T_BREAK,
114
                                                        T_RETURN   => T_RETURN,
115
                                                        T_CONTINUE => T_CONTINUE,
116
                                                        T_THROW    => T_THROW,
117
                                                       ),
118
                                           'strict' => true,
119
                                           'shared' => true,
120
                                           'with'   => array(
121
                                                        T_CASE   => T_CASE,
122
                                                        T_SWITCH => T_SWITCH,
123
                                                       ),
124
                                          ),
125
                           );
126
127
    /**
128
     * A list of tokens that end the scope.
129
     *
130
     * This array is just a unique collection of the end tokens
131
     * from the _scopeOpeners array. The data is duplicated here to
132
     * save time during parsing of the file.
133
     *
134
     * @var array
135
     */
136
    public $endScopeTokens = array(
137
                              T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
138
                              T_BREAK               => T_BREAK,
139
                             );
140
141
    /**
142
     * A list of special JS tokens and their types.
143
     *
144
     * @var array
145
     */
146
    protected $tokenValues = array(
147
                              'function'  => 'T_FUNCTION',
148
                              'prototype' => 'T_PROTOTYPE',
149
                              'try'       => 'T_TRY',
150
                              'catch'     => 'T_CATCH',
151
                              'return'    => 'T_RETURN',
152
                              'throw'     => 'T_THROW',
153
                              'break'     => 'T_BREAK',
154
                              'switch'    => 'T_SWITCH',
155
                              'continue'  => 'T_CONTINUE',
156
                              'if'        => 'T_IF',
157
                              'else'      => 'T_ELSE',
158
                              'do'        => 'T_DO',
159
                              'while'     => 'T_WHILE',
160
                              'for'       => 'T_FOR',
161
                              'var'       => 'T_VAR',
162
                              'case'      => 'T_CASE',
163
                              'default'   => 'T_DEFAULT',
164
                              'true'      => 'T_TRUE',
165
                              'false'     => 'T_FALSE',
166
                              'null'      => 'T_NULL',
167
                              'this'      => 'T_THIS',
168
                              'typeof'    => 'T_TYPEOF',
169
                              '('         => 'T_OPEN_PARENTHESIS',
170
                              ')'         => 'T_CLOSE_PARENTHESIS',
171
                              '{'         => 'T_OPEN_CURLY_BRACKET',
172
                              '}'         => 'T_CLOSE_CURLY_BRACKET',
173
                              '['         => 'T_OPEN_SQUARE_BRACKET',
174
                              ']'         => 'T_CLOSE_SQUARE_BRACKET',
175
                              '?'         => 'T_INLINE_THEN',
176
                              '.'         => 'T_OBJECT_OPERATOR',
177
                              '+'         => 'T_PLUS',
178
                              '-'         => 'T_MINUS',
179
                              '*'         => 'T_MULTIPLY',
180
                              '%'         => 'T_MODULUS',
181
                              '/'         => 'T_DIVIDE',
182
                              '^'         => 'T_LOGICAL_XOR',
183
                              ','         => 'T_COMMA',
184
                              ';'         => 'T_SEMICOLON',
185
                              ':'         => 'T_COLON',
186
                              '<'         => 'T_LESS_THAN',
187
                              '>'         => 'T_GREATER_THAN',
188
                              '<='        => 'T_IS_SMALLER_OR_EQUAL',
189
                              '>='        => 'T_IS_GREATER_OR_EQUAL',
190
                              '!'         => 'T_BOOLEAN_NOT',
191
                              '||'        => 'T_BOOLEAN_OR',
192
                              '&&'        => 'T_BOOLEAN_AND',
193
                              '|'         => 'T_BITWISE_OR',
194
                              '&'         => 'T_BITWISE_AND',
195
                              '!='        => 'T_IS_NOT_EQUAL',
196
                              '!=='       => 'T_IS_NOT_IDENTICAL',
197
                              '='         => 'T_EQUAL',
198
                              '=='        => 'T_IS_EQUAL',
199
                              '==='       => 'T_IS_IDENTICAL',
200
                              '-='        => 'T_MINUS_EQUAL',
201
                              '+='        => 'T_PLUS_EQUAL',
202
                              '*='        => 'T_MUL_EQUAL',
203
                              '/='        => 'T_DIV_EQUAL',
204
                              '%='        => 'T_MOD_EQUAL',
205
                              '++'        => 'T_INC',
206
                              '--'        => 'T_DEC',
207
                              '//'        => 'T_COMMENT',
208
                              '/*'        => 'T_COMMENT',
209
                              '/**'       => 'T_DOC_COMMENT',
210
                              '*/'        => 'T_COMMENT',
211
                             );
212
213
    /**
214
     * A list string delimiters.
215
     *
216
     * @var array
217
     */
218
    protected $stringTokens = array(
219
                               '\'' => '\'',
220
                               '"'  => '"',
221
                              );
222
223
    /**
224
     * A list tokens that start and end comments.
225
     *
226
     * @var array
227
     */
228
    protected $commentTokens = array(
229
                                '//'  => null,
230
                                '/*'  => '*/',
231
                                '/**' => '*/',
232
                               );
233
234
235
    /**
236
     * Initialise the tokenizer.
237
     *
238
     * Pre-checks the content to see if it looks minified.
239
     *
240
     * @param string                  $content The content to tokenize,
241
     * @param \Symplify\PHP7_CodeSniffer\Config $config  The config data for the run.
242
     * @param string                  $eolChar The EOL char used in the content.
243
     *
244
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
245
     * @throws TokenizerException If the file appears to be minified.
246
     */
247 View Code Duplication
    public function __construct($content, Config $config, $eolChar='\n')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
248
    {
249
        if ($this->isMinifiedContent($content, $eolChar) === true) {
250
            throw new TokenizerException('File appears to be minified and cannot be processed');
251
        }
252
253
        return parent::__construct($content, $config, $eolChar);
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
254
255
    }//end __construct()
256
257
258
    /**
259
     * Creates an array of tokens when given some PHP code.
260
     *
261
     * Starts by using token_get_all() but does a lot of extra processing
262
     * to insert information about the context of the token.
263
     *
264
     * @param string $string The string to tokenize.
265
     *
266
     * @return array
267
     */
268
    public function tokenize($string)
269
    {
270
        if (PHP_CodeSniffer_VERBOSITY > 1) {
271
            echo "\t*** START JS TOKENIZING ***".PHP_EOL;
272
        }
273
274
        $maxTokenLength = 0;
275
        foreach ($this->tokenValues as $token => $values) {
276
            if (strlen($token) > $maxTokenLength) {
277
                $maxTokenLength = strlen($token);
278
            }
279
        }
280
281
        $tokens          = array();
282
        $inString        = '';
283
        $stringChar      = null;
284
        $inComment       = '';
285
        $buffer          = '';
286
        $preStringBuffer = '';
287
        $cleanBuffer     = false;
288
289
        $commentTokenizer = new Comment();
290
291
        $tokens[] = array(
292
                     'code'    => T_OPEN_TAG,
293
                     'type'    => 'T_OPEN_TAG',
294
                     'content' => '',
295
                    );
296
297
        // Convert newlines to single characters for ease of
298
        // processing. We will change them back later.
299
        $string = str_replace($this->eolChar, "\n", $string);
300
301
        $chars    = str_split($string);
302
        $numChars = count($chars);
303
        for ($i = 0; $i < $numChars; $i++) {
304
            $char = $chars[$i];
305
306
            if (PHP_CodeSniffer_VERBOSITY > 1) {
307
                $content       = Util\Common::prepareForOutput($char);
308
                $bufferContent = Util\Common::prepareForOutput($buffer);
309
310
                if ($inString !== '') {
311
                    echo "\t";
312
                }
313
314
                if ($inComment !== '') {
315
                    echo "\t";
316
                }
317
318
                echo "\tProcess char $i => $content (buffer: $bufferContent)".PHP_EOL;
319
            }//end if
320
321
            if ($inString === '' && $inComment === '' && $buffer !== '') {
322
                // If the buffer only has whitespace and we are about to
323
                // add a character, store the whitespace first.
324 View Code Duplication
                if (trim($char) !== '' && trim($buffer) === '') {
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...
325
                    $tokens[] = array(
326
                                 'code'    => T_WHITESPACE,
327
                                 'type'    => 'T_WHITESPACE',
328
                                 'content' => str_replace("\n", $this->eolChar, $buffer),
329
                                );
330
331
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
332
                        $content = Util\Common::prepareForOutput($buffer);
333
                        echo "\t=> Added token T_WHITESPACE ($content)".PHP_EOL;
334
                    }
335
336
                    $buffer = '';
337
                }
338
339
                // If the buffer is not whitespace and we are about to
340
                // add a whitespace character, store the content first.
341
                if ($inString === ''
342
                    && $inComment === ''
343
                    && trim($char) === ''
344
                    && trim($buffer) !== ''
345
                ) {
346
                    $tokens[] = array(
347
                                 'code'    => T_STRING,
348
                                 'type'    => 'T_STRING',
349
                                 'content' => str_replace("\n", $this->eolChar, $buffer),
350
                                );
351
352
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
353
                        $content = Util\Common::prepareForOutput($buffer);
354
                        echo "\t=> Added token T_STRING ($content)".PHP_EOL;
355
                    }
356
357
                    $buffer = '';
358
                }
359
            }//end if
360
361
            // Process strings.
362
            if ($inComment === '' && isset($this->stringTokens[$char]) === true) {
363
                if ($inString === $char) {
364
                    // This could be the end of the string, but make sure it
365
                    // is not escaped first.
366
                    $escapes = 0;
367
                    for ($x = ($i - 1); $x >= 0; $x--) {
368
                        if ($chars[$x] !== '\\') {
369
                            break;
370
                        }
371
372
                        $escapes++;
373
                    }
374
375
                    if ($escapes === 0 || ($escapes % 2) === 0) {
376
                        // There is an even number escape chars,
377
                        // so this is not escaped, it is the end of the string.
378
                        $tokens[] = array(
379
                                     'code'    => T_CONSTANT_ENCAPSED_STRING,
380
                                     'type'    => 'T_CONSTANT_ENCAPSED_STRING',
381
                                     'content' => str_replace("\n", $this->eolChar, $buffer).$char,
382
                                    );
383
384
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
385
                            echo "\t\t* found end of string *".PHP_EOL;
386
                            $content = Util\Common::prepareForOutput($buffer.$char);
387
                            echo "\t=> Added token T_CONSTANT_ENCAPSED_STRING ($content)".PHP_EOL;
388
                        }
389
390
                        $buffer          = '';
391
                        $preStringBuffer = '';
392
                        $inString        = '';
393
                        $stringChar      = null;
394
                        continue;
395
                    }//end if
396
                } else if ($inString === '') {
397
                    $inString        = $char;
398
                    $stringChar      = $i;
399
                    $preStringBuffer = $buffer;
400
401
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
402
                        echo "\t\t* looking for string closer *".PHP_EOL;
403
                    }
404
                }//end if
405
            }//end if
406
407
            if ($inString !== '' && $char === "\n") {
408
                // Unless this newline character is escaped, the string did not
409
                // end before the end of the line, which means it probably
410
                // wasn't a string at all (maybe a regex).
411
                if ($chars[($i - 1)] !== '\\') {
412
                    $i      = $stringChar;
413
                    $buffer = $preStringBuffer;
414
                    $preStringBuffer = '';
415
                    $inString        = '';
416
                    $stringChar      = null;
417
                    $char            = $chars[$i];
418
419
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
420
                        echo "\t\t* found newline before end of string, bailing *".PHP_EOL;
421
                    }
422
                }
423
            }
424
425
            $buffer .= $char;
426
427
            // We don't look for special tokens inside strings,
428
            // so if we are in a string, we can continue here now
429
            // that the current char is in the buffer.
430
            if ($inString !== '') {
431
                continue;
432
            }
433
434
            // Special case for T_DIVIDE which can actually be
435
            // the start of a regular expression.
436
            if ($buffer === $char && $char === '/' && $chars[($i + 1)] !== '*') {
437
                $regex = $this->getRegexToken(
438
                    $i,
439
                    $string,
440
                    $chars,
0 ignored issues
show
Documentation introduced by
$chars is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
441
                    $tokens,
0 ignored issues
show
Documentation introduced by
$tokens is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
442
                    $this->eolChar
0 ignored issues
show
Unused Code introduced by
The call to JS::getRegexToken() has too many arguments starting with $this->eolChar.

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

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

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

Loading history...
443
                );
444
445
                if ($regex !== null) {
446
                    $tokens[] = array(
447
                                 'code'    => T_REGULAR_EXPRESSION,
448
                                 'type'    => 'T_REGULAR_EXPRESSION',
449
                                 'content' => $regex['content'],
450
                                );
451
452
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
453
                        $content = Util\Common::prepareForOutput($regex['content']);
454
                        echo "\t=> Added token T_REGULAR_EXPRESSION ($content)".PHP_EOL;
455
                    }
456
457
                    $i           = $regex['end'];
458
                    $buffer      = '';
459
                    $cleanBuffer = false;
460
                    continue;
461
                }//end if
462
            }//end if
463
464
            // Check for known tokens, but ignore tokens found that are not at
465
            // the end of a string, like FOR and this.FORmat.
466
            if (isset($this->tokenValues[strtolower($buffer)]) === true
467
                && (preg_match('|[a-zA-z0-9_]|', $char) === 0
468
                || isset($chars[($i + 1)]) === false
469
                || preg_match('|[a-zA-z0-9_]|', $chars[($i + 1)]) === 0)
470
            ) {
471
                $matchedToken    = false;
472
                $lookAheadLength = ($maxTokenLength - strlen($buffer));
473
474
                if ($lookAheadLength > 0) {
475
                    // The buffer contains a token type, but we need
476
                    // to look ahead at the next chars to see if this is
477
                    // actually part of a larger token. For example,
478
                    // FOR and FOREACH.
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
479
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
480
                        echo "\t\t* buffer possibly contains token, looking ahead $lookAheadLength chars *".PHP_EOL;
481
                    }
482
483
                    $charBuffer = $buffer;
484
                    for ($x = 1; $x <= $lookAheadLength; $x++) {
485
                        if (isset($chars[($i + $x)]) === false) {
486
                            break;
487
                        }
488
489
                        $charBuffer .= $chars[($i + $x)];
490
491
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
492
                            $content = Util\Common::prepareForOutput($charBuffer);
493
                            echo "\t\t=> Looking ahead $x chars => $content".PHP_EOL;
494
                        }
495
496
                        if (isset($this->tokenValues[strtolower($charBuffer)]) === true) {
497
                            // We've found something larger that matches
498
                            // so we can ignore this char. Except for 1 very specific
499
                            // case where a comment like /**/ needs to tokenize as
500
                            // T_COMMENT and not T_DOC_COMMENT.
501
                            $oldType = $this->tokenValues[strtolower($buffer)];
502
                            $newType = $this->tokenValues[strtolower($charBuffer)];
503
                            if ($oldType === 'T_COMMENT'
504
                                && $newType === 'T_DOC_COMMENT'
505
                                && $chars[($i + $x + 1)] === '/'
506
                            ) {
507
                                if (PHP_CodeSniffer_VERBOSITY > 1) {
508
                                    echo "\t\t* look ahead ignored T_DOC_COMMENT, continuing *".PHP_EOL;
509
                                }
510
                            } else {
511
                                if (PHP_CodeSniffer_VERBOSITY > 1) {
512
                                    echo "\t\t* look ahead found more specific token ($newType), ignoring $i *".PHP_EOL;
513
                                }
514
515
                                $matchedToken = true;
516
                                break;
517
                            }
518
                        }//end if
519
                    }//end for
520
                }//end if
521
522
                if ($matchedToken === false) {
523
                    if (PHP_CodeSniffer_VERBOSITY > 1 && $lookAheadLength > 0) {
524
                        echo "\t\t* look ahead found nothing *".PHP_EOL;
525
                    }
526
527
                    $value    = $this->tokenValues[strtolower($buffer)];
528
                    $tokens[] = array(
529
                                 'code'    => constant($value),
530
                                 'type'    => $value,
531
                                 'content' => $buffer,
532
                                );
533
534
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
535
                        $content = Util\Common::prepareForOutput($buffer);
536
                        echo "\t=> Added token $value ($content)".PHP_EOL;
537
                    }
538
539
                    $cleanBuffer = true;
540
                }//end if
541
            } else if (isset($this->tokenValues[strtolower($char)]) === true) {
542
                // No matter what token we end up using, we don't
543
                // need the content in the buffer any more because we have
544
                // found a valid token.
545
                $newContent = substr(str_replace("\n", $this->eolChar, $buffer), 0, -1);
546
                if ($newContent !== '') {
547
                    $tokens[] = array(
548
                                 'code'    => T_STRING,
549
                                 'type'    => 'T_STRING',
550
                                 'content' => $newContent,
551
                                );
552
553
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
554
                        $content = Util\Common::prepareForOutput(substr($buffer, 0, -1));
555
                        echo "\t=> Added token T_STRING ($content)".PHP_EOL;
556
                    }
557
                }
558
559
                if (PHP_CodeSniffer_VERBOSITY > 1) {
560
                    echo "\t\t* char is token, looking ahead ".($maxTokenLength - 1).' chars *'.PHP_EOL;
561
                }
562
563
                // The char is a token type, but we need to look ahead at the
564
                // next chars to see if this is actually part of a larger token.
565
                // For example, = and ===.
566
                $charBuffer   = $char;
567
                $matchedToken = false;
568
                for ($x = 1; $x <= $maxTokenLength; $x++) {
569
                    if (isset($chars[($i + $x)]) === false) {
570
                        break;
571
                    }
572
573
                    $charBuffer .= $chars[($i + $x)];
574
575
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
576
                        $content = Util\Common::prepareForOutput($charBuffer);
577
                        echo "\t\t=> Looking ahead $x chars => $content".PHP_EOL;
578
                    }
579
580
                    if (isset($this->tokenValues[strtolower($charBuffer)]) === true) {
581
                        // We've found something larger that matches
582
                        // so we can ignore this char.
583
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
584
                            $type = $this->tokenValues[strtolower($charBuffer)];
585
                            echo "\t\t* look ahead found more specific token ($type), ignoring $i *".PHP_EOL;
586
                        }
587
588
                        $matchedToken = true;
589
                        break;
590
                    }
591
                }//end for
592
593
                if ($matchedToken === false) {
594
                    $value    = $this->tokenValues[strtolower($char)];
595
                    $tokens[] = array(
596
                                 'code'    => constant($value),
597
                                 'type'    => $value,
598
                                 'content' => $char,
599
                                );
600
601
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
602
                        echo "\t\t* look ahead found nothing *".PHP_EOL;
603
                        $content = Util\Common::prepareForOutput($char);
604
                        echo "\t=> Added token $value ($content)".PHP_EOL;
605
                    }
606
607
                    $cleanBuffer = true;
608
                } else {
609
                    $buffer = $char;
610
                }//end if
611
            }//end if
612
613
            // Keep track of content inside comments.
614
            if ($inComment === ''
615
                && array_key_exists($buffer, $this->commentTokens) === true
616
            ) {
617
                // This is not really a comment if the content
618
                // looks like \// (i.e., it is escaped).
619
                if (isset($chars[($i - 2)]) === true && $chars[($i - 2)] === '\\') {
620
                    $lastToken   = array_pop($tokens);
621
                    $lastContent = $lastToken['content'];
622 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...
623
                        $value   = $this->tokenValues[strtolower($lastContent)];
624
                        $content = Util\Common::prepareForOutput($lastContent);
625
                        echo "\t=> Removed token $value ($content)".PHP_EOL;
626
                    }
627
628
                    $lastChars    = str_split($lastContent);
629
                    $lastNumChars = count($lastChars);
630
                    for ($x = 0; $x < $lastNumChars; $x++) {
631
                        $lastChar = $lastChars[$x];
632
                        $value    = $this->tokenValues[strtolower($lastChar)];
633
                        $tokens[] = array(
634
                                     'code'    => constant($value),
635
                                     'type'    => $value,
636
                                     'content' => $lastChar,
637
                                    );
638
639
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
640
                            $content = Util\Common::prepareForOutput($lastChar);
641
                            echo "\t=> Added token $value ($content)".PHP_EOL;
642
                        }
643
                    }
644
                } else {
645
                    // We have started a comment.
646
                    $inComment = $buffer;
647
648
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
649
                        echo "\t\t* looking for end of comment *".PHP_EOL;
650
                    }
651
                }//end if
652
            } else if ($inComment !== '') {
653
                if ($this->commentTokens[$inComment] === null) {
654
                    // Comment ends at the next newline.
655
                    if (strpos($buffer, "\n") !== false) {
656
                        $inComment = '';
657
                    }
658
                } else {
659
                    if ($this->commentTokens[$inComment] === $buffer) {
660
                        $inComment = '';
661
                    }
662
                }
663
664
                if (PHP_CodeSniffer_VERBOSITY > 1) {
665
                    if ($inComment === '') {
666
                        echo "\t\t* found end of comment *".PHP_EOL;
667
                    }
668
                }
669
670 View Code Duplication
                if ($inComment === '' && $cleanBuffer === 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...
671
                    $tokens[] = array(
672
                                 'code'    => T_STRING,
673
                                 'type'    => 'T_STRING',
674
                                 'content' => str_replace("\n", $this->eolChar, $buffer),
675
                                );
676
677
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
678
                        $content = Util\Common::prepareForOutput($buffer);
679
                        echo "\t=> Added token T_STRING ($content)".PHP_EOL;
680
                    }
681
682
                    $buffer = '';
683
                }
684
            }//end if
685
686
            if ($cleanBuffer === true) {
687
                $buffer      = '';
688
                $cleanBuffer = false;
689
            }
690
        }//end for
691
692
        if (empty($buffer) === false) {
693
            // Buffer contains whitespace from the end of the file.
694
            $tokens[] = array(
695
                         'code'    => T_WHITESPACE,
696
                         'type'    => 'T_WHITESPACE',
697
                         'content' => str_replace("\n", $this->eolChar, $buffer),
698
                        );
699
700
            if (PHP_CodeSniffer_VERBOSITY > 1) {
701
                $content = Util\Common::prepareForOutput($buffer);
702
                echo "\t=> Added token T_WHITESPACE ($content)".PHP_EOL;
703
            }
704
        }
705
706
        $tokens[] = array(
707
                     'code'    => T_CLOSE_TAG,
708
                     'type'    => 'T_CLOSE_TAG',
709
                     'content' => '',
710
                    );
711
712
        /*
713
            Now that we have done some basic tokenizing, we need to
714
            modify the tokens to join some together and split some apart
715
            so they match what the PHP tokenizer does.
716
        */
717
718
        $finalTokens = array();
719
        $newStackPtr = 0;
720
        $numTokens   = count($tokens);
721
        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
722
            $token = $tokens[$stackPtr];
723
724
            /*
725
                Look for comments and join the tokens together.
726
            */
727
728
            if ($token['code'] === T_COMMENT || $token['code'] === T_DOC_COMMENT) {
729
                $newContent   = '';
730
                $tokenContent = $token['content'];
731
                $endContent   = $this->commentTokens[$tokenContent];
732
                while ($tokenContent !== $endContent) {
733
                    if ($endContent === null
734
                        && strpos($tokenContent, $this->eolChar) !== false
735
                    ) {
736
                        // A null end token means the comment ends at the end of
737
                        // the line so we look for newlines and split the token.
738
                        $tokens[$stackPtr]['content'] = substr(
739
                            $tokenContent,
740
                            (strpos($tokenContent, $this->eolChar) + strlen($this->eolChar))
741
                        );
742
743
                        $tokenContent = substr(
744
                            $tokenContent,
745
                            0,
746
                            (strpos($tokenContent, $this->eolChar) + strlen($this->eolChar))
747
                        );
748
749
                        // If the substr failed, skip the token as the content
750
                        // will now be blank.
751
                        if ($tokens[$stackPtr]['content'] !== false
752
                            && $tokens[$stackPtr]['content'] !== ''
753
                        ) {
754
                            $stackPtr--;
755
                        }
756
757
                        break;
758
                    }//end if
759
760
                    $stackPtr++;
761
                    $newContent .= $tokenContent;
762
                    if (isset($tokens[$stackPtr]) === false) {
763
                        break;
764
                    }
765
766
                    $tokenContent = $tokens[$stackPtr]['content'];
767
                }//end while
768
769
                if ($token['code'] === T_DOC_COMMENT) {
770
                    $commentTokens = $commentTokenizer->tokenizeString($newContent.$tokenContent, $this->eolChar, $newStackPtr);
771
                    foreach ($commentTokens as $commentToken) {
772
                        $finalTokens[$newStackPtr] = $commentToken;
773
                        $newStackPtr++;
774
                    }
775
776
                    continue;
777
                } else {
778
                    // Save the new content in the current token so
779
                    // the code below can chop it up on newlines.
780
                    $token['content'] = $newContent.$tokenContent;
781
                }
782
            }//end if
783
784
            /*
785
                If this token has newlines in its content, split each line up
786
                and create a new token for each line. We do this so it's easier
787
                to ascertain where errors occur on a line.
788
                Note that $token[1] is the token's content.
789
            */
790
791
            if (strpos($token['content'], $this->eolChar) !== false) {
792
                $tokenLines = explode($this->eolChar, $token['content']);
793
                $numLines   = count($tokenLines);
794
795
                for ($i = 0; $i < $numLines; $i++) {
796
                    $newToken['content'] = $tokenLines[$i];
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...
797 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...
798
                        if ($tokenLines[$i] === '') {
799
                            break;
800
                        }
801
                    } else {
802
                        $newToken['content'] .= $this->eolChar;
0 ignored issues
show
Bug introduced by
The variable $newToken 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...
803
                    }
804
805
                    $newToken['type']          = $token['type'];
806
                    $newToken['code']          = $token['code'];
807
                    $finalTokens[$newStackPtr] = $newToken;
808
                    $newStackPtr++;
809
                }
810
            } else {
811
                $finalTokens[$newStackPtr] = $token;
812
                $newStackPtr++;
813
            }//end if
814
815
            // Convert numbers, including decimals.
816
            if ($token['code'] === T_STRING
817
                || $token['code'] === T_OBJECT_OPERATOR
818
            ) {
819
                $newContent  = '';
820
                $oldStackPtr = $stackPtr;
821
                while (preg_match('|^[0-9\.]+$|', $tokens[$stackPtr]['content']) !== 0) {
822
                    $newContent .= $tokens[$stackPtr]['content'];
823
                    $stackPtr++;
824
                }
825
826
                if ($newContent !== '' && $newContent !== '.') {
827
                    $finalTokens[($newStackPtr - 1)]['content'] = $newContent;
828
                    if (ctype_digit($newContent) === true) {
829
                        $finalTokens[($newStackPtr - 1)]['code'] = constant('T_LNUMBER');
830
                        $finalTokens[($newStackPtr - 1)]['type'] = 'T_LNUMBER';
831
                    } else {
832
                        $finalTokens[($newStackPtr - 1)]['code'] = constant('T_DNUMBER');
833
                        $finalTokens[($newStackPtr - 1)]['type'] = 'T_DNUMBER';
834
                    }
835
836
                    $stackPtr--;
837
                    continue;
838
                } else {
839
                    $stackPtr = $oldStackPtr;
840
                }
841
            }//end if
842
843
            // Convert the token after an object operator into a string, in most cases.
844
            if ($token['code'] === T_OBJECT_OPERATOR) {
845
                for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
846
                    if (isset(Util\Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
847
                        continue;
848
                    }
849
850
                    if ($tokens[$i]['code'] !== T_PROTOTYPE
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $tokens[$i]['code'] (integer) and T_PROTOTYPE (string) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
851
                        && $tokens[$i]['code'] !== T_LNUMBER
852
                        && $tokens[$i]['code'] !== T_DNUMBER
853
                    ) {
854
                        $tokens[$i]['code'] = T_STRING;
855
                        $tokens[$i]['type'] = 'T_STRING';
856
                    }
857
858
                    break;
859
                }
860
            }
861
        }//end for
862
863
        if (PHP_CodeSniffer_VERBOSITY > 1) {
864
            echo "\t*** END TOKENIZING ***".PHP_EOL;
865
        }
866
867
        return $finalTokens;
868
869
    }//end tokenize()
870
871
872
    /**
873
     * Tokenizes a regular expression if one is found.
874
     *
875
     * If a regular expression is not found, NULL is returned.
876
     *
877
     * @param string $char   The index of the possible regex start character.
878
     * @param string $string The complete content of the string being tokenized.
879
     * @param string $chars  An array of characters being tokenized.
880
     * @param string $tokens The current array of tokens found in the string.
881
     *
882
     * @return void
883
     */
884
    public function getRegexToken($char, $string, $chars, $tokens)
885
    {
886
        $beforeTokens = array(
887
                         T_EQUAL               => true,
888
                         T_OPEN_PARENTHESIS    => true,
889
                         T_OPEN_SQUARE_BRACKET => true,
890
                         T_RETURN              => true,
891
                         T_BOOLEAN_OR          => true,
892
                         T_BOOLEAN_AND         => true,
893
                         T_BITWISE_OR          => true,
894
                         T_BITWISE_AND         => true,
895
                         T_COMMA               => true,
896
                         T_COLON               => true,
897
                         T_TYPEOF              => true,
898
                         T_INLINE_THEN         => true,
899
                         T_INLINE_ELSE         => true,
900
                        );
901
902
        $afterTokens = array(
903
                        ','            => true,
904
                        ')'            => true,
905
                        ']'            => true,
906
                        ';'            => true,
907
                        ' '            => true,
908
                        '.'            => true,
909
                        ':'            => true,
910
                        $this->eolChar => true,
911
                       );
912
913
        // Find the last non-whitespace token that was added
914
        // to the tokens array.
915
        $numTokens = count($tokens);
916 View Code Duplication
        for ($prev = ($numTokens - 1); $prev >= 0; $prev--) {
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...
917
            if (isset(Util\Tokens::$emptyTokens[$tokens[$prev]['code']]) === false) {
918
                break;
919
            }
920
        }
921
922
        if (isset($beforeTokens[$tokens[$prev]['code']]) === false) {
923
            return null;
924
        }
925
926
        // This is probably a regular expression, so look for the end of it.
927
        if (PHP_CodeSniffer_VERBOSITY > 1) {
928
            echo "\t* token possibly starts a regular expression *".PHP_EOL;
929
        }
930
931
        $numChars = count($chars);
932
        for ($next = ($char + 1); $next < $numChars; $next++) {
933
            if ($chars[$next] === '/') {
934
                // Just make sure this is not escaped first.
935
                if ($chars[($next - 1)] !== '\\') {
936
                    // In the simple form: /.../ so we found the end.
937
                    break;
938
                } else if ($chars[($next - 2)] === '\\') {
939
                    // In the form: /...\\/ so we found the end.
940
                    break;
941
                }
942 View Code Duplication
            } else {
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...
943
                $possibleEolChar = substr($string, $next, strlen($this->eolChar));
944
                if ($possibleEolChar === $this->eolChar) {
945
                    // This is the last token on the line and regular
946
                    // expressions need to be defined on a single line,
947
                    // so this is not a regular expression.
948
                    break;
949
                }
950
            }
951
        }
952
953
        if ($chars[$next] !== '/') {
954
            if (PHP_CodeSniffer_VERBOSITY > 1) {
955
                echo "\t* could not find end of regular expression *".PHP_EOL;
956
            }
957
958
            return null;
959
        }
960
961
        while (preg_match('|[a-zA-Z]|', $chars[($next + 1)]) !== 0) {
962
            // The token directly after the end of the regex can
963
            // be modifiers like global and case insensitive
964
            // (.e.g, /pattern/gi).
965
            $next++;
966
        }
967
968
        $regexEnd = $next;
969
        if (PHP_CodeSniffer_VERBOSITY > 1) {
970
            echo "\t* found end of regular expression at token $regexEnd *".PHP_EOL;
971
        }
972
973
        for ($next = ($next + 1); $next < $numChars; $next++) {
974 View Code Duplication
            if ($chars[$next] !== ' ') {
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...
975
                break;
976
            } else {
977
                $possibleEolChar = substr($string, $next, strlen($this->eolChar));
978
                if ($possibleEolChar === $this->eolChar) {
979
                    // This is the last token on the line.
980
                    break;
981
                }
982
            }
983
        }
984
985
        if (isset($afterTokens[$chars[$next]]) === false) {
986
            if (PHP_CodeSniffer_VERBOSITY > 1) {
987
                echo "\t* tokens after regular expression do not look correct *".PHP_EOL;
988
            }
989
990
            return null;
991
        }
992
993
        // This is a regular expression, so join all the tokens together.
994
        $content = '';
995
        for ($x = $char; $x <= $regexEnd; $x++) {
996
            $content .= $chars[$x];
997
        }
998
999
        $token = array(
1000
                  'start'   => $char,
1001
                  'end'     => $regexEnd,
1002
                  'content' => $content,
1003
                 );
1004
1005
        return $token;
1006
1007
    }//end getRegexToken()
1008
1009
1010
    /**
1011
     * Performs additional processing after main tokenizing.
1012
     *
1013
     * This additional processing looks for properties, closures, labels and objects.
1014
     *
1015
     * @return void
1016
     */
1017
    public function processAdditional()
1018
    {
1019
        if (PHP_CodeSniffer_VERBOSITY > 1) {
1020
            echo "\t*** START ADDITIONAL JS PROCESSING ***".PHP_EOL;
1021
        }
1022
1023
        $numTokens  = count($this->tokens);
1024
        $classStack = array();
1025
1026
        for ($i = 0; $i < $numTokens; $i++) {
1027 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...
1028
                $type    = $this->tokens[$i]['type'];
1029
                $content = Util\Common::prepareForOutput($this->tokens[$i]['content']);
1030
1031
                echo str_repeat("\t", count($classStack));
1032
                echo "\tProcess token $i: $type => $content".PHP_EOL;
1033
            }
1034
1035
            // Looking for functions that are actually closures.
1036
            if ($this->tokens[$i]['code'] === T_FUNCTION && isset($this->tokens[$i]['scope_opener']) === true) {
1037 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...
1038
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) {
1039
                        break;
1040
                    }
1041
                }
1042
1043
                if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
1044
                    $this->tokens[$i]['code'] = T_CLOSURE;
1045
                    $this->tokens[$i]['type'] = 'T_CLOSURE';
1046
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1047
                        $line = $this->tokens[$i]['line'];
1048
                        echo str_repeat("\t", count($classStack));
1049
                        echo "\t* token $i on line $line changed from T_FUNCTION to T_CLOSURE".PHP_EOL;
1050
                    }
1051
1052
                    for ($x = ($this->tokens[$i]['scope_opener'] + 1); $x < $this->tokens[$i]['scope_closer']; $x++) {
1053
                        if (isset($this->tokens[$x]['conditions'][$i]) === false) {
1054
                            continue;
1055
                        }
1056
1057
                        $this->tokens[$x]['conditions'][$i] = T_CLOSURE;
1058
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
1059
                            $type = $this->tokens[$x]['type'];
1060
                            echo str_repeat("\t", count($classStack));
1061
                            echo "\t\t* cleaned $x ($type) *".PHP_EOL;
1062
                        }
1063
                    }
1064
                }//end if
1065
1066
                continue;
1067
            } else if ($this->tokens[$i]['code'] === T_OPEN_CURLY_BRACKET
1068
                && isset($this->tokens[$i]['scope_condition']) === false
1069
            ) {
1070
                $classStack[] = $i;
1071
1072
                $closer = $this->tokens[$i]['bracket_closer'];
1073
                $this->tokens[$i]['code']      = T_OBJECT;
1074
                $this->tokens[$i]['type']      = 'T_OBJECT';
1075
                $this->tokens[$closer]['code'] = T_CLOSE_OBJECT;
1076
                $this->tokens[$closer]['type'] = 'T_CLOSE_OBJECT';
1077
1078 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...
1079
                    echo str_repeat("\t", count($classStack));
1080
                    echo "\t* token $i converted from T_OPEN_CURLY_BRACKET to T_OBJECT *".PHP_EOL;
1081
                    echo str_repeat("\t", count($classStack));
1082
                    echo "\t* token $closer converted from T_CLOSE_CURLY_BRACKET to T_CLOSE_OBJECT *".PHP_EOL;
1083
                }
1084
1085
                for ($x = ($i + 1); $x < $closer; $x++) {
1086
                    $this->tokens[$x]['conditions'][$i] = T_OBJECT;
1087
                    ksort($this->tokens[$x]['conditions'], SORT_NUMERIC);
1088
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1089
                        $type = $this->tokens[$x]['type'];
1090
                        echo str_repeat("\t", count($classStack));
1091
                        echo "\t\t* added T_OBJECT condition to $x ($type) *".PHP_EOL;
1092
                    }
1093
                }
1094
            } else if ($this->tokens[$i]['code'] === T_CLOSE_OBJECT) {
1095
                $opener = array_pop($classStack);
0 ignored issues
show
Unused Code introduced by
$opener 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...
1096
            } else if ($this->tokens[$i]['code'] === T_COLON) {
1097
                // If it is a scope opener, it belongs to a
1098
                // DEFAULT or CASE statement.
1099
                if (isset($this->tokens[$i]['scope_condition']) === true) {
1100
                    continue;
1101
                }
1102
1103
                // Make sure this is not part of an inline IF statement.
1104
                for ($x = ($i - 1); $x >= 0; $x--) {
1105
                    if ($this->tokens[$x]['code'] === T_INLINE_THEN) {
1106
                        $this->tokens[$i]['code'] = T_INLINE_ELSE;
1107
                        $this->tokens[$i]['type'] = 'T_INLINE_ELSE';
1108
1109
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
1110
                            echo str_repeat("\t", count($classStack));
1111
                            echo "\t* token $i converted from T_COLON to T_INLINE_THEN *".PHP_EOL;
1112
                        }
1113
1114
                        continue(2);
1115
                    } else if ($this->tokens[$x]['line'] < $this->tokens[$i]['line']) {
1116
                        break;
1117
                    }
1118
                }
1119
1120
                // The string to the left of the colon is either a property or label.
1121 View Code Duplication
                for ($label = ($i - 1); $label >= 0; $label--) {
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...
1122
                    if (isset(Util\Tokens::$emptyTokens[$this->tokens[$label]['code']]) === false) {
1123
                        break;
1124
                    }
1125
                }
1126
1127
                if ($this->tokens[$label]['code'] !== T_STRING
1128
                    && $this->tokens[$label]['code'] !== T_CONSTANT_ENCAPSED_STRING
1129
                ) {
1130
                    continue;
1131
                }
1132
1133
                if (empty($classStack) === false) {
1134
                    $this->tokens[$label]['code'] = T_PROPERTY;
1135
                    $this->tokens[$label]['type'] = 'T_PROPERTY';
1136
1137
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1138
                        echo str_repeat("\t", count($classStack));
1139
                        echo "\t* token $label converted from T_STRING to T_PROPERTY *".PHP_EOL;
1140
                    }
1141
                } else {
1142
                    $this->tokens[$label]['code'] = T_LABEL;
1143
                    $this->tokens[$label]['type'] = 'T_LABEL';
1144
1145
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1146
                        echo str_repeat("\t", count($classStack));
1147
                        echo "\t* token $label converted from T_STRING to T_LABEL *".PHP_EOL;
1148
                    }
1149
                }//end if
1150
            }//end if
1151
        }//end for
1152
1153
        if (PHP_CodeSniffer_VERBOSITY > 1) {
1154
            echo "\t*** END ADDITIONAL JS PROCESSING ***".PHP_EOL;
1155
        }
1156
1157
    }//end processAdditional()
1158
1159
1160
}//end class
1161