~ubuntu-branches/ubuntu/utopic/php-codesniffer/utopic-proposed

« back to all changes in this revision

Viewing changes to PHP_CodeSniffer-1.5.3/CodeSniffer/Tokenizers/PHP.php

  • Committer: Package Import Robot
  • Author(s): David Prévot
  • Date: 2014-07-21 14:42:41 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20140721144241-g4orlcuk4jzn9mhs
Tags: 1.5.3-1
* Team upload
* Focus on stable release
* Update copyright
* Bump standards version to 3.9.5
* Update Homepage
* Use ${phppear:…} instead of hardcoding them
* Run tests in dh_auto_test
* Update patch with gbp pq
* Simplify configuration installation
* Edit package.xml to move script
* Add DEP-8 tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Tokenizes PHP code.
 
4
 *
 
5
 * PHP version 5
 
6
 *
 
7
 * @category  PHP
 
8
 * @package   PHP_CodeSniffer
 
9
 * @author    Greg Sherwood <gsherwood@squiz.net>
 
10
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 
11
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 
12
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 
13
 */
 
14
 
 
15
/**
 
16
 * Tokenizes PHP code.
 
17
 *
 
18
 * @category  PHP
 
19
 * @package   PHP_CodeSniffer
 
20
 * @author    Greg Sherwood <gsherwood@squiz.net>
 
21
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 
22
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 
23
 * @version   Release: 1.5.3
 
24
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 
25
 */
 
26
class PHP_CodeSniffer_Tokenizers_PHP
 
