@@ -812,6 +812,81 @@ protected function tokenize($string)
812
812
continue ;
813
813
}//end if
814
814
815
+ /*
816
+ As of PHP 8.0 fully qualified, partially qualified and namespace relative
817
+ identifier names are tokenized differently.
818
+ This "undoes" the new tokenization so the tokenization will be the same in
819
+ in PHP 5, 7 and 8.
820
+ */
821
+
822
+ if (PHP_VERSION_ID >= 80000
823
+ && $ tokenIsArray === true
824
+ && ($ token [0 ] === T_NAME_QUALIFIED
825
+ || $ token [0 ] === T_NAME_FULLY_QUALIFIED
826
+ || $ token [0 ] === T_NAME_RELATIVE )
827
+ ) {
828
+ $ name = $ token [1 ];
829
+
830
+ if ($ token [0 ] === T_NAME_FULLY_QUALIFIED ) {
831
+ $ newToken = [];
832
+ $ newToken ['code ' ] = T_NS_SEPARATOR ;
833
+ $ newToken ['type ' ] = 'T_NS_SEPARATOR ' ;
834
+ $ newToken ['content ' ] = '\\' ;
835
+ $ finalTokens [$ newStackPtr ] = $ newToken ;
836
+ ++$ newStackPtr ;
837
+
838
+ $ name = ltrim ($ name , '\\' );
839
+ }
840
+
841
+ if ($ token [0 ] === T_NAME_RELATIVE ) {
842
+ $ newToken = [];
843
+ $ newToken ['code ' ] = T_NAMESPACE ;
844
+ $ newToken ['type ' ] = 'T_NAMESPACE ' ;
845
+ $ newToken ['content ' ] = substr ($ name , 0 , 9 );
846
+ $ finalTokens [$ newStackPtr ] = $ newToken ;
847
+ ++$ newStackPtr ;
848
+
849
+ $ newToken = [];
850
+ $ newToken ['code ' ] = T_NS_SEPARATOR ;
851
+ $ newToken ['type ' ] = 'T_NS_SEPARATOR ' ;
852
+ $ newToken ['content ' ] = '\\' ;
853
+ $ finalTokens [$ newStackPtr ] = $ newToken ;
854
+ ++$ newStackPtr ;
855
+
856
+ $ name = substr ($ name , 10 );
857
+ }
858
+
859
+ $ parts = explode ('\\' , $ name );
860
+ $ partCount = count ($ parts );
861
+ $ lastPart = ($ partCount - 1 );
862
+
863
+ foreach ($ parts as $ i => $ part ) {
864
+ $ newToken = [];
865
+ $ newToken ['code ' ] = T_STRING ;
866
+ $ newToken ['type ' ] = 'T_STRING ' ;
867
+ $ newToken ['content ' ] = $ part ;
868
+ $ finalTokens [$ newStackPtr ] = $ newToken ;
869
+ ++$ newStackPtr ;
870
+
871
+ if ($ i !== $ lastPart ) {
872
+ $ newToken = [];
873
+ $ newToken ['code ' ] = T_NS_SEPARATOR ;
874
+ $ newToken ['type ' ] = 'T_NS_SEPARATOR ' ;
875
+ $ newToken ['content ' ] = '\\' ;
876
+ $ finalTokens [$ newStackPtr ] = $ newToken ;
877
+ ++$ newStackPtr ;
878
+ }
879
+ }
880
+
881
+ if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
882
+ $ type = Util \Tokens::tokenName ($ token [0 ]);
883
+ $ content = Util \Common::prepareForOutput ($ token [1 ]);
884
+ echo "\t\t* token $ stackPtr split into individual tokens; was: $ type => $ content " .PHP_EOL ;
885
+ }
886
+
887
+ continue ;
888
+ }//end if
889
+
815
890
/*
816
891
Before PHP 7.0, the "yield from" was tokenized as
817
892
T_YIELD, T_WHITESPACE and T_STRING. So look for
@@ -1105,7 +1180,7 @@ protected function tokenize($string)
1105
1180
* Check if the next non-empty token is one of the tokens which can be used
1106
1181
* in type declarations. If not, it's definitely a ternary.
1107
1182
* At this point, the only token types which need to be taken into consideration
1108
- * as potential type declarations are T_STRING , T_ARRAY, T_CALLABLE and T_NS_SEPARATOR.
1183
+ * as potential type declarations are identifier names , T_ARRAY, T_CALLABLE and T_NS_SEPARATOR.
1109
1184
*/
1110
1185
1111
1186
$ lastRelevantNonEmpty = null ;
@@ -1122,6 +1197,9 @@ protected function tokenize($string)
1122
1197
}
1123
1198
1124
1199
if ($ tokenType === T_STRING
1200
+ || $ tokenType === T_NAME_FULLY_QUALIFIED
1201
+ || $ tokenType === T_NAME_RELATIVE
1202
+ || $ tokenType === T_NAME_QUALIFIED
1125
1203
|| $ tokenType === T_ARRAY
1126
1204
|| $ tokenType === T_NS_SEPARATOR
1127
1205
) {
@@ -1133,7 +1211,10 @@ protected function tokenize($string)
1133
1211
&& isset ($ lastRelevantNonEmpty ) === false )
1134
1212
|| ($ lastRelevantNonEmpty === T_ARRAY
1135
1213
&& $ tokenType === '( ' )
1136
- || ($ lastRelevantNonEmpty === T_STRING
1214
+ || (($ lastRelevantNonEmpty === T_STRING
1215
+ || $ lastRelevantNonEmpty === T_NAME_FULLY_QUALIFIED
1216
+ || $ lastRelevantNonEmpty === T_NAME_RELATIVE
1217
+ || $ lastRelevantNonEmpty === T_NAME_QUALIFIED )
1137
1218
&& ($ tokenType === T_DOUBLE_COLON
1138
1219
|| $ tokenType === '( '
1139
1220
|| $ tokenType === ': ' ))
@@ -1278,6 +1359,10 @@ protected function tokenize($string)
1278
1359
tokenized as T_STRING even if it appears to be a different token,
1279
1360
such as when writing code like: function default(): foo
1280
1361
so go forward and change the token type before it is processed.
1362
+
1363
+ Note: this should not be done for `function Level\Name` within a
1364
+ group use statement for the PHP 8 identifier name tokens as it
1365
+ would interfere with the re-tokenization of those.
1281
1366
*/
1282
1367
1283
1368
if ($ tokenIsArray === true
@@ -1295,7 +1380,10 @@ protected function tokenize($string)
1295
1380
}
1296
1381
}
1297
1382
1298
- if ($ x < $ numTokens && is_array ($ tokens [$ x ]) === true ) {
1383
+ if ($ x < $ numTokens
1384
+ && is_array ($ tokens [$ x ]) === true
1385
+ && $ tokens [$ x ][0 ] !== T_NAME_QUALIFIED
1386
+ ) {
1299
1387
if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
1300
1388
$ oldType = Util \Tokens::tokenName ($ tokens [$ x ][0 ]);
1301
1389
echo "\t\t* token $ x changed from $ oldType to T_STRING " .PHP_EOL ;
@@ -1351,12 +1439,15 @@ function return types. We want to keep the parenthesis map clean,
1351
1439
&& $ tokens [$ x ] === ': '
1352
1440
) {
1353
1441
$ allowed = [
1354
- T_STRING => T_STRING ,
1355
- T_ARRAY => T_ARRAY ,
1356
- T_CALLABLE => T_CALLABLE ,
1357
- T_SELF => T_SELF ,
1358
- T_PARENT => T_PARENT ,
1359
- T_NS_SEPARATOR => T_NS_SEPARATOR ,
1442
+ T_STRING => T_STRING ,
1443
+ T_NAME_FULLY_QUALIFIED => T_NAME_FULLY_QUALIFIED ,
1444
+ T_NAME_RELATIVE => T_NAME_RELATIVE ,
1445
+ T_NAME_QUALIFIED => T_NAME_QUALIFIED ,
1446
+ T_ARRAY => T_ARRAY ,
1447
+ T_CALLABLE => T_CALLABLE ,
1448
+ T_SELF => T_SELF ,
1449
+ T_PARENT => T_PARENT ,
1450
+ T_NS_SEPARATOR => T_NS_SEPARATOR ,
1360
1451
];
1361
1452
1362
1453
$ allowed += Util \Tokens::$ emptyTokens ;
0 commit comments