2727
2828class CallFinder
2929{
30- private static $ ignore = array (
30+ private static $ ignore = [
3131 T_CLOSE_TAG => true ,
3232 T_COMMENT => true ,
3333 T_DOC_COMMENT => true ,
3434 T_INLINE_HTML => true ,
3535 T_OPEN_TAG => true ,
3636 T_OPEN_TAG_WITH_ECHO => true ,
3737 T_WHITESPACE => true ,
38- ) ;
38+ ] ;
3939
4040 /**
4141 * Things we need to do specially for operator tokens:
4242 * - Refuse to strip spaces around them
4343 * - Wrap the access path in parentheses if there
4444 * are any of these in the final short parameter.
4545 */
46- private static $ operator = array (
46+ private static $ operator = [
4747 T_AND_EQUAL => true ,
4848 T_BOOLEAN_AND => true ,
4949 T_BOOLEAN_OR => true ,
5050 T_ARRAY_CAST => true ,
5151 T_BOOL_CAST => true ,
52+ T_CLASS => true ,
5253 T_CLONE => true ,
5354 T_CONCAT_EQUAL => true ,
5455 T_DEC => true ,
5556 T_DIV_EQUAL => true ,
5657 T_DOUBLE_CAST => true ,
58+ T_FUNCTION => true ,
5759 T_INC => true ,
5860 T_INCLUDE => true ,
5961 T_INCLUDE_ONCE => true ,
@@ -84,6 +86,9 @@ class CallFinder
8486 T_STRING_CAST => true ,
8587 T_UNSET_CAST => true ,
8688 T_XOR_EQUAL => true ,
89+ T_POW => true ,
90+ T_POW_EQUAL => true ,
91+ T_DOUBLE_ARROW => true ,
8792 '! ' => true ,
8893 '% ' => true ,
8994 '& ' => true ,
@@ -100,9 +105,9 @@ class CallFinder
100105 '^ ' => true ,
101106 '| ' => true ,
102107 '~ ' => true ,
103- ) ;
108+ ] ;
104109
105- private static $ strip = array (
110+ private static $ strip = [
106111 '( ' => true ,
107112 ') ' => true ,
108113 '[ ' => true ,
@@ -112,39 +117,43 @@ class CallFinder
112117 T_OBJECT_OPERATOR => true ,
113118 T_DOUBLE_COLON => true ,
114119 T_NS_SEPARATOR => true ,
115- );
120+ ];
121+
122+ private static $ classcalls = [
123+ T_DOUBLE_COLON => true ,
124+ T_OBJECT_OPERATOR => true ,
125+ ];
126+
127+ private static $ namespace = [
128+ T_STRING => true ,
129+ ];
116130
117131 public static function getFunctionCalls ($ source , $ line , $ function )
118132 {
119- static $ up = array (
133+ static $ up = [
120134 '( ' => true ,
121135 '[ ' => true ,
122136 '{ ' => true ,
123137 T_CURLY_OPEN => true ,
124138 T_DOLLAR_OPEN_CURLY_BRACES => true ,
125- ) ;
126- static $ down = array (
139+ ] ;
140+ static $ down = [
127141 ') ' => true ,
128142 '] ' => true ,
129143 '} ' => true ,
130- ) ;
131- static $ modifiers = array (
144+ ] ;
145+ static $ modifiers = [
132146 '! ' => true ,
133147 '@ ' => true ,
134148 '~ ' => true ,
135149 '+ ' => true ,
136150 '- ' => true ,
137- ) ;
138- static $ identifier = array (
151+ ] ;
152+ static $ identifier = [
139153 T_DOUBLE_COLON => true ,
140154 T_STRING => true ,
141155 T_NS_SEPARATOR => true ,
142- );
143-
144- if (KINT_PHP56 ) {
145- self ::$ operator [T_POW ] = true ;
146- self ::$ operator [T_POW_EQUAL ] = true ;
147- }
156+ ];
148157
149158 if (KINT_PHP70 ) {
150159 self ::$ operator [T_SPACESHIP ] = true ;
@@ -154,11 +163,24 @@ public static function getFunctionCalls($source, $line, $function)
154163 self ::$ operator [T_COALESCE_EQUAL ] = true ;
155164 }
156165
166+ if (KINT_PHP80 ) {
167+ $ up [T_ATTRIBUTE ] = true ;
168+ self ::$ operator [T_MATCH ] = true ;
169+ self ::$ strip [T_NULLSAFE_OBJECT_OPERATOR ] = true ;
170+ self ::$ classcalls [T_NULLSAFE_OBJECT_OPERATOR ] = true ;
171+ self ::$ namespace [T_NAME_FULLY_QUALIFIED ] = true ;
172+ self ::$ namespace [T_NAME_QUALIFIED ] = true ;
173+ self ::$ namespace [T_NAME_RELATIVE ] = true ;
174+ $ identifier [T_NAME_FULLY_QUALIFIED ] = true ;
175+ $ identifier [T_NAME_QUALIFIED ] = true ;
176+ $ identifier [T_NAME_RELATIVE ] = true ;
177+ }
178+
157179 $ tokens = \token_get_all ($ source );
158180 $ cursor = 1 ;
159- $ function_calls = array () ;
160- /** @var array<int, null|array|string> Performance optimization preventing backwards loops */
161- $ prev_tokens = array ( null , null , null ) ;
181+ $ function_calls = [] ;
182+ // Performance optimization preventing backwards loops
183+ $ prev_tokens = [ null , null , null ] ;
162184
163185 if (\is_array ($ function )) {
164186 $ class = \explode ('\\' , $ function [0 ]);
@@ -188,10 +210,16 @@ public static function getFunctionCalls($source, $line, $function)
188210 continue ;
189211 }
190212
191- $ prev_tokens = array ( $ prev_tokens [1 ], $ prev_tokens [2 ], $ token) ;
213+ $ prev_tokens = [ $ prev_tokens [1 ], $ prev_tokens [2 ], $ token] ;
192214
193215 // Check if it's the right type to be the function we're looking for
194- if (T_STRING !== $ token [0 ] || \strtolower ($ token [1 ]) !== $ function ) {
216+ if (!isset (self ::$ namespace [$ token [0 ]])) {
217+ continue ;
218+ }
219+
220+ $ ns = \explode ('\\' , \strtolower ($ token [1 ]));
221+
222+ if (\end ($ ns ) !== $ function ) {
195223 continue ;
196224 }
197225
@@ -203,15 +231,23 @@ public static function getFunctionCalls($source, $line, $function)
203231
204232 // Check if it matches the signature
205233 if (null === $ class ) {
206- if ($ prev_tokens [1 ] && \in_array ( $ prev_tokens [1 ][0 ], array ( T_DOUBLE_COLON , T_OBJECT_OPERATOR ), true )) {
234+ if ($ prev_tokens [1 ] && isset ( self :: $ classcalls [ $ prev_tokens [1 ][0 ]] )) {
207235 continue ;
208236 }
209237 } else {
210238 if (!$ prev_tokens [1 ] || T_DOUBLE_COLON !== $ prev_tokens [1 ][0 ]) {
211239 continue ;
212240 }
213241
214- if (!$ prev_tokens [0 ] || T_STRING !== $ prev_tokens [0 ][0 ] || \strtolower ($ prev_tokens [0 ][1 ]) !== $ class ) {
242+ if (!$ prev_tokens [0 ] || !isset (self ::$ namespace [$ prev_tokens [0 ][0 ]])) {
243+ continue ;
244+ }
245+
246+ /** @var array{int, string, int} $prev_tokens[0] */
247+ // All self::$namespace tokens are T_ constants
248+ $ ns = \explode ('\\' , \strtolower ($ prev_tokens [0 ][1 ]));
249+
250+ if (\end ($ ns ) !== $ class ) {
215251 continue ;
216252 }
217253 }
@@ -222,8 +258,8 @@ public static function getFunctionCalls($source, $line, $function)
222258 $ instring = false ; // Whether we're in a string or not
223259 $ realtokens = false ; // Whether the current scope contains anything meaningful or not
224260 $ paramrealtokens = false ; // Whether the current parameter contains anything meaningful
225- $ params = array () ; // All our collected parameters
226- $ shortparam = array () ; // The short version of the parameter
261+ $ params = [] ; // All our collected parameters
262+ $ shortparam = [] ; // The short version of the parameter
227263 $ param_start = $ offset ; // The distance to the start of the parameter
228264
229265 // Loop through the following tokens until the function call ends
@@ -276,11 +312,11 @@ public static function getFunctionCalls($source, $line, $function)
276312 $ shortparam [] = '" ' ;
277313 } elseif (1 === $ depth ) {
278314 if (', ' === $ token [0 ]) {
279- $ params [] = array (
315+ $ params [] = [
280316 'full ' => \array_slice ($ tokens , $ param_start , $ offset - $ param_start ),
281317 'short ' => $ shortparam ,
282- ) ;
283- $ shortparam = array () ;
318+ ] ;
319+ $ shortparam = [] ;
284320 $ paramrealtokens = false ;
285321 $ param_start = $ offset + 1 ;
286322 } elseif (T_CONSTANT_ENCAPSED_STRING === $ token [0 ] && \strlen ($ token [1 ]) > 2 ) {
@@ -293,10 +329,10 @@ public static function getFunctionCalls($source, $line, $function)
293329 // Depth has dropped to 0 (So we've hit the closing paren)
294330 if ($ depth <= 0 ) {
295331 if ($ paramrealtokens ) {
296- $ params [] = array (
332+ $ params [] = [
297333 'full ' => \array_slice ($ tokens , $ param_start , $ offset - $ param_start ),
298334 'short ' => $ shortparam ,
299- ) ;
335+ ] ;
300336 }
301337
302338 break ;
@@ -322,11 +358,11 @@ public static function getFunctionCalls($source, $line, $function)
322358 }
323359 }
324360
325- $ param = array (
361+ $ param = [
326362 'name ' => self ::tokensToString ($ name ),
327363 'path ' => self ::tokensToString (self ::tokensTrim ($ param ['full ' ])),
328364 'expression ' => $ expression ,
329- ) ;
365+ ] ;
330366 }
331367
332368 // Get the modifiers
@@ -340,7 +376,7 @@ public static function getFunctionCalls($source, $line, $function)
340376 --$ index ;
341377 }
342378
343- $ mods = array () ;
379+ $ mods = [] ;
344380
345381 while (isset ($ tokens [$ index ])) {
346382 if (isset (self ::$ ignore [$ tokens [$ index ][0 ]])) {
@@ -357,10 +393,10 @@ public static function getFunctionCalls($source, $line, $function)
357393 break ;
358394 }
359395
360- $ function_calls [] = array (
396+ $ function_calls [] = [
361397 'parameters ' => $ params ,
362398 'modifiers ' => $ mods ,
363- ) ;
399+ ] ;
364400 }
365401
366402 return $ function_calls ;
@@ -436,10 +472,11 @@ private static function tokensTrim(array $tokens)
436472 private static function tokensFormatted (array $ tokens )
437473 {
438474 $ space = false ;
475+ $ attribute = false ;
439476
440477 $ tokens = self ::tokensTrim ($ tokens );
441478
442- $ output = array () ;
479+ $ output = [] ;
443480 $ last = null ;
444481
445482 foreach ($ tokens as $ index => $ token ) {
@@ -450,7 +487,10 @@ private static function tokensFormatted(array $tokens)
450487
451488 $ next = $ tokens [self ::realTokenIndex ($ tokens , $ index )];
452489
453- if (isset (self ::$ strip [$ last [0 ]]) && !self ::tokenIsOperator ($ next )) {
490+ /** @var array|string $last */
491+ if ($ attribute && '] ' === $ last [0 ]) {
492+ $ attribute = false ;
493+ } elseif (isset (self ::$ strip [$ last [0 ]]) && !self ::tokenIsOperator ($ next )) {
454494 continue ;
455495 }
456496
@@ -461,6 +501,10 @@ private static function tokensFormatted(array $tokens)
461501 $ token = ' ' ;
462502 $ space = true ;
463503 } else {
504+ if (KINT_PHP80 && $ last && T_ATTRIBUTE == $ last [0 ]) {
505+ $ attribute = true ;
506+ }
507+
464508 $ space = false ;
465509 $ last = $ token ;
466510 }
0 commit comments