27
{
 
28
 
 
29
    /**
 
30
     * A list of tokens that are allowed to open a scope.
 
31
     *
 
32
     * This array also contains information about what kind of token the scope
 
33
     * opener uses to open and close the scope, if the token strictly requires
 
34
     * an opener, if the token can share a scope closer, and who it can be shared
 
35
     * with. An example of a token that shares a scope closer is a CASE scope.
 
36
     *
 
37
     * @var array
 
38
     */
 
39
    public $scopeOpeners = array(
 
40
                            T_IF            => array(
 
41
                                                'start'  => array(
 
42
                                                             T_OPEN_CURLY_BRACKET,
 
43
                                                             T_COLON,
 
44
                                                            ),
 
45
                                                'end'    => array(
 
46
                                                             T_CLOSE_CURLY_BRACKET,
 
47
                                                             T_ENDIF,
 
48
                                                             T_ELSE,
 
49
                                                             T_ELSEIF,
 
50
                                                            ),
 
51
                                                'strict' => false,
 
52
                                                'shared' => false,
 
53
                                                'with'   => array(
 
54
                                                             T_ELSE,
 
55
                                                             T_ELSEIF,
 
56
                                                            ),
 
57
                                               ),
 
58
                            T_TRY           => array(
 
59
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
60
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
61
                                                'strict' => true,
 
62
                                                'shared' => false,
 
63
                                                'with'   => array(),
 
64
                                               ),
 
65
                            T_CATCH         => array(
 
66
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
67
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
68
                                                'strict' => true,
 
69
                                                'shared' => false,
 
70
                                                'with'   => array(),
 
71
                                               ),
 
72
                            T_FINALLY       => array(
 
73
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
74
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
75
                                                'strict' => true,
 
76
                                                'shared' => false,
 
77
                                                'with'   => array(),
 
78
                                               ),
 
79
                            T_ELSE          => array(
 
80
                                                'start'  => array(
 
81
                                                             T_OPEN_CURLY_BRACKET,
 
82
                                                             T_COLON,
 
83
                                                            ),
 
84
                                                'end'    => array(
 
85
                                                             T_CLOSE_CURLY_BRACKET,
 
86
                                                             T_ENDIF,
 
87
                                                            ),
 
88
                                                'strict' => false,
 
89
                                                'shared' => false,
 
90
                                                'with'   => array(
 
91
                                                             T_IF,
 
92
                                                             T_ELSEIF,
 
93
                                                            ),
 
94
                                               ),
 
95
                            T_ELSEIF        => array(
 
96
                                                'start'  => array(
 
97
                                                             T_OPEN_CURLY_BRACKET,
 
98
                                                             T_COLON,
 
99
                                                            ),
 
100
                                                'end'    => array(
 
101
                                                             T_CLOSE_CURLY_BRACKET,
 
102
                                                             T_ENDIF,
 
103
                                                             T_ELSE,
 
104
                                                             T_ELSEIF,
 
105
                                                            ),
 
106
                                                'strict' => false,
 
107
                                                'shared' => false,
 
108
                                                'with'   => array(
 
109
                                                             T_IF,
 
110
                                                             T_ELSE,
 
111
                                                            ),
 
112
                                               ),
 
113
                            T_FOR           => array(
 
114
                                                'start'  => array(
 
115
                                                             T_OPEN_CURLY_BRACKET,
 
116
                                                             T_COLON,
 
117
                                                            ),
 
118
                                                'end'    => array(
 
119
                                                             T_CLOSE_CURLY_BRACKET,
 
120
                                                             T_ENDFOR,
 
121
                                                            ),
 
122
                                                'strict' => false,
 
123
                                                'shared' => false,
 
124
                                                'with'   => array(),
 
125
                                               ),
 
126
                            T_FOREACH       => array(
 
127
                                                'start'  => array(
 
128
                                                             T_OPEN_CURLY_BRACKET,
 
129
                                                             T_COLON,
 
130
                                                            ),
 
131
                                                'end'    => array(
 
132
                                                             T_CLOSE_CURLY_BRACKET,
 
133
                                                             T_ENDFOREACH,
 
134
                                                            ),
 
135
                                                'strict' => false,
 
136
                                                'shared' => false,
 
137
                                                'with'   => array(),
 
138
                                               ),
 
139
                            T_INTERFACE     => array(
 
140
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
141
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
142
                                                'strict' => true,
 
143
                                                'shared' => false,
 
144
                                                'with'   => array(),
 
145
                                               ),
 
146
                            T_FUNCTION      => array(
 
147
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
148
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
149
                                                'strict' => true,
 
150
                                                'shared' => false,
 
151
                                                'with'   => array(),
 
152
                                               ),
 
153
                            T_CLASS         => array(
 
154
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
155
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
156
                                                'strict' => true,
 
157
                                                'shared' => false,
 
158
                                                'with'   => array(),
 
159
                                               ),
 
160
                            T_TRAIT         => array(
 
161
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
162
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
163
                                                'strict' => true,
 
164
                                                'shared' => false,
 
165
                                                'with'   => array(),
 
166
                                               ),
 
167
                            T_NAMESPACE     => array(
 
168
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
169
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
170
                                                'strict' => false,
 
171
                                                'shared' => false,
 
172
                                                'with'   => array(),
 
173
                                               ),
 
174
                            T_WHILE         => array(
 
175
                                                'start'  => array(
 
176
                                                             T_OPEN_CURLY_BRACKET,
 
177
                                                             T_COLON,
 
178
                                                            ),
 
179
                                                'end'    => array(
 
180
                                                             T_CLOSE_CURLY_BRACKET,
 
181
                                                             T_ENDWHILE,
 
182
                                                            ),
 
183
                                                'strict' => false,
 
184
                                                'shared' => false,
 
185
                                                'with'   => array(),
 
186
                                               ),
 
187
                            T_DO            => array(
 
188
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
189
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
190
                                                'strict' => true,
 
191
                                                'shared' => false,
 
192
                                                'with'   => array(),
 
193
                                               ),
 
194
                            T_SWITCH        => array(
 
195
                                                'start'  => array(T_OPEN_CURLY_BRACKET),
 
196
                                                'end'    => array(T_CLOSE_CURLY_BRACKET),
 
197
                                                'strict' => true,
 
198
                                                'shared' => false,
 
199
                                                'with'   => array(),
 
200
                                               ),
 
201
                            T_CASE          => array(
 
202
                                                'start'  => array(
 
203
                                                             T_COLON,
 
204
                                                             T_SEMICOLON,
 
205
                                                            ),
 
206
                                                'end'    => array(
 
207
                                                             T_BREAK,
 
208
                                                             T_RETURN,
 
209
                                                             T_CONTINUE,
 
210
                                                             T_THROW,
 
211
                                                             T_EXIT,
 
212
                                                            ),
 
213
                                                'strict' => true,
 
214
                                                'shared' => true,
 
215
                                                'with'   => array(
 
216
                                                             T_DEFAULT,
 
217
                                                             T_CASE,
 
218
                                                             T_SWITCH,
 
219
                                                            ),
 
220
                                               ),
 
221
                            T_DEFAULT       => array(
 
222
                                                'start'  => array(
 
223
                                                             T_COLON,
 
224
                                                             T_SEMICOLON,
 
225
                                                            ),
 
226
                                                'end'    => array(
 
227
                                                             T_BREAK,
 
228
                                                             T_RETURN,
 
229
                                                             T_CONTINUE,
 
230
                                                             T_THROW,
 
231
                                                             T_EXIT,
 
232
                                                            ),
 
233
                                                'strict' => true,
 
234
                                                'shared' => true,
 
235
                                                'with'   => array(
 
236
                                                             T_CASE,
 
237
                                                             T_SWITCH,
 
238
                                                            ),
 
239
                                               ),
 
240
                            T_START_HEREDOC => array(
 
241
                                                'start'  => array(T_START_HEREDOC),
 
242
                                                'end'    => array(T_END_HEREDOC),
 
243
                                                'strict' => true,
 
244
                                                'shared' => false,
 
245
                                                'with'   => array(),
 
246
                                               ),
 
247
                           );
 
248
 
 
249
    /**
 
250
     * A list of tokens that end the scope.
 
251
     *
 
252
     * This array is just a unique collection of the end tokens
 
253
     * from the _scopeOpeners array. The data is duplicated here to
 
254
     * save time during parsing of the file.
 
255
     *
 
256
     * @var array
 
257
     */
 
258
    public $endScopeTokens = array(
 
259
                              T_CLOSE_CURLY_BRACKET,
 
260
                              T_BREAK,
 
261
                              T_END_HEREDOC,
 
262
                             );
 
263
 
 
264
 
 
265
    /**
 
266
     * Creates an array of tokens when given some PHP code.
 
267
     *
 
268
     * Starts by using token_get_all() but does a lot of extra processing
 
269
     * to insert information about the context of the token.
 
270
     *
 
271
     * @param string $string  The string to tokenize.
 
272
     * @param string $eolChar The EOL character to use for splitting strings.
 
273
     *
 
274
     * @return array
 
275
     */
 
276
    public function tokenizeString($string, $eolChar='\n')
 
277
    {
 
278
        $tokens      = @token_get_all($string);
 
279
        $finalTokens = array();
 
280
 
 
281
        $newStackPtr = 0;
 
282
        $numTokens   = count($tokens);
 
283
 
 
284
        $insideInlineIf = false;
 
285
 
 
286
        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
 
287
            $token        = $tokens[$stackPtr];
 
288
            $tokenIsArray = is_array($token);
 
289
 
 
290
            /*
 
291
                If we are using \r\n newline characters, the \r and \n are sometimes
 
292
                split over two tokens. This normally occurs after comments. We need
 
293
                to merge these two characters together so that our line endings are
 
294
                consistent for all lines.
 
295
            */
 
296
 
 
297
            if ($tokenIsArray === true && substr($token[1], -1) === "\r") {
 
298
                if (isset($tokens[($stackPtr + 1)]) === true
 
299
                    && is_array($tokens[($stackPtr + 1)]) === true
 
300
                    && $tokens[($stackPtr + 1)][1][0] === "\n"
 
301
                ) {
 
302
                    $token[1] .= "\n";
 
303
 
 
304
                    if ($tokens[($stackPtr + 1)][1] === "\n") {
 
305
                        // The next token's content has been merged into this token,
 
306
                        // so we can skip it.
 
307
                        $stackPtr++;
 
308
                    } else {
 
309
                        $tokens[($stackPtr + 1)][1]
 
310
                            = substr($tokens[($stackPtr + 1)][1], 1);
 
311
                    }
 
312
                }
 
313
            }//end if
 
314
 
 
315
            /*
 
316
                If this is a double quoted string, PHP will tokenise the whole
 
317
                thing which causes problems with the scope map when braces are
 
318
                within the string. So we need to merge the tokens together to
 
319
                provide a single string.
 
320
            */
 
321
 
 
322
            if ($tokenIsArray === false && $token === '"') {
 
323
                $tokenContent = '"';
 
324
                $nestedVars   = array();
 
325
                for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
 
326
                    $subTokenIsArray = is_array($tokens[$i]);
 
327
 
 
328
                    if ($subTokenIsArray === true) {
 
329
                        $tokenContent .= $tokens[$i][1];
 
330
                        if ($tokens[$i][1] === '{'
 
331
                            && $tokens[$i][0] !== T_ENCAPSED_AND_WHITESPACE
 
332
                        ) {
 
333
                            $nestedVars[] = $i;
 
334
                        }
 
335
                    } else {
 
336
                        $tokenContent .= $tokens[$i];
 
337
                        if ($tokens[$i] === '}') {
 
338
                            array_pop($nestedVars);
 
339
                        }
 
340
                    }
 
341
 
 
342
                    if ($subTokenIsArray === false
 
343
                        && $tokens[$i] === '"'
 
344
                        && empty($nestedVars) === true
 
345
                    ) {
 
346
                        // We found the other end of the double quoted string.
 
347
                        break;
 
348
                    }
 
349
                }
 
350
 
 
351
                $stackPtr = $i;
 
352
 
 
353
                // Convert each line within the double quoted string to a
 
354
                // new token, so it conforms with other multiple line tokens.
 
355
                $tokenLines = explode($eolChar, $tokenContent);
 
356
                $numLines   = count($tokenLines);
 
357
                $newToken   = array();
 
358
 
 
359
                for ($j = 0; $j < $numLines; $j++) {
 
360
                    $newToken['content'] = $tokenLines[$j];
 
361
                    if ($j === ($numLines - 1)) {
 
362
                        if ($tokenLines[$j] === '') {
 
363
                            break;
 
364
                        }
 
365
                    } else {
 
366
                        $newToken['content'] .= $eolChar;
 
367
                    }
 
368
 
 
369
                    $newToken['code']          = T_DOUBLE_QUOTED_STRING;
 
370
                    $newToken['type']          = 'T_DOUBLE_QUOTED_STRING';
 
371
                    $finalTokens[$newStackPtr] = $newToken;
 
372
                    $newStackPtr++;
 
373
                }
 
374
 
 
375
                // Continue, as we're done with this token.
 
376
                continue;
 
377
            }//end if
 
378
 
 
379
            /*
 
380
                If this is a heredoc, PHP will tokenise the whole
 
381
                thing which causes problems when heredocs don't
 
382
                contain real PHP code, which is almost never.
 
383
                We want to leave the start and end heredoc tokens
 
384
                alone though.
 
385
            */
 
386
 
 
387
            if ($tokenIsArray === true && $token[0] === T_START_HEREDOC) {
 
388
                // Add the start heredoc token to the final array.
 
389
                $finalTokens[$newStackPtr]
 
390
                    = PHP_CodeSniffer::standardiseToken($token);
 
391
 
 
392
                // Check if this is actually a nowdoc and use a different token
 
393
                // to help the sniffs.
 
394
                $nowdoc = false;
 
395
                if ($token[1][3] === "'") {
 
396
                    $finalTokens[$newStackPtr]['code'] = T_START_NOWDOC;
 
397
                    $finalTokens[$newStackPtr]['type'] = 'T_START_NOWDOC';
 
398
                    $nowdoc = true;
 
399
                }
 
400
 
 
401
                $newStackPtr++;
 
402
 
 
403
                $tokenContent = '';
 
404
                for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
 
405
                    $subTokenIsArray = is_array($tokens[$i]);
 
406
                    if ($subTokenIsArray === true
 
407
                        && $tokens[$i][0] === T_END_HEREDOC
 
408
                    ) {
 
409
                        // We found the other end of the heredoc.
 
410
                        break;
 
411
                    }
 
412
 
 
413
                    if ($subTokenIsArray === true) {
 
414
                        $tokenContent .= $tokens[$i][1];
 
415
                    } else {
 
416
                        $tokenContent .= $tokens[$i];
 
417
                    }
 
418
                }
 
419
 
 
420
                $stackPtr = $i;
 
421
 
 
422
                // Convert each line within the heredoc to a
 
423
                // new token, so it conforms with other multiple line tokens.
 
424
                $tokenLines = explode($eolChar, $tokenContent);
 
425
                $numLines   = count($tokenLines);
 
426
                $newToken   = array();
 
427
 
 
428
                for ($j = 0; $j < $numLines; $j++) {
 
429
                    $newToken['content'] = $tokenLines[$j];
 
430
                    if ($j === ($numLines - 1)) {
 
431
                        if ($tokenLines[$j] === '') {
 
432
                            break;
 
433
                        }
 
434
                    } else {
 
435
                        $newToken['content'] .= $eolChar;
 
436
                    }
 
437
 
 
438
                    if ($nowdoc === true) {
 
439
                        $newToken['code'] = T_NOWDOC;
 
440
                        $newToken['type'] = 'T_NOWDOC';
 
441
                    } else {
 
442
                        $newToken['code'] = T_HEREDOC;
 
443
                        $newToken['type'] = 'T_HEREDOC';
 
444
                    }
 
445
 
 
446
                    $finalTokens[$newStackPtr] = $newToken;
 
447
                    $newStackPtr++;
 
448
                }
 
449
 
 
450
                // Add the end heredoc token to the final array.
 
451
                $finalTokens[$newStackPtr]
 
452
                    = PHP_CodeSniffer::standardiseToken($tokens[$stackPtr]);
 
453
 
 
454
                if ($nowdoc === true) {
 
455
                    $finalTokens[$newStackPtr]['code'] = T_END_NOWDOC;
 
456
                    $finalTokens[$newStackPtr]['type'] = 'T_END_NOWDOC';
 
457
                    $nowdoc = true;
 
458
                }
 
459
 
 
460
                $newStackPtr++;
 
461
 
 
462
                // Continue, as we're done with this token.
 
463
                continue;
 
464
            }//end if
 
