|
10 | 10 |
|
11 | 11 | namespace PHP_CodeSniffer\Util; |
12 | 12 |
|
| 13 | +// PHPCS native tokens. |
13 | 14 | define('T_NONE', 'PHPCS_T_NONE'); |
14 | 15 | define('T_OPEN_CURLY_BRACKET', 'PHPCS_T_OPEN_CURLY_BRACKET'); |
15 | 16 | define('T_CLOSE_CURLY_BRACKET', 'PHPCS_T_CLOSE_CURLY_BRACKET'); |
|
70 | 71 | define('T_TYPE_OPEN_PARENTHESIS', 'PHPCS_T_TYPE_OPEN_PARENTHESIS'); |
71 | 72 | define('T_TYPE_CLOSE_PARENTHESIS', 'PHPCS_T_TYPE_CLOSE_PARENTHESIS'); |
72 | 73 |
|
73 | | -/* |
74 | | - * {@internal IMPORTANT: all PHP native polyfilled tokens MUST be added to the |
75 | | - * `PHP_CodeSniffer\Tests\Core\Util\Tokens\TokenNameTest::dataPolyfilledPHPNativeTokens()` test method!} |
76 | | - */ |
77 | | - |
78 | | -// Some PHP 7.4 tokens, replicated for lower versions. |
79 | | -if (defined('T_COALESCE_EQUAL') === false) { |
80 | | - define('T_COALESCE_EQUAL', 'PHPCS_T_COALESCE_EQUAL'); |
81 | | -} |
82 | | - |
83 | | -if (defined('T_BAD_CHARACTER') === false) { |
84 | | - define('T_BAD_CHARACTER', 'PHPCS_T_BAD_CHARACTER'); |
85 | | -} |
86 | | - |
87 | | -if (defined('T_FN') === false) { |
88 | | - define('T_FN', 'PHPCS_T_FN'); |
89 | | -} |
90 | | - |
91 | | -// Some PHP 8.0 tokens, replicated for lower versions. |
92 | | -if (defined('T_NULLSAFE_OBJECT_OPERATOR') === false) { |
93 | | - define('T_NULLSAFE_OBJECT_OPERATOR', 'PHPCS_T_NULLSAFE_OBJECT_OPERATOR'); |
94 | | -} |
95 | | - |
96 | | -if (defined('T_NAME_QUALIFIED') === false) { |
97 | | - define('T_NAME_QUALIFIED', 'PHPCS_T_NAME_QUALIFIED'); |
98 | | -} |
99 | | - |
100 | | -if (defined('T_NAME_FULLY_QUALIFIED') === false) { |
101 | | - define('T_NAME_FULLY_QUALIFIED', 'PHPCS_T_NAME_FULLY_QUALIFIED'); |
102 | | -} |
103 | | - |
104 | | -if (defined('T_NAME_RELATIVE') === false) { |
105 | | - define('T_NAME_RELATIVE', 'PHPCS_T_NAME_RELATIVE'); |
106 | | -} |
107 | | - |
108 | | -if (defined('T_MATCH') === false) { |
109 | | - define('T_MATCH', 'PHPCS_T_MATCH'); |
110 | | -} |
111 | | - |
112 | | -if (defined('T_ATTRIBUTE') === false) { |
113 | | - define('T_ATTRIBUTE', 'PHPCS_T_ATTRIBUTE'); |
114 | | -} |
115 | | - |
116 | | -// Some PHP 8.1 tokens, replicated for lower versions. |
117 | | -if (defined('T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG') === false) { |
118 | | - define('T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG', 'PHPCS_T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG'); |
119 | | -} |
120 | | - |
121 | | -if (defined('T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG') === false) { |
122 | | - define('T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', 'PHPCS_T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG'); |
123 | | -} |
124 | | - |
125 | | -if (defined('T_READONLY') === false) { |
126 | | - define('T_READONLY', 'PHPCS_T_READONLY'); |
127 | | -} |
128 | | - |
129 | | -if (defined('T_ENUM') === false) { |
130 | | - define('T_ENUM', 'PHPCS_T_ENUM'); |
131 | | -} |
132 | | - |
133 | | -// Some PHP 8.4 tokens, replicated for lower versions. |
134 | | -if (defined('T_PUBLIC_SET') === false) { |
135 | | - define('T_PUBLIC_SET', 'PHPCS_T_PUBLIC_SET'); |
136 | | -} |
137 | | - |
138 | | -if (defined('T_PROTECTED_SET') === false) { |
139 | | - define('T_PROTECTED_SET', 'PHPCS_T_PROTECTED_SET'); |
140 | | -} |
141 | | - |
142 | | -if (defined('T_PRIVATE_SET') === false) { |
143 | | - define('T_PRIVATE_SET', 'PHPCS_T_PRIVATE_SET'); |
144 | | -} |
145 | | - |
146 | | -// Some PHP 8.5 tokens, replicated for lower versions. |
147 | | -if (defined('T_VOID_CAST') === false) { |
148 | | - define('T_VOID_CAST', 'PHPCS_T_VOID_CAST'); |
149 | | -} |
150 | | - |
151 | 74 | // Tokens used for parsing doc blocks. |
152 | 75 | define('T_DOC_COMMENT_STAR', 'PHPCS_T_DOC_COMMENT_STAR'); |
153 | 76 | define('T_DOC_COMMENT_WHITESPACE', 'PHPCS_T_DOC_COMMENT_WHITESPACE'); |
|
163 | 86 | define('T_PHPCS_IGNORE', 'PHPCS_T_PHPCS_IGNORE'); |
164 | 87 | define('T_PHPCS_IGNORE_FILE', 'PHPCS_T_PHPCS_IGNORE_FILE'); |
165 | 88 |
|
| 89 | +Tokens::polyfillTokenizerConstants(); |
| 90 | + |
166 | 91 | final class Tokens |
167 | 92 | { |
168 | 93 |
|
@@ -612,6 +537,13 @@ final class Tokens |
612 | 537 | T_YIELD_FROM => T_YIELD_FROM, |
613 | 538 | ]; |
614 | 539 |
|
| 540 | + /** |
| 541 | + * Mapping table for polyfilled constants |
| 542 | + * |
| 543 | + * @var array<int, string> |
| 544 | + */ |
| 545 | + private static $polyfillMappingTable = []; |
| 546 | + |
615 | 547 | /** |
616 | 548 | * The token weightings. |
617 | 549 | * |
@@ -943,12 +875,12 @@ final class Tokens |
943 | 875 | */ |
944 | 876 | public static function tokenName($token) |
945 | 877 | { |
946 | | - if (is_string($token) === false) { |
947 | | - // PHP-supplied token name. |
948 | | - return token_name($token); |
| 878 | + if (is_string($token) === true) { |
| 879 | + // PHPCS native token. |
| 880 | + return substr($token, 6); |
949 | 881 | } |
950 | 882 |
|
951 | | - return substr($token, 6); |
| 883 | + return (self::$polyfillMappingTable[$token] ?? token_name($token)); |
952 | 884 | } |
953 | 885 |
|
954 | 886 |
|
@@ -991,4 +923,66 @@ public static function getHighestWeightedToken(array $tokens) |
991 | 923 |
|
992 | 924 | return $highestType; |
993 | 925 | } |
| 926 | + |
| 927 | + |
| 928 | + /** |
| 929 | + * Polyfill tokenizer (T_*) constants. |
| 930 | + * |
| 931 | + * {@internal IMPORTANT: all PHP native polyfilled tokens MUST be added to the |
| 932 | + * `PHP_CodeSniffer\Tests\Core\Util\Tokens\TokenNameTest::dataPolyfilledPHPNativeTokens()` test method!} |
| 933 | + * |
| 934 | + * @return void |
| 935 | + */ |
| 936 | + public static function polyfillTokenizerConstants(): void |
| 937 | + { |
| 938 | + // Ideally this would be a private class constant. We cannot do that |
| 939 | + // here as the constants that we are polyfilling in this method are |
| 940 | + // used in some of the class constants for this class. If we reference |
| 941 | + // any class constants or properties before this method has fully run, |
| 942 | + // PHP will intitialise the class, leading to warnings about undefined |
| 943 | + // T_* constants. |
| 944 | + $tokensToPolyfill = [ |
| 945 | + 'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG', |
| 946 | + 'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', |
| 947 | + 'T_ATTRIBUTE', |
| 948 | + 'T_BAD_CHARACTER', |
| 949 | + 'T_COALESCE_EQUAL', |
| 950 | + 'T_ENUM', |
| 951 | + 'T_FN', |
| 952 | + 'T_MATCH', |
| 953 | + 'T_NAME_FULLY_QUALIFIED', |
| 954 | + 'T_NAME_QUALIFIED', |
| 955 | + 'T_NAME_RELATIVE', |
| 956 | + 'T_NULLSAFE_OBJECT_OPERATOR', |
| 957 | + 'T_PRIVATE_SET', |
| 958 | + 'T_PROTECTED_SET', |
| 959 | + 'T_PUBLIC_SET', |
| 960 | + 'T_READONLY', |
| 961 | + 'T_VOID_CAST', |
| 962 | + ]; |
| 963 | + |
| 964 | + // <https://www.php.net/manual/en/tokens.php> |
| 965 | + // The PHP manual suggests "using big numbers like 10000" for |
| 966 | + // polyfilled T_* constants. We have arbitrarily chosen to start our |
| 967 | + // numbering scheme from 135_000. |
| 968 | + $nextTokenNumber = 135000; |
| 969 | + |
| 970 | + $polyfillMappingTable = []; |
| 971 | + |
| 972 | + foreach ($tokensToPolyfill as $tokenName) { |
| 973 | + if (defined($tokenName) === false) { |
| 974 | + while (isset($polyfillMappingTable[$nextTokenNumber]) === true) { |
| 975 | + $nextTokenNumber++; |
| 976 | + } |
| 977 | + |
| 978 | + define($tokenName, $nextTokenNumber); |
| 979 | + } |
| 980 | + |
| 981 | + $polyfillMappingTable[constant($tokenName)] = $tokenName; |
| 982 | + } |
| 983 | + |
| 984 | + // Be careful to not reference this class anywhere in this method until |
| 985 | + // *after* all constants have been polyfilled. |
| 986 | + self::$polyfillMappingTable = $polyfillMappingTable; |
| 987 | + } |
994 | 988 | } |
0 commit comments