diff vendor/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/PHP.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 7a779792577d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/PHP.php	Wed Nov 29 16:09:58 2017 +0000
@@ -0,0 +1,1707 @@
+<?php
+/**
+ * Tokenizes PHP code.
+ *
+ * PHP version 5
+ *
+ * @category  PHP
+ * @package   PHP_CodeSniffer
+ * @author    Greg Sherwood <gsherwood@squiz.net>
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @link      http://pear.php.net/package/PHP_CodeSniffer
+ */
+
+/**
+ * Tokenizes PHP code.
+ *
+ * @category  PHP
+ * @package   PHP_CodeSniffer
+ * @author    Greg Sherwood <gsherwood@squiz.net>
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @version   Release: @package_version@
+ * @link      http://pear.php.net/package/PHP_CodeSniffer
+ */
+class PHP_CodeSniffer_Tokenizers_PHP
+{
+
+    /**
+     * If TRUE, files that appear to be minified will not be processed.
+     *
+     * @var boolean
+     */
+    public $skipMinified = false;
+
+    /**
+     * A list of tokens that are allowed to open a scope.
+     *
+     * This array also contains information about what kind of token the scope
+     * opener uses to open and close the scope, if the token strictly requires
+     * an opener, if the token can share a scope closer, and who it can be shared
+     * with. An example of a token that shares a scope closer is a CASE scope.
+     *
+     * @var array
+     */
+    public $scopeOpeners = array(
+                            T_IF            => array(
+                                                'start'  => array(
+                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
+                                                             T_COLON              => T_COLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                                                             T_ENDIF               => T_ENDIF,
+                                                             T_ELSE                => T_ELSE,
+                                                             T_ELSEIF              => T_ELSEIF,
+                                                            ),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(
+                                                             T_ELSE   => T_ELSE,
+                                                             T_ELSEIF => T_ELSEIF,
+                                                            ),
+                                               ),
+                            T_TRY           => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_CATCH         => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_FINALLY       => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_ELSE          => array(
+                                                'start'  => array(
+                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
+                                                             T_COLON              => T_COLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                                                             T_ENDIF               => T_ENDIF,
+                                                            ),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(
+                                                             T_IF     => T_IF,
+                                                             T_ELSEIF => T_ELSEIF,
+                                                            ),
+                                               ),
+                            T_ELSEIF        => array(
+                                                'start'  => array(
+                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
+                                                             T_COLON              => T_COLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                                                             T_ENDIF               => T_ENDIF,
+                                                             T_ELSE                => T_ELSE,
+                                                             T_ELSEIF              => T_ELSEIF,
+                                                            ),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(
+                                                             T_IF   => T_IF,
+                                                             T_ELSE => T_ELSE,
+                                                            ),
+                                               ),
+                            T_FOR           => array(
+                                                'start'  => array(
+                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
+                                                             T_COLON              => T_COLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                                                             T_ENDFOR              => T_ENDFOR,
+                                                            ),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_FOREACH       => array(
+                                                'start'  => array(
+                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
+                                                             T_COLON              => T_COLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                                                             T_ENDFOREACH          => T_ENDFOREACH,
+                                                            ),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_INTERFACE     => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_FUNCTION      => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_CLASS         => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_TRAIT         => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_USE           => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_DECLARE       => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_NAMESPACE     => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_WHILE         => array(
+                                                'start'  => array(
+                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
+                                                             T_COLON              => T_COLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                                                             T_ENDWHILE            => T_ENDWHILE,
+                                                            ),
+                                                'strict' => false,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_DO            => array(
+                                                'start'  => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
+                                                'end'    => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_SWITCH        => array(
+                                                'start'  => array(
+                                                             T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
+                                                             T_COLON              => T_COLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                                                             T_ENDSWITCH           => T_ENDSWITCH,
+                                                            ),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                            T_CASE          => array(
+                                                'start'  => array(
+                                                             T_COLON     => T_COLON,
+                                                             T_SEMICOLON => T_SEMICOLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_BREAK    => T_BREAK,
+                                                             T_RETURN   => T_RETURN,
+                                                             T_CONTINUE => T_CONTINUE,
+                                                             T_THROW    => T_THROW,
+                                                             T_EXIT     => T_EXIT,
+                                                            ),
+                                                'strict' => true,
+                                                'shared' => true,
+                                                'with'   => array(
+                                                             T_DEFAULT => T_DEFAULT,
+                                                             T_CASE    => T_CASE,
+                                                             T_SWITCH  => T_SWITCH,
+                                                            ),
+                                               ),
+                            T_DEFAULT       => array(
+                                                'start'  => array(
+                                                             T_COLON     => T_COLON,
+                                                             T_SEMICOLON => T_SEMICOLON,
+                                                            ),
+                                                'end'    => array(
+                                                             T_BREAK    => T_BREAK,
+                                                             T_RETURN   => T_RETURN,
+                                                             T_CONTINUE => T_CONTINUE,
+                                                             T_THROW    => T_THROW,
+                                                             T_EXIT     => T_EXIT,
+                                                            ),
+                                                'strict' => true,
+                                                'shared' => true,
+                                                'with'   => array(
+                                                             T_CASE   => T_CASE,
+                                                             T_SWITCH => T_SWITCH,
+                                                            ),
+                                               ),
+                            T_START_HEREDOC => array(
+                                                'start'  => array(T_START_HEREDOC => T_START_HEREDOC),
+                                                'end'    => array(T_END_HEREDOC => T_END_HEREDOC),
+                                                'strict' => true,
+                                                'shared' => false,
+                                                'with'   => array(),
+                                               ),
+                           );
+
+    /**
+     * A list of tokens that end the scope.
+     *
+     * This array is just a unique collection of the end tokens
+     * from the _scopeOpeners array. The data is duplicated here to
+     * save time during parsing of the file.
+     *
+     * @var array
+     */
+    public $endScopeTokens = array(
+                              T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
+                              T_ENDIF               => T_ENDIF,
+                              T_ENDFOR              => T_ENDFOR,
+                              T_ENDFOREACH          => T_ENDFOREACH,
+                              T_ENDWHILE            => T_ENDWHILE,
+                              T_ENDSWITCH           => T_ENDSWITCH,
+                              T_BREAK               => T_BREAK,
+                              T_END_HEREDOC         => T_END_HEREDOC,
+                             );
+
+    /**
+     * A cache of different token types, resolved into arrays.
+     *
+     * @var array()
+     * @see standardiseToken()
+     */
+    private static $_resolveTokenCache = array();
+
+
+    /**
+     * Creates an array of tokens when given some PHP code.
+     *
+     * Starts by using token_get_all() but does a lot of extra processing
+     * to insert information about the context of the token.
+     *
+     * @param string $string  The string to tokenize.
+     * @param string $eolChar The EOL character to use for splitting strings.
+     *
+     * @return array
+     */
+    public function tokenizeString($string, $eolChar='\n')
+    {
+        if (PHP_CODESNIFFER_VERBOSITY > 1) {
+            echo "\t*** START PHP TOKENIZING ***".PHP_EOL;
+            $isWin = false;
+            if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+                $isWin = true;
+            }
+        }
+
+        $tokens      = @token_get_all($string);
+        $finalTokens = array();
+
+        $newStackPtr       = 0;
+        $numTokens         = count($tokens);
+        $lastNotEmptyToken = 0;
+
+        $insideInlineIf = array();
+        $insideUseGroup = false;
+
+        $commentTokenizer = new PHP_CodeSniffer_Tokenizers_Comment();
+
+        for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
+            $token        = (array) $tokens[$stackPtr];
+            $tokenIsArray = isset($token[1]);
+
+            if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                if ($tokenIsArray === true) {
+                    $type    = token_name($token[0]);
+                    $content = PHP_CodeSniffer::prepareForOutput($token[1]);
+                } else {
+                    $newToken = self::resolveSimpleToken($token[0]);
+                    $type     = $newToken['type'];
+                    $content  = PHP_CodeSniffer::prepareForOutput($token[0]);
+                }
+
+                echo "\tProcess token ";
+                if ($tokenIsArray === true) {
+                    echo "[$stackPtr]";
+                } else {
+                    echo " $stackPtr ";
+                }
+
+                echo ": $type => $content";
+            }//end if
+
+            if ($newStackPtr > 0 && $finalTokens[($newStackPtr - 1)]['code'] !== T_WHITESPACE) {
+                $lastNotEmptyToken = ($newStackPtr - 1);
+            }
+
+            /*
+                If we are using \r\n newline characters, the \r and \n are sometimes
+                split over two tokens. This normally occurs after comments. We need
+                to merge these two characters together so that our line endings are
+                consistent for all lines.
+            */
+
+            if ($tokenIsArray === true && substr($token[1], -1) === "\r") {
+                if (isset($tokens[($stackPtr + 1)]) === true
+                    && is_array($tokens[($stackPtr + 1)]) === true
+                    && $tokens[($stackPtr + 1)][1][0] === "\n"
+                ) {
+                    $token[1] .= "\n";
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        if ($isWin === true) {
+                            echo '\n';
+                        } else {
+                            echo "\033[30;1m\\n\033[0m";
+                        }
+                    }
+
+                    if ($tokens[($stackPtr + 1)][1] === "\n") {
+                        // This token's content has been merged into the previous,
+                        // so we can skip it.
+                        $tokens[($stackPtr + 1)] = '';
+                    } else {
+                        $tokens[($stackPtr + 1)][1] = substr($tokens[($stackPtr + 1)][1], 1);
+                    }
+                }
+            }//end if
+
+            if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                echo PHP_EOL;
+            }
+
+            /*
+                Parse doc blocks into something that can be easily iterated over.
+            */
+
+            if ($tokenIsArray === true && $token[0] === T_DOC_COMMENT) {
+                $commentTokens = $commentTokenizer->tokenizeString($token[1], $eolChar, $newStackPtr);
+                foreach ($commentTokens as $commentToken) {
+                    $finalTokens[$newStackPtr] = $commentToken;
+                    $newStackPtr++;
+                }
+
+                continue;
+            }
+
+            /*
+                If this is a double quoted string, PHP will tokenize the whole
+                thing which causes problems with the scope map when braces are
+                within the string. So we need to merge the tokens together to
+                provide a single string.
+            */
+
+            if ($tokenIsArray === false && ($token[0] === '"' || $token[0] === 'b"')) {
+                // Binary casts need a special token.
+                if ($token[0] === 'b"') {
+                    $finalTokens[$newStackPtr] = array(
+                                                  'code'    => T_BINARY_CAST,
+                                                  'type'    => 'T_BINARY_CAST',
+                                                  'content' => 'b',
+                                                 );
+                    $newStackPtr++;
+                }
+
+                $tokenContent = '"';
+                $nestedVars   = array();
+                for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
+                    $subToken        = (array) $tokens[$i];
+                    $subTokenIsArray = isset($subToken[1]);
+
+                    if ($subTokenIsArray === true) {
+                        $tokenContent .= $subToken[1];
+                        if ($subToken[1] === '{'
+                            && $subToken[0] !== T_ENCAPSED_AND_WHITESPACE
+                        ) {
+                            $nestedVars[] = $i;
+                        }
+                    } else {
+                        $tokenContent .= $subToken[0];
+                        if ($subToken[0] === '}') {
+                            array_pop($nestedVars);
+                        }
+                    }
+
+                    if ($subTokenIsArray === false
+                        && $subToken[0] === '"'
+                        && empty($nestedVars) === true
+                    ) {
+                        // We found the other end of the double quoted string.
+                        break;
+                    }
+                }//end for
+
+                $stackPtr = $i;
+
+                // Convert each line within the double quoted string to a
+                // new token, so it conforms with other multiple line tokens.
+                $tokenLines = explode($eolChar, $tokenContent);
+                $numLines   = count($tokenLines);
+                $newToken   = array();
+
+                for ($j = 0; $j < $numLines; $j++) {
+                    $newToken['content'] = $tokenLines[$j];
+                    if ($j === ($numLines - 1)) {
+                        if ($tokenLines[$j] === '') {
+                            break;
+                        }
+                    } else {
+                        $newToken['content'] .= $eolChar;
+                    }
+
+                    $newToken['code']          = T_DOUBLE_QUOTED_STRING;
+                    $newToken['type']          = 'T_DOUBLE_QUOTED_STRING';
+                    $finalTokens[$newStackPtr] = $newToken;
+                    $newStackPtr++;
+                }
+
+                // Continue, as we're done with this token.
+                continue;
+            }//end if
+
+            /*
+                If this is a heredoc, PHP will tokenize the whole
+                thing which causes problems when heredocs don't
+                contain real PHP code, which is almost never.
+                We want to leave the start and end heredoc tokens
+                alone though.
+            */
+
+            if ($tokenIsArray === true && $token[0] === T_START_HEREDOC) {
+                // Add the start heredoc token to the final array.
+                $finalTokens[$newStackPtr] = self::standardiseToken($token);
+
+                // Check if this is actually a nowdoc and use a different token
+                // to help the sniffs.
+                $nowdoc = false;
+                if ($token[1][3] === "'") {
+                    $finalTokens[$newStackPtr]['code'] = T_START_NOWDOC;
+                    $finalTokens[$newStackPtr]['type'] = 'T_START_NOWDOC';
+                    $nowdoc = true;
+                }
+
+                $tokenContent = '';
+                for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
+                    $subTokenIsArray = is_array($tokens[$i]);
+                    if ($subTokenIsArray === true
+                        && $tokens[$i][0] === T_END_HEREDOC
+                    ) {
+                        // We found the other end of the heredoc.
+                        break;
+                    }
+
+                    if ($subTokenIsArray === true) {
+                        $tokenContent .= $tokens[$i][1];
+                    } else {
+                        $tokenContent .= $tokens[$i];
+                    }
+                }
+
+                if ($i === $numTokens) {
+                    // We got to the end of the file and never
+                    // found the closing token, so this probably wasn't
+                    // a heredoc.
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        $type = $finalTokens[$newStackPtr]['type'];
+                        echo "\t\t* failed to find the end of the here/nowdoc".PHP_EOL;
+                        echo "\t\t* token $stackPtr changed from $type to T_STRING".PHP_EOL;
+                    }
+
+                    $finalTokens[$newStackPtr]['code'] = T_STRING;
+                    $finalTokens[$newStackPtr]['type'] = 'T_STRING';
+                    $newStackPtr++;
+                    continue;
+                }
+
+                $stackPtr = $i;
+                $newStackPtr++;
+
+                // Convert each line within the heredoc to a
+                // new token, so it conforms with other multiple line tokens.
+                $tokenLines = explode($eolChar, $tokenContent);
+                $numLines   = count($tokenLines);
+                $newToken   = array();
+
+                for ($j = 0; $j < $numLines; $j++) {
+                    $newToken['content'] = $tokenLines[$j];
+                    if ($j === ($numLines - 1)) {
+                        if ($tokenLines[$j] === '') {
+                            break;
+                        }
+                    } else {
+                        $newToken['content'] .= $eolChar;
+                    }
+
+                    if ($nowdoc === true) {
+                        $newToken['code'] = T_NOWDOC;
+                        $newToken['type'] = 'T_NOWDOC';
+                    } else {
+                        $newToken['code'] = T_HEREDOC;
+                        $newToken['type'] = 'T_HEREDOC';
+                    }
+
+                    $finalTokens[$newStackPtr] = $newToken;
+                    $newStackPtr++;
+                }//end for
+
+                // Add the end heredoc token to the final array.
+                $finalTokens[$newStackPtr] = self::standardiseToken($tokens[$stackPtr]);
+
+                if ($nowdoc === true) {
+                    $finalTokens[$newStackPtr]['code'] = T_END_NOWDOC;
+                    $finalTokens[$newStackPtr]['type'] = 'T_END_NOWDOC';
+                    $nowdoc = true;
+                }
+
+                $newStackPtr++;
+
+                // Continue, as we're done with this token.
+                continue;
+            }//end if
+
+            /*
+                Before PHP 5.6, the ... operator was tokenized as three
+                T_STRING_CONCAT tokens in a row. So look for and combine
+                these tokens in earlier versions.
+            */
+
+            if ($tokenIsArray === false
+                && $token[0] === '.'
+                && isset($tokens[($stackPtr + 1)]) === true
+                && isset($tokens[($stackPtr + 2)]) === true
+                && $tokens[($stackPtr + 1)] === '.'
+                && $tokens[($stackPtr + 2)] === '.'
+            ) {
+                $newToken            = array();
+                $newToken['code']    = T_ELLIPSIS;
+                $newToken['type']    = 'T_ELLIPSIS';
+                $newToken['content'] = '...';
+                $finalTokens[$newStackPtr] = $newToken;
+
+                $newStackPtr++;
+                $stackPtr += 2;
+                continue;
+            }
+
+            /*
+                Before PHP 5.6, the ** operator was tokenized as two
+                T_MULTIPLY tokens in a row. So look for and combine
+                these tokens in earlier versions.
+            */
+
+            if ($tokenIsArray === false
+                && $token[0] === '*'
+                && isset($tokens[($stackPtr + 1)]) === true
+                && $tokens[($stackPtr + 1)] === '*'
+            ) {
+                $newToken            = array();
+                $newToken['code']    = T_POW;
+                $newToken['type']    = 'T_POW';
+                $newToken['content'] = '**';
+                $finalTokens[$newStackPtr] = $newToken;
+
+                $newStackPtr++;
+                $stackPtr++;
+                continue;
+            }
+
+            /*
+                Before PHP 5.6, the **= operator was tokenized as
+                T_MULTIPLY followed by T_MUL_EQUAL. So look for and combine
+                these tokens in earlier versions.
+            */
+
+            if ($tokenIsArray === false
+                && $token[0] === '*'
+                && isset($tokens[($stackPtr + 1)]) === true
+                && is_array($tokens[($stackPtr + 1)]) === true
+                && $tokens[($stackPtr + 1)][1] === '*='
+            ) {
+                $newToken            = array();
+                $newToken['code']    = T_POW_EQUAL;
+                $newToken['type']    = 'T_POW_EQUAL';
+                $newToken['content'] = '**=';
+                $finalTokens[$newStackPtr] = $newToken;
+
+                $newStackPtr++;
+                $stackPtr++;
+                continue;
+            }
+
+            /*
+                Before PHP 7, the ??= operator was tokenized as
+                T_INLINE_THEN, T_INLINE_THEN, T_EQUAL.
+                Between PHP 7.0 and 7.2, the ??= operator was tokenized as
+                T_COALESCE, T_EQUAL.
+                So look for and combine these tokens in earlier versions.
+            */
+
+            if (($tokenIsArray === false
+                && $token[0] === '?'
+                && isset($tokens[($stackPtr + 1)]) === true
+                && $tokens[($stackPtr + 1)][0] === '?'
+                && isset($tokens[($stackPtr + 2)]) === true
+                && $tokens[($stackPtr + 2)][0] === '=')
+                || ($tokenIsArray === true
+                && $token[0] === T_COALESCE
+                && isset($tokens[($stackPtr + 1)]) === true
+                && $tokens[($stackPtr + 1)][0] === '=')
+            ) {
+                $newToken            = array();
+                $newToken['code']    = T_COALESCE_EQUAL;
+                $newToken['type']    = 'T_COALESCE_EQUAL';
+                $newToken['content'] = '??=';
+                $finalTokens[$newStackPtr] = $newToken;
+
+                $newStackPtr++;
+                $stackPtr++;
+
+                if ($tokenIsArray === false) {
+                    // Pre PHP 7.
+                    $stackPtr++;
+                }
+
+                continue;
+            }
+
+            /*
+                Before PHP 7, the ?? operator was tokenized as
+                T_INLINE_THEN followed by T_INLINE_THEN.
+                So look for and combine these tokens in earlier versions.
+            */
+
+            if ($tokenIsArray === false
+                && $token[0] === '?'
+                && isset($tokens[($stackPtr + 1)]) === true
+                && $tokens[($stackPtr + 1)][0] === '?'
+            ) {
+                $newToken            = array();
+                $newToken['code']    = T_COALESCE;
+                $newToken['type']    = 'T_COALESCE';
+                $newToken['content'] = '??';
+                $finalTokens[$newStackPtr] = $newToken;
+
+                $newStackPtr++;
+                $stackPtr++;
+                continue;
+            }
+
+            /*
+                Convert ? to T_NULLABLE OR T_INLINE_THEN
+            */
+
+            if ($tokenIsArray === false && $token[0] === '?') {
+                $newToken            = array();
+                $newToken['content'] = '?';
+
+                for ($i = ($stackPtr - 1); $i >= 0; $i--) {
+                    if (is_array($tokens[$i]) === true) {
+                        $tokenType = $tokens[$i][0];
+                    } else {
+                        $tokenType = $tokens[$i];
+                    }
+
+                    if ($tokenType === T_FUNCTION) {
+                        $newToken['code'] = T_NULLABLE;
+                        $newToken['type'] = 'T_NULLABLE';
+                        break;
+                    } else if (in_array($tokenType, array(T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, '{', ';')) === true) {
+                        $newToken['code'] = T_INLINE_THEN;
+                        $newToken['type'] = 'T_INLINE_THEN';
+
+                        $insideInlineIf[] = $stackPtr;
+                        break;
+                    }
+                }
+
+                $finalTokens[$newStackPtr] = $newToken;
+                $newStackPtr++;
+                continue;
+            }//end if
+
+            /*
+                Tokens after a double colon may be look like scope openers,
+                such as when writing code like Foo::NAMESPACE, but they are
+                only ever variables or strings.
+            */
+
+            if ($stackPtr > 1
+                && (is_array($tokens[($stackPtr - 1)]) === true
+                && $tokens[($stackPtr - 1)][0] === T_PAAMAYIM_NEKUDOTAYIM)
+                && $tokenIsArray === true
+                && $token[0] !== T_STRING
+                && $token[0] !== T_VARIABLE
+                && $token[0] !== T_DOLLAR
+                && isset(PHP_CodeSniffer_Tokens::$emptyTokens[$token[0]]) === false
+            ) {
+                $newToken            = array();
+                $newToken['code']    = T_STRING;
+                $newToken['type']    = 'T_STRING';
+                $newToken['content'] = $token[1];
+                $finalTokens[$newStackPtr] = $newToken;
+
+                $newStackPtr++;
+                continue;
+            }
+
+            /*
+                The string-like token after a function keyword should always be
+                tokenized as T_STRING even if it appears to be a different token,
+                such as when writing code like: function default(): foo
+                so go forward and change the token type before it is processed.
+            */
+
+            if ($tokenIsArray === true && $token[0] === T_FUNCTION) {
+                for ($x = ($stackPtr + 1); $x < $numTokens; $x++) {
+                    if (is_array($tokens[$x]) === false
+                        || isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x][0]]) === false
+                    ) {
+                        // Non-empty content.
+                        break;
+                    }
+                }
+
+                if ($x < $numTokens && is_array($tokens[$x]) === true) {
+                    $tokens[$x][0] = T_STRING;
+                }
+            }
+
+            /*
+                Before PHP 7, the <=> operator was tokenized as
+                T_IS_SMALLER_OR_EQUAL followed by T_GREATER_THAN.
+                So look for and combine these tokens in earlier versions.
+            */
+
+            if ($tokenIsArray === true
+                && $token[0] === T_IS_SMALLER_OR_EQUAL
+                && isset($tokens[($stackPtr + 1)]) === true
+                && $tokens[($stackPtr + 1)][0] === '>'
+            ) {
+                $newToken            = array();
+                $newToken['code']    = T_SPACESHIP;
+                $newToken['type']    = 'T_SPACESHIP';
+                $newToken['content'] = '<=>';
+                $finalTokens[$newStackPtr] = $newToken;
+
+                $newStackPtr++;
+                $stackPtr++;
+                continue;
+            }
+
+            /*
+                Emulate traits in PHP versions less than 5.4.
+            */
+
+            if ($tokenIsArray === true
+                && $token[0] === T_STRING
+                && strtolower($token[1]) === 'trait'
+                && $tokens[($stackPtr - 1)][0] !== T_OBJECT_OPERATOR
+                && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM
+            ) {
+                $finalTokens[$newStackPtr] = array(
+                                              'content' => $token[1],
+                                              'code'    => T_TRAIT,
+                                              'type'    => 'T_TRAIT',
+                                             );
+
+                if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                    echo "\t\t* token $stackPtr changed from T_STRING to T_TRAIT".PHP_EOL;
+                }
+
+                $newStackPtr++;
+                continue;
+            }
+
+            /*
+                PHP doesn't assign a token to goto labels, so we have to.
+                These are just string tokens with a single colon after them. Double
+                colons are already tokenized and so don't interfere with this check.
+                But we do have to account for CASE statements, that look just like
+                goto labels.
+            */
+
+            if ($tokenIsArray === true
+                && $token[0] === T_STRING
+                && isset($tokens[($stackPtr + 1)]) === true
+                && $tokens[($stackPtr + 1)] === ':'
+                && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM
+            ) {
+                $stopTokens = array(
+                               T_CASE               => true,
+                               T_SEMICOLON          => true,
+                               T_OPEN_CURLY_BRACKET => true,
+                               T_INLINE_THEN        => true,
+                              );
+
+                for ($x = ($newStackPtr - 1); $x > 0; $x--) {
+                    if (isset($stopTokens[$finalTokens[$x]['code']]) === true) {
+                        break;
+                    }
+                }
+
+                if ($finalTokens[$x]['code'] !== T_CASE
+                    && $finalTokens[$x]['code'] !== T_INLINE_THEN
+                ) {
+                    $finalTokens[$newStackPtr] = array(
+                                                  'content' => $token[1].':',
+                                                  'code'    => T_GOTO_LABEL,
+                                                  'type'    => 'T_GOTO_LABEL',
+                                                 );
+
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        echo "\t\t* token $stackPtr changed from T_STRING to T_GOTO_LABEL".PHP_EOL;
+                        echo "\t\t* skipping T_COLON token ".($stackPtr + 1).PHP_EOL;
+                    }
+
+                    $newStackPtr++;
+                    $stackPtr++;
+                    continue;
+                }
+            }//end if
+
+            /*
+                HHVM 3.5 tokenizes "else[\s]+if" as a T_ELSEIF token while PHP
+                proper only tokenizes "elseif" as a T_ELSEIF token. So split
+                up the HHVM token to make it looks like proper PHP.
+            */
+
+            if ($tokenIsArray === true
+                && $token[0] === T_ELSEIF
+                && strtolower($token[1]) !== 'elseif'
+            ) {
+                $finalTokens[$newStackPtr] = array(
+                                              'content' => substr($token[1], 0, 4),
+                                              'code'    => T_ELSE,
+                                              'type'    => 'T_ELSE',
+                                             );
+
+                $newStackPtr++;
+                $finalTokens[$newStackPtr] = array(
+                                              'content' => substr($token[1], 4, -2),
+                                              'code'    => T_WHITESPACE,
+                                              'type'    => 'T_WHITESPACE',
+                                             );
+
+                $newStackPtr++;
+                $finalTokens[$newStackPtr] = array(
+                                              'content' => substr($token[1], -2),
+                                              'code'    => T_IF,
+                                              'type'    => 'T_IF',
+                                             );
+
+                if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                    echo "\t\t* token $stackPtr changed from T_ELSEIF to T_ELSE/T_WHITESPACE/T_IF".PHP_EOL;
+                }
+
+                $newStackPtr++;
+                continue;
+            }//end if
+
+            /*
+                HHVM 3.5 and 3.6 tokenizes a hashbang line such as #!/usr/bin/php
+                as T_HASHANG while PHP proper uses T_INLINE_HTML.
+            */
+
+            if ($tokenIsArray === true && token_name($token[0]) === 'T_HASHBANG') {
+                $finalTokens[$newStackPtr] = array(
+                                              'content' => $token[1],
+                                              'code'    => T_INLINE_HTML,
+                                              'type'    => 'T_INLINE_HTML',
+                                             );
+
+                if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                    echo "\t\t* token $stackPtr changed from T_HASHBANG to T_INLINE_HTML".PHP_EOL;
+                }
+
+                $newStackPtr++;
+                continue;
+            }//end if
+
+            /*
+                If this token has newlines in its content, split each line up
+                and create a new token for each line. We do this so it's easier
+                to ascertain where errors occur on a line.
+                Note that $token[1] is the token's content.
+            */
+
+            if ($tokenIsArray === true && strpos($token[1], $eolChar) !== false) {
+                $tokenLines = explode($eolChar, $token[1]);
+                $numLines   = count($tokenLines);
+                $newToken   = array(
+                               'type'    => token_name($token[0]),
+                               'code'    => $token[0],
+                               'content' => '',
+                              );
+
+                for ($i = 0; $i < $numLines; $i++) {
+                    $newToken['content'] = $tokenLines[$i];
+                    if ($i === ($numLines - 1)) {
+                        if ($tokenLines[$i] === '') {
+                            break;
+                        }
+                    } else {
+                        $newToken['content'] .= $eolChar;
+                    }
+
+                    $finalTokens[$newStackPtr] = $newToken;
+                    $newStackPtr++;
+                }
+            } else {
+                if ($tokenIsArray === true && $token[0] === T_STRING) {
+                    // Some T_STRING tokens should remain that way
+                    // due to their context.
+                    $context = array(
+                                T_OBJECT_OPERATOR      => true,
+                                T_FUNCTION             => true,
+                                T_CLASS                => true,
+                                T_EXTENDS              => true,
+                                T_IMPLEMENTS           => true,
+                                T_NEW                  => true,
+                                T_CONST                => true,
+                                T_NS_SEPARATOR         => true,
+                                T_USE                  => true,
+                                T_NAMESPACE            => true,
+                                T_PAAMAYIM_NEKUDOTAYIM => true,
+                               );
+                    if (isset($context[$finalTokens[$lastNotEmptyToken]['code']]) === true) {
+                        // Special case for syntax like: return new self
+                        // where self should not be a string.
+                        if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW
+                            && strtolower($token[1]) === 'self'
+                        ) {
+                            $finalTokens[$newStackPtr] = array(
+                                                          'content' => $token[1],
+                                                          'code'    => T_SELF,
+                                                          'type'    => 'T_SELF',
+                                                         );
+                        } else {
+                            $finalTokens[$newStackPtr] = array(
+                                                          'content' => $token[1],
+                                                          'code'    => T_STRING,
+                                                          'type'    => 'T_STRING',
+                                                         );
+                        }
+
+                        $newStackPtr++;
+                        continue;
+                    }//end if
+                }//end if
+
+                $newToken = null;
+                if ($tokenIsArray === false) {
+                    if (isset(self::$_resolveTokenCache[$token[0]]) === true) {
+                        $newToken = self::$_resolveTokenCache[$token[0]];
+                    }
+                } else {
+                    $cacheKey = null;
+                    if ($token[0] === T_STRING) {
+                        $cacheKey = strtolower($token[1]);
+                    } else if ($token[0] !== T_CURLY_OPEN) {
+                        $cacheKey = $token[0];
+                    }
+
+                    if ($cacheKey !== null && isset(self::$_resolveTokenCache[$cacheKey]) === true) {
+                        $newToken            = self::$_resolveTokenCache[$cacheKey];
+                        $newToken['content'] = $token[1];
+                    }
+                }
+
+                if ($newToken === null) {
+                    $newToken = self::standardiseToken($token);
+                }
+
+                // Convert colons that are actually the ELSE component of an
+                // inline IF statement.
+                if (empty($insideInlineIf) === false && $newToken['code'] === T_COLON) {
+                    array_pop($insideInlineIf);
+                    $newToken['code'] = T_INLINE_ELSE;
+                    $newToken['type'] = 'T_INLINE_ELSE';
+                }
+
+                // This is a special condition for T_ARRAY tokens used for
+                // type hinting function arguments as being arrays. We want to keep
+                // the parenthesis map clean, so let's tag these tokens as
+                // T_ARRAY_HINT.
+                if ($newToken['code'] === T_ARRAY) {
+                    for ($i = $stackPtr; $i < $numTokens; $i++) {
+                        if ($tokens[$i] === '(') {
+                            break;
+                        } else if ($tokens[$i][0] === T_VARIABLE) {
+                            $newToken['code'] = T_ARRAY_HINT;
+                            $newToken['type'] = 'T_ARRAY_HINT';
+                            break;
+                        }
+                    }
+                }
+
+                // This is a special case when checking PHP 5.5+ code in PHP < 5.5
+                // where "finally" should be T_FINALLY instead of T_STRING.
+                if ($newToken['code'] === T_STRING
+                    && strtolower($newToken['content']) === 'finally'
+                ) {
+                    $newToken['code'] = T_FINALLY;
+                    $newToken['type'] = 'T_FINALLY';
+                }
+
+                // This is a special case for the PHP 5.5 classname::class syntax
+                // where "class" should be T_STRING instead of T_CLASS.
+                if (($newToken['code'] === T_CLASS
+                    || $newToken['code'] === T_FUNCTION)
+                    && $finalTokens[($newStackPtr - 1)]['code'] === T_DOUBLE_COLON
+                ) {
+                    $newToken['code'] = T_STRING;
+                    $newToken['type'] = 'T_STRING';
+                }
+
+                // This is a special case for PHP 5.6 use function and use const
+                // where "function" and "const" should be T_STRING instead of T_FUNCTION
+                // and T_CONST.
+                if (($newToken['code'] === T_FUNCTION
+                    || $newToken['code'] === T_CONST)
+                    && $finalTokens[$lastNotEmptyToken]['code'] === T_USE
+                ) {
+                    $newToken['code'] = T_STRING;
+                    $newToken['type'] = 'T_STRING';
+                }
+
+                // This is a special case for use groups in PHP 7+ where leaving
+                // the curly braces as their normal tokens would confuse
+                // the scope map and sniffs.
+                if ($newToken['code'] === T_OPEN_CURLY_BRACKET
+                    && $finalTokens[$lastNotEmptyToken]['code'] === T_NS_SEPARATOR
+                ) {
+                    $newToken['code'] = T_OPEN_USE_GROUP;
+                    $newToken['type'] = 'T_OPEN_USE_GROUP';
+                    $insideUseGroup   = true;
+                }
+
+                if ($insideUseGroup === true && $newToken['code'] === T_CLOSE_CURLY_BRACKET) {
+                    $newToken['code'] = T_CLOSE_USE_GROUP;
+                    $newToken['type'] = 'T_CLOSE_USE_GROUP';
+                    $insideUseGroup   = false;
+                }
+
+                $finalTokens[$newStackPtr] = $newToken;
+                $newStackPtr++;
+            }//end if
+        }//end for
+
+        if (PHP_CODESNIFFER_VERBOSITY > 1) {
+            echo "\t*** END PHP TOKENIZING ***".PHP_EOL;
+        }
+
+        return $finalTokens;
+
+    }//end tokenizeString()
+
+
+    /**
+     * Performs additional processing after main tokenizing.
+     *
+     * This additional processing checks for CASE statements that are using curly
+     * braces for scope openers and closers. It also turns some T_FUNCTION tokens
+     * into T_CLOSURE when they are not standard function definitions. It also
+     * detects short array syntax and converts those square brackets into new tokens.
+     * It also corrects some usage of the static and class keywords. It also
+     * assigns tokens to function return types.
+     *
+     * @param array  $tokens  The array of tokens to process.
+     * @param string $eolChar The EOL character to use for splitting strings.
+     *
+     * @return void
+     */
+    public function processAdditional(&$tokens, $eolChar)
+    {
+        if (PHP_CODESNIFFER_VERBOSITY > 1) {
+            echo "\t*** START ADDITIONAL PHP PROCESSING ***".PHP_EOL;
+        }
+
+        $numTokens = count($tokens);
+        for ($i = ($numTokens - 1); $i >= 0; $i--) {
+            // Check for any unset scope conditions due to alternate IF/ENDIF syntax.
+            if (isset($tokens[$i]['scope_opener']) === true
+                && isset($tokens[$i]['scope_condition']) === false
+            ) {
+                $tokens[$i]['scope_condition'] = $tokens[$tokens[$i]['scope_opener']]['scope_condition'];
+            }
+
+            if ($tokens[$i]['code'] === T_FUNCTION) {
+                /*
+                    Detect functions that are actually closures and
+                    assign them a different token.
+                */
+
+                if (isset($tokens[$i]['scope_opener']) === true) {
+                    for ($x = ($i + 1); $x < $numTokens; $x++) {
+                        if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false
+                            && $tokens[$x]['code'] !== T_BITWISE_AND
+                        ) {
+                            break;
+                        }
+                    }
+
+                    if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
+                        $tokens[$i]['code'] = T_CLOSURE;
+                        $tokens[$i]['type'] = 'T_CLOSURE';
+                        if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                            $line = $tokens[$i]['line'];
+                            echo "\t* token $i on line $line changed from T_FUNCTION to T_CLOSURE".PHP_EOL;
+                        }
+
+                        for ($x = ($tokens[$i]['scope_opener'] + 1); $x < $tokens[$i]['scope_closer']; $x++) {
+                            if (isset($tokens[$x]['conditions'][$i]) === false) {
+                                continue;
+                            }
+
+                            $tokens[$x]['conditions'][$i] = T_CLOSURE;
+                            if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                                $type = $tokens[$x]['type'];
+                                echo "\t\t* cleaned $x ($type) *".PHP_EOL;
+                            }
+                        }
+                    }
+
+                    $tokenAfterReturnTypeHint = $tokens[$i]['scope_opener'];
+                } else if (isset($tokens[$i]['parenthesis_closer']) === true) {
+                    $tokenAfterReturnTypeHint = null;
+                    for ($x = ($tokens[$i]['parenthesis_closer'] + 1); $x < $numTokens; $x++) {
+                        if ($tokens[$x]['code'] === T_SEMICOLON) {
+                            $tokenAfterReturnTypeHint = $x;
+                            break;
+                        }
+                    }
+
+                    if ($tokenAfterReturnTypeHint === null) {
+                        // Probably a syntax error.
+                        continue;
+                    }
+                } else {
+                    // Probably a syntax error.
+                    continue;
+                }//end if
+
+                /*
+                    Detect function return values and assign them
+                    a special token, because PHP doesn't.
+                */
+
+                for ($x = ($tokenAfterReturnTypeHint - 1); $x > $i; $x--) {
+                    if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
+                        if (in_array($tokens[$x]['code'], array(T_STRING, T_ARRAY, T_ARRAY_HINT, T_CALLABLE, T_SELF, T_PARENT), true) === true) {
+                            if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                                $line = $tokens[$x]['line'];
+                                $type = $tokens[$x]['type'];
+                                echo "\t* token $x on line $line changed from $type to T_RETURN_TYPE".PHP_EOL;
+                            }
+
+                            $tokens[$x]['code'] = T_RETURN_TYPE;
+                            $tokens[$x]['type'] = 'T_RETURN_TYPE';
+                        }
+
+                        break;
+                    }
+                }
+
+                continue;
+            } else if ($tokens[$i]['code'] === T_CLASS && isset($tokens[$i]['scope_opener']) === true) {
+                /*
+                    Detect anonymous classes and assign them a different token.
+                */
+
+                for ($x = ($i + 1); $x < $numTokens; $x++) {
+                    if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
+                        break;
+                    }
+                }
+
+                if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS
+                    || $tokens[$x]['code'] === T_OPEN_CURLY_BRACKET
+                    || $tokens[$x]['code'] === T_EXTENDS
+                    || $tokens[$x]['code'] === T_IMPLEMENTS
+                ) {
+                    $tokens[$i]['code'] = T_ANON_CLASS;
+                    $tokens[$i]['type'] = 'T_ANON_CLASS';
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        $line = $tokens[$i]['line'];
+                        echo "\t* token $i on line $line changed from T_CLASS to T_ANON_CLASS".PHP_EOL;
+                    }
+
+                    for ($x = ($tokens[$i]['scope_opener'] + 1); $x < $tokens[$i]['scope_closer']; $x++) {
+                        if (isset($tokens[$x]['conditions'][$i]) === false) {
+                            continue;
+                        }
+
+                        $tokens[$x]['conditions'][$i] = T_ANON_CLASS;
+                        if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                            $type = $tokens[$x]['type'];
+                            echo "\t\t* cleaned $x ($type) *".PHP_EOL;
+                        }
+                    }
+                }
+
+                continue;
+            } else if ($tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) {
+                if (isset($tokens[$i]['bracket_closer']) === false) {
+                    continue;
+                }
+
+                // Unless there is a variable or a bracket before this token,
+                // it is the start of an array being defined using the short syntax.
+                $isShortArray = false;
+                $allowed      = array(
+                                 T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET,
+                                 T_CLOSE_PARENTHESIS    => T_CLOSE_PARENTHESIS,
+                                 T_VARIABLE             => T_VARIABLE,
+                                 T_OBJECT_OPERATOR      => T_OBJECT_OPERATOR,
+                                 T_STRING               => T_STRING,
+                                );
+
+                for ($x = ($i - 1); $x > 0; $x--) {
+                    // If we hit a scope opener, the statement has ended
+                    // without finding anything, so it's probably an array
+                    // using PHP 7.1 short list syntax.
+                    if (isset($tokens[$x]['scope_opener']) === true) {
+                        $isShortArray = true;
+                        break;
+                    }
+
+                    if (isset($tokens[$x]['bracket_opener']) === true
+                        && $x > $tokens[$x]['bracket_opener']
+                    ) {
+                        $x = $tokens[$x]['bracket_opener'];
+                        continue;
+                    }
+
+                    if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
+                        if (isset($allowed[$tokens[$x]['code']]) === false) {
+                            $isShortArray = true;
+                        }
+
+                        break;
+                    }
+                }//end for
+
+                if ($isShortArray === true) {
+                    $tokens[$i]['code'] = T_OPEN_SHORT_ARRAY;
+                    $tokens[$i]['type'] = 'T_OPEN_SHORT_ARRAY';
+
+                    $closer = $tokens[$i]['bracket_closer'];
+                    $tokens[$closer]['code'] = T_CLOSE_SHORT_ARRAY;
+                    $tokens[$closer]['type'] = 'T_CLOSE_SHORT_ARRAY';
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        $line = $tokens[$i]['line'];
+                        echo "\t* token $i on line $line changed from T_OPEN_SQUARE_BRACKET to T_OPEN_SHORT_ARRAY".PHP_EOL;
+                        $line = $tokens[$closer]['line'];
+                        echo "\t* token $closer on line $line changed from T_CLOSE_SQUARE_BRACKET to T_CLOSE_SHORT_ARRAY".PHP_EOL;
+                    }
+                }
+
+                continue;
+            } else if ($tokens[$i]['code'] === T_STATIC) {
+                for ($x = ($i - 1); $x > 0; $x--) {
+                    if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
+                        break;
+                    }
+                }
+
+                if ($tokens[$x]['code'] === T_INSTANCEOF) {
+                    $tokens[$i]['code'] = T_STRING;
+                    $tokens[$i]['type'] = 'T_STRING';
+
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        $line = $tokens[$i]['line'];
+                        echo "\t* token $i on line $line changed from T_STATIC to T_STRING".PHP_EOL;
+                    }
+                }
+
+                continue;
+            } else if ($tokens[$i]['code'] === T_ECHO && $tokens[$i]['content'] === '<?=') {
+                // HHVM tokenizes <?= as T_ECHO but it should be T_OPEN_TAG_WITH_ECHO.
+                $tokens[$i]['code'] = T_OPEN_TAG_WITH_ECHO;
+                $tokens[$i]['type'] = 'T_OPEN_TAG_WITH_ECHO';
+
+                if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                    $line = $tokens[$i]['line'];
+                    echo "\t* token $i on line $line changed from T_ECHO to T_OPEN_TAG_WITH_ECHO".PHP_EOL;
+                }
+            } else if ($tokens[$i]['code'] === T_TRUE
+                || $tokens[$i]['code'] === T_FALSE
+                || $tokens[$i]['code'] === T_NULL
+            ) {
+                for ($x = ($i + 1); $i < $numTokens; $x++) {
+                    if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
+                        // Non-whitespace content.
+                        break;
+                    }
+                }
+
+                $context = array(
+                            T_OBJECT_OPERATOR      => true,
+                            T_NS_SEPARATOR         => true,
+                            T_PAAMAYIM_NEKUDOTAYIM => true,
+                           );
+                if (isset($context[$tokens[$x]['code']]) === true) {
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        $line = $tokens[$i]['line'];
+                        $type = $tokens[$i]['type'];
+                        echo "\t* token $i on line $line changed from $type to T_STRING".PHP_EOL;
+                    }
+
+                    $tokens[$i]['code'] = T_STRING;
+                    $tokens[$i]['type'] = 'T_STRING';
+                }
+            } else if ($tokens[$i]['code'] === T_CONST) {
+                // Context sensitive keywords support.
+                for ($x = ($i + 1); $i < $numTokens; $x++) {
+                    if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
+                        // Non-whitespace content.
+                        break;
+                    }
+                }
+
+                if ($tokens[$x]['code'] !== T_STRING) {
+                    if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                        $line = $tokens[$x]['line'];
+                        $type = $tokens[$x]['type'];
+                        echo "\t* token $x on line $line changed from $type to T_STRING".PHP_EOL;
+                    }
+
+                    $tokens[$x]['code'] = T_STRING;
+                    $tokens[$x]['type'] = 'T_STRING';
+                }
+            }//end if
+
+            if (($tokens[$i]['code'] !== T_CASE
+                && $tokens[$i]['code'] !== T_DEFAULT)
+                || isset($tokens[$i]['scope_opener']) === false
+            ) {
+                // Only interested in CASE and DEFAULT statements from here on in.
+                continue;
+            }
+
+            $scopeOpener = $tokens[$i]['scope_opener'];
+            $scopeCloser = $tokens[$i]['scope_closer'];
+
+            // If the first char after the opener is a curly brace
+            // and that brace has been ignored, it is actually
+            // opening this case statement and the opener and closer are
+            // probably set incorrectly.
+            for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) {
+                if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
+                    // Non-whitespace content.
+                    break;
+                }
+            }
+
+            if ($tokens[$x]['code'] === T_CASE || $tokens[$x]['code'] === T_DEFAULT) {
+                // Special case for multiple CASE statements that share the same
+                // closer. Because we are going backwards through the file, this next
+                // CASE/DEFAULT statement is already fixed, so just use its closer
+                // and don't worry about fixing anything.
+                $newCloser = $tokens[$x]['scope_closer'];
+                $tokens[$i]['scope_closer'] = $newCloser;
+                if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                    $oldType = $tokens[$scopeCloser]['type'];
+                    $newType = $tokens[$newCloser]['type'];
+                    $line    = $tokens[$i]['line'];
+                    echo "\t* token $i (T_CASE) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
+                }
+
+                continue;
+            }
+
+            if ($tokens[$x]['code'] !== T_OPEN_CURLY_BRACKET
+                || isset($tokens[$x]['scope_condition']) === true
+            ) {
+                // Not a CASE/DEFAULT with a curly brace opener.
+                continue;
+            }
+
+            // The closer for this CASE/DEFAULT should be the closing curly brace and
+            // not whatever it already is. The opener needs to be the opening curly
+            // brace so everything matches up.
+            $newCloser = $tokens[$x]['bracket_closer'];
+            foreach (array($i, $x, $newCloser) as $index) {
+                $tokens[$index]['scope_condition'] = $i;
+                $tokens[$index]['scope_opener']    = $x;
+                $tokens[$index]['scope_closer']    = $newCloser;
+            }
+
+            unset($tokens[$scopeOpener]['scope_condition']);
+            unset($tokens[$scopeOpener]['scope_opener']);
+            unset($tokens[$scopeOpener]['scope_closer']);
+            unset($tokens[$scopeCloser]['scope_condition']);
+            unset($tokens[$scopeCloser]['scope_opener']);
+            unset($tokens[$scopeCloser]['scope_closer']);
+            unset($tokens[$x]['bracket_opener']);
+            unset($tokens[$x]['bracket_closer']);
+            unset($tokens[$newCloser]['bracket_opener']);
+            unset($tokens[$newCloser]['bracket_closer']);
+            $tokens[$scopeCloser]['conditions'][] = $i;
+
+            if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                $line      = $tokens[$i]['line'];
+                $tokenType = $tokens[$i]['type'];
+
+                $oldType = $tokens[$scopeOpener]['type'];
+                $newType = $tokens[$x]['type'];
+                echo "\t* token $i ($tokenType) on line $line opener changed from $scopeOpener ($oldType) to $x ($newType)".PHP_EOL;
+
+                $oldType = $tokens[$scopeCloser]['type'];
+                $newType = $tokens[$newCloser]['type'];
+                echo "\t* token $i ($tokenType) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
+            }
+
+            // Now fix up all the tokens that think they are
+            // inside the CASE/DEFAULT statement when they are really outside.
+            for ($x = $newCloser; $x < $scopeCloser; $x++) {
+                foreach ($tokens[$x]['conditions'] as $num => $oldCond) {
+                    if ($oldCond === $tokens[$i]['code']) {
+                        $oldConditions = $tokens[$x]['conditions'];
+                        unset($tokens[$x]['conditions'][$num]);
+
+                        if (PHP_CODESNIFFER_VERBOSITY > 1) {
+                            $type     = $tokens[$x]['type'];
+                            $oldConds = '';
+                            foreach ($oldConditions as $condition) {
+                                $oldConds .= token_name($condition).',';
+                            }
+
+                            $oldConds = rtrim($oldConds, ',');
+
+                            $newConds = '';
+                            foreach ($tokens[$x]['conditions'] as $condition) {
+                                $newConds .= token_name($condition).',';
+                            }
+
+                            $newConds = rtrim($newConds, ',');
+
+                            echo "\t\t* cleaned $x ($type) *".PHP_EOL;
+                            echo "\t\t\t=> conditions changed from $oldConds to $newConds".PHP_EOL;
+                        }
+
+                        break;
+                    }//end if
+                }//end foreach
+            }//end for
+        }//end for
+
+        if (PHP_CODESNIFFER_VERBOSITY > 1) {
+            echo "\t*** END ADDITIONAL PHP PROCESSING ***".PHP_EOL;
+        }
+
+    }//end processAdditional()
+
+
+    /**
+     * Takes a token produced from <code>token_get_all()</code> and produces a
+     * more uniform token.
+     *
+     * @param string|array $token The token to convert.
+     *
+     * @return array The new token.
+     */
+    public static function standardiseToken($token)
+    {
+        if (isset($token[1]) === false) {
+            if (isset(self::$_resolveTokenCache[$token[0]]) === true) {
+                return self::$_resolveTokenCache[$token[0]];
+            }
+        } else {
+            $cacheKey = null;
+            if ($token[0] === T_STRING) {
+                $cacheKey = strtolower($token[1]);
+            } else if ($token[0] !== T_CURLY_OPEN) {
+                $cacheKey = $token[0];
+            }
+
+            if ($cacheKey !== null && isset(self::$_resolveTokenCache[$cacheKey]) === true) {
+                $newToken            = self::$_resolveTokenCache[$cacheKey];
+                $newToken['content'] = $token[1];
+                return $newToken;
+            }
+        }
+
+        if (isset($token[1]) === false) {
+            return self::resolveSimpleToken($token[0]);
+        }
+
+        if ($token[0] === T_STRING) {
+            switch ($cacheKey) {
+            case 'false':
+                $newToken['type'] = 'T_FALSE';
+                break;
+            case 'true':
+                $newToken['type'] = 'T_TRUE';
+                break;
+            case 'null':
+                $newToken['type'] = 'T_NULL';
+                break;
+            case 'self':
+                $newToken['type'] = 'T_SELF';
+                break;
+            case 'parent':
+                $newToken['type'] = 'T_PARENT';
+                break;
+            default:
+                $newToken['type'] = 'T_STRING';
+                break;
+            }
+
+            $newToken['code'] = constant($newToken['type']);
+
+            self::$_resolveTokenCache[$cacheKey] = $newToken;
+        } else if ($token[0] === T_CURLY_OPEN) {
+            $newToken = array(
+                         'code' => T_OPEN_CURLY_BRACKET,
+                         'type' => 'T_OPEN_CURLY_BRACKET',
+                        );
+        } else {
+            $newToken = array(
+                         'code' => $token[0],
+                         'type' => token_name($token[0]),
+                        );
+
+            self::$_resolveTokenCache[$token[0]] = $newToken;
+        }//end if
+
+        $newToken['content'] = $token[1];
+        return $newToken;
+
+    }//end standardiseToken()
+
+
+    /**
+     * Converts simple tokens into a format that conforms to complex tokens
+     * produced by token_get_all().
+     *
+     * Simple tokens are tokens that are not in array form when produced from
+     * token_get_all().
+     *
+     * @param string $token The simple token to convert.
+     *
+     * @return array The new token in array format.
+     */
+    public static function resolveSimpleToken($token)
+    {
+        $newToken = array();
+
+        switch ($token) {
+        case '{':
+            $newToken['type'] = 'T_OPEN_CURLY_BRACKET';
+            break;
+        case '}':
+            $newToken['type'] = 'T_CLOSE_CURLY_BRACKET';
+            break;
+        case '[':
+            $newToken['type'] = 'T_OPEN_SQUARE_BRACKET';
+            break;
+        case ']':
+            $newToken['type'] = 'T_CLOSE_SQUARE_BRACKET';
+            break;
+        case '(':
+            $newToken['type'] = 'T_OPEN_PARENTHESIS';
+            break;
+        case ')':
+            $newToken['type'] = 'T_CLOSE_PARENTHESIS';
+            break;
+        case ':':
+            $newToken['type'] = 'T_COLON';
+            break;
+        case '.':
+            $newToken['type'] = 'T_STRING_CONCAT';
+            break;
+        case ';':
+            $newToken['type'] = 'T_SEMICOLON';
+            break;
+        case '=':
+            $newToken['type'] = 'T_EQUAL';
+            break;
+        case '*':
+            $newToken['type'] = 'T_MULTIPLY';
+            break;
+        case '/':
+            $newToken['type'] = 'T_DIVIDE';
+            break;
+        case '+':
+            $newToken['type'] = 'T_PLUS';
+            break;
+        case '-':
+            $newToken['type'] = 'T_MINUS';
+            break;
+        case '%':
+            $newToken['type'] = 'T_MODULUS';
+            break;
+        case '^':
+            $newToken['type'] = 'T_BITWISE_XOR';
+            break;
+        case '&':
+            $newToken['type'] = 'T_BITWISE_AND';
+            break;
+        case '|':
+            $newToken['type'] = 'T_BITWISE_OR';
+            break;
+        case '<':
+            $newToken['type'] = 'T_LESS_THAN';
+            break;
+        case '>':
+            $newToken['type'] = 'T_GREATER_THAN';
+            break;
+        case '!':
+            $newToken['type'] = 'T_BOOLEAN_NOT';
+            break;
+        case ',':
+            $newToken['type'] = 'T_COMMA';
+            break;
+        case '@':
+            $newToken['type'] = 'T_ASPERAND';
+            break;
+        case '$':
+            $newToken['type'] = 'T_DOLLAR';
+            break;
+        case '`':
+            $newToken['type'] = 'T_BACKTICK';
+            break;
+        default:
+            $newToken['type'] = 'T_NONE';
+            break;
+        }//end switch
+
+        $newToken['code']    = constant($newToken['type']);
+        $newToken['content'] = $token;
+
+        self::$_resolveTokenCache[$token] = $newToken;
+        return $newToken;
+
+    }//end resolveSimpleToken()
+
+
+}//end class