465
 
 
466
            /*
 
467
                PHP doesn't assign a token to goto labels, so we have to.
 
468
                These are just string tokens with a single colon after them. Double
 
469
                colons are already tokenized and so don't interfere with this check.
 
470
                But we do have to account for CASE statements, that look just like
 
471
                goto labels.
 
472
            */
 
473
 
 
474
            if ($tokenIsArray === true
 
475
                && $token[0] === T_STRING
 
476
                && $tokens[($stackPtr + 1)] === ':'
 
477
                && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM
 
478
            ) {
 
479
                $stopTokens = array(
 
480
                               T_CASE,
 
481
                               T_SEMICOLON,
 
482
                               T_OPEN_CURLY_BRACKET,
 
483
                               T_INLINE_THEN,
 
484
                              );
 
485
 
 
486
                for ($x = ($newStackPtr - 1); $x > 0; $x--) {
 
487
                    if (in_array($finalTokens[$x]['code'], $stopTokens) === true) {
 
488
                        break;
 
489
                    }
 
490
                }
 
491
 
 
492
                if ($finalTokens[$x]['code'] !== T_CASE
 
493
                    && $finalTokens[$x]['code'] !== T_INLINE_THEN
 
494
                ) {
 
495
                    $finalTokens[$newStackPtr] = array(
 
496
                                                  'content' => $token[1].':',
 
497
                                                  'code'    => T_GOTO_LABEL,
 
498
                                                  'type'    => 'T_GOTO_LABEL',
 
499
                                                 );
 
500
                    $newStackPtr++;
 
501
                    $stackPtr++;
 
502
                    continue;
 
503
                }
 
504
            }//end if
 
505
 
 
506
            /*
 
507
                If this token has newlines in its content, split each line up
 
508
                and create a new token for each line. We do this so it's easier
 
509
                to ascertain where errors occur on a line.
 
510
                Note that $token[1] is the token's content.
 
511
            */
 
512
 
 
513
            if ($tokenIsArray === true && strpos($token[1], $eolChar) !== false) {
 
514
                $tokenLines = explode($eolChar, $token[1]);
 
515
                $numLines   = count($tokenLines);
 
516
                $tokenName  = token_name($token[0]);
 
517
 
 
518
                for ($i = 0; $i < $numLines; $i++) {
 
519
                    $newToken['content'] = $tokenLines[$i];
 
520
                    if ($i === ($numLines - 1)) {
 
521
                        if ($tokenLines[$i] === '') {
 
522
                            break;
 
523
                        }
 
524
                    } else {
 
525
                        $newToken['content'] .= $eolChar;
 
526
                    }
 
527
 
 
528
                    $newToken['type']          = $tokenName;
 
529
                    $newToken['code']          = $token[0];
 
530
                    $finalTokens[$newStackPtr] = $newToken;
 
531
                    $newStackPtr++;
 
532
                }
 
533
            } else {
 
534
                $newToken = PHP_CodeSniffer::standardiseToken($token);
 
535
 
 
536
                // Convert colons that are actually the ELSE component of an
 
537
                // inline IF statement.
 
538
                if ($newToken['code'] === T_INLINE_THEN) {
 
539
                    $insideInlineIf = true;
 
540
                } else if ($insideInlineIf === true && $newToken['code'] === T_COLON) {
 
541
                    $insideInlineIf = false;
 
542
                    $newToken['code'] = T_INLINE_ELSE;
 
543
                    $newToken['type'] = 'T_INLINE_ELSE';
 
544
                }
 
545
 
 
546
                // This is a special condition for T_ARRAY tokens used for
 
547
                // type hinting function arguments as being arrays. We want to keep
 
548
                // the parenthesis map clean, so let's tag these tokens as
 
549
                // T_ARRAY_HINT.
 
550
                if ($newToken['code'] === T_ARRAY) {
 
551
                    // Recalculate number of tokens.
 
552
                    $numTokens = count($tokens);
 
553
                    for ($i = $stackPtr; $i < $numTokens; $i++) {
 
554
                        if (is_array($tokens[$i]) === false) {
 
555
                            if ($tokens[$i] === '(') {
 
556
                                break;
 
557
                            }
 
558
                        } else if ($tokens[$i][0] === T_VARIABLE) {
 
559
                            $newToken['code'] = T_ARRAY_HINT;
 
560
                            $newToken['type'] = 'T_ARRAY_HINT';
 
561
                            break;
 
562
                        }
 
563
                    }
 
564
                }
 
565
 
 
566
                // This is a special case for the PHP 5.5 classname::class syntax
 
567
                // where "class" should be T_STRING instead of T_CLASS.
 
568
                if ($newToken['code'] === T_CLASS
 
569
                    && $finalTokens[($newStackPtr - 1)]['code'] === T_DOUBLE_COLON
 
570
                ) {
 
571
                    $newToken['code'] = T_STRING;
 
572
                    $newToken['type'] = 'T_STRING';
 
573
                }
 
574
 
 
575
                $finalTokens[$newStackPtr] = $newToken;
 
576
                $newStackPtr++;
 
577
            }//end if
 
578
        }//end for
 
579
 
 
580
        return $finalTokens;
 
581
 
 
582
    }//end tokenizeString()
 
583
 
 
584
 
 
585
    /**
 
586
     * Performs additional processing after main tokenizing.
 
587
     *
 
588
     * This additional processing checks for CASE statements that are using curly
 
589
     * braces for scope openers and closers. It also turns some T_FUNCTION tokens
 
590
     * into T_CLOSURE when they are not standard function definitions. It also
 
591
     * detects short array syntax and converts those square brackets into new tokens.
 
592
     * It also corrects some usage of the static and class keywords.
 
593
     *
 
594
     * @param array  &$tokens The array of tokens to process.
 
595
     * @param string $eolChar The EOL character to use for splitting strings.
 
596
     *
 
597
     * @return void
 
598
     */
 
599
    public function processAdditional(&$tokens, $eolChar)
 
600
    {
 
601
        if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
602
            echo "\t*** START ADDITIONAL PHP PROCESSING ***".PHP_EOL;
 
603
        }
 
604
 
 
605
        $numTokens = count($tokens);
 
606
        for ($i = ($numTokens - 1); $i >= 0; $i--) {
 
607
            // Check for any unset scope conditions due to alternate IF/ENDIF syntax.
 
608
            if (isset($tokens[$i]['scope_opener']) === true
 
609
                && isset($tokens[$i]['scope_condition']) === false
 
610
            ) {
 
611
                $tokens[$i]['scope_condition'] = $tokens[$tokens[$i]['scope_opener']]['scope_condition'];
 
612
            }
 
613
 
 
614
            // Looking for functions that are actually closures.
 
615
            if ($tokens[$i]['code'] === T_FUNCTION && isset($tokens[$i]['scope_opener']) === true) {
 
616
                for ($x = ($i + 1); $x < $numTokens; $x++) {
 
617
                    if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
 
618
                        break;
 
619
                    }
 
620
                }
 
621
 
 
622
                if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
 
623
                    $tokens[$i]['code'] = T_CLOSURE;
 
624
                    $tokens[$i]['type'] = 'T_CLOSURE';
 
625
                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
626
                        $line = $tokens[$i]['line'];
 
627
                        echo "\t* token $i on line $line changed from T_FUNCTION to T_CLOSURE".PHP_EOL;
 
628
                    }
 
629
 
 
630
                    for ($x = ($tokens[$i]['scope_opener'] + 1); $x < $tokens[$i]['scope_closer']; $x++) {
 
631
                        if (isset($tokens[$x]['conditions'][$i]) === false) {
 
632
                            continue;
 
633
                        }
 
634
 
 
635
                        $tokens[$x]['conditions'][$i] = T_CLOSURE;
 
636
                        if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
637
                            $type = $tokens[$x]['type'];
 
638
                            echo "\t\t* cleaned $x ($type) *".PHP_EOL;
 
639
                        }
 
640
                    }
 
641
                }
 
642
 
 
643
                continue;
 
644
            } else if ($tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) {
 
645
                // Unless there is a variable or a bracket before this token,
 
646
                // it is the start of an array being defined using the short syntax.
 
647
                for ($x = ($i - 1); $x > 0; $x--) {
 
648
                    if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
 
649
                        break;
 
650
                    }
 
651
                }
 
652
 
 
653
                $allowed = array(
 
654
                            T_CLOSE_SQUARE_BRACKET,
 
655
                            T_CLOSE_PARENTHESIS,
 
656
                            T_VARIABLE,
 
657
                            T_STRING,
 
658
                           );
 
659
 
 
660
                if (in_array($tokens[$x]['code'], $allowed) === false) {
 
661
                    $tokens[$i]['code'] = T_OPEN_SHORT_ARRAY;
 
662
                    $tokens[$i]['type'] = 'T_OPEN_SHORT_ARRAY';
 
663
 
 
664
                    $closer                  = $tokens[$i]['bracket_closer'];
 
665
                    $tokens[$closer]['code'] = T_CLOSE_SHORT_ARRAY;
 
666
                    $tokens[$closer]['type'] = 'T_CLOSE_SHORT_ARRAY';
 
667
                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
668
                        $line = $tokens[$i]['line'];
 
669
                        echo "\t* token $i on line $line changed from T_OPEN_SQUARE_BRACKET to T_OPEN_SHORT_ARRAY".PHP_EOL;
 
670
                        $line = $tokens[$closer]['line'];
 
671
                        echo "\t* token $closer on line $line changed from T_CLOSE_SQUARE_BRACKET to T_CLOSE_SHORT_ARRAY".PHP_EOL;
 
672
                    }
 
673
                }
 
674
 
 
675
                continue;
 
676
            } else if ($tokens[$i]['code'] === T_STATIC) {
 
677
                for ($x = ($i - 1); $x > 0; $x--) {
 
678
                    if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
 
679
                        break;
 
680
                    }
 
681
                }
 
682
 
 
683
                if ($tokens[$x]['code'] === T_INSTANCEOF) {
 
684
                    $tokens[$i]['code'] = T_STRING;
 
685
                    $tokens[$i]['type'] = 'T_STRING';
 
686
 
 
687
                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
688
                        $line = $tokens[$i]['line'];
 
689
                        echo "\t* token $i on line $line changed from T_STATIC to T_STRING".PHP_EOL;
 
690
                    }
 
691
                }
 
692
 
 
693
                continue;
 
694
            }
 
695
 
 
696
            if (($tokens[$i]['code'] !== T_CASE
 
697
                && $tokens[$i]['code'] !== T_DEFAULT)
 
698
                || isset($tokens[$i]['scope_opener']) === false
 
699
            ) {
 
700
                // Only interested in CASE and DEFAULT statements from here on in.
 
701
                continue;
 
702
            }
 
703
 
 
704
            $scopeOpener = $tokens[$i]['scope_opener'];
 
705
            $scopeCloser = $tokens[$i]['scope_closer'];
 
706
 
 
707
            // If the first char after the opener is a curly brace
 
708
            // and that brace has been ignored, it is actually
 
709
            // opening this case statement and the opener and closer are
 
710
            // probably set incorrectly.
 
711
            for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) {
 
712
                if (in_array($tokens[$x]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
 
713
                    // Non-whitespace content.
 
714
                    break;
 
715
                }
 
716
            }
 
717
 
 
718
            if ($tokens[$x]['code'] === T_CASE) {
 
719
                // Special case for multiple CASE statements that share the same
 
720
                // closer. Because we are going backwards through the file, this next
 
721
                // CASE statement is already fixed, so just use its closer and don't
 
722
                // worry about fixing anything.
 
723
                $newCloser = $tokens[$x]['scope_closer'];
 
724
                $tokens[$i]['scope_closer'] = $newCloser;
 
725
                if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
726
                    $oldType = $tokens[$scopeCloser]['type'];
 
727
                    $newType = $tokens[$newCloser]['type'];
 
728
                    $line    = $tokens[$i]['line'];
 
729
                    echo "\t* token $i (T_CASE) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
 
730
                }
 
731
 
 
732
                continue;
 
733
            }
 
734
 
 
735
            if ($tokens[$x]['code'] !== T_OPEN_CURLY_BRACKET
 
736
                || isset($tokens[$x]['scope_condition']) === true
 
737
            ) {
 
738
                // Not a CASE with a curly brace opener.
 
739
                continue;
 
740
            }
 
741
 
 
742
            // The closer for this CASE/DEFAULT should be the closing curly brace and
 
743
            // not whatever it already is. The opener needs to be the opening curly
 
744
            // brace so everything matches up.
 
745
            $newCloser = $tokens[$x]['bracket_closer'];
 
746
            $tokens[$i]['scope_closer'] = $newCloser;
 
747
            $tokens[$x]['scope_closer'] = $newCloser;
 
748
            $tokens[$i]['scope_opener'] = $x;
 
749
            $tokens[$x]['scope_condition'] = $i;
 
750
            $tokens[$newCloser]['scope_condition'] = $i;
 
751
            $tokens[$newCloser]['scope_opener']    = $x;
 
752
            if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
753
                $line      = $tokens[$i]['line'];
 
754
                $tokenType = $tokens[$i]['type'];
 
755
 
 
756
                $oldType = $tokens[$scopeOpener]['type'];
 
757
                $newType = $tokens[$x]['type'];
 
758
                echo "\t* token $i ($tokenType) on line $line opener changed from $scopeOpener ($oldType) to $x ($newType)".PHP_EOL;
 
759
 
 
760
                $oldType = $tokens[$scopeCloser]['type'];
 
761
                $newType = $tokens[$newCloser]['type'];
 
762
                echo "\t* token $i ($tokenType) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
 
763
            }
 
764
 
 
765
            // Now fix up all the tokens that think they are
 
766
            // inside the CASE/DEFAULT statement when they are really outside.
 
767
            for ($x = $newCloser; $x < $scopeCloser; $x++) {
 
768
                foreach ($tokens[$x]['conditions'] as $num => $oldCond) {
 
769
                    if ($oldCond === $tokens[$i]['code']) {
 
770
                        $oldConditions = $tokens[$x]['conditions'];
 
771
                        unset($tokens[$x]['conditions'][$num]);
 
772
 
 
773
                        if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
774
                            $type     = $tokens[$x]['type'];
 
775
                            $oldConds = '';
 
776
                            foreach ($oldConditions as $condition) {
 
777
                                $oldConds .= token_name($condition).',';
 
778
                            }
 
779
 
 
780
                            $oldConds = rtrim($oldConds, ',');
 
781
 
 
782
                            $newConds = '';
 
783
                            foreach ($tokens[$x]['conditions'] as $condition) {
 
784
                                $newConds .= token_name($condition).',';
 
785
                            }
 
786
 
 
787
                            $newConds = rtrim($newConds, ',');
 
788
 
 
789
                            echo "\t\t* cleaned $x ($type) *".PHP_EOL;
 
790
                            echo "\t\t\t=> conditions changed from $oldConds to $newConds".PHP_EOL;
 
791
                        }
 
792
 
 
793
                        break;
 
794
                    }
 
795
                }
 
796
            }
 
797
        }//end for
 
798
 
 
799
        if (PHP_CODESNIFFER_VERBOSITY > 1) {
 
800
            echo "\t*** END ADDITIONAL PHP PROCESSING ***".PHP_EOL;
 
801
        }
 
802
 
 
803
    }//end processAdditional()
 
804
 
 
805
 
 
806
}//end class
 
807
 
 
808
?>