@@ -893,6 +893,62 @@ protected function tokenize($string)
893
893
continue ;
894
894
}//end if
895
895
896
+ /*
897
+ Tokenize the parameter labels for PHP 8.0 named parameters as a special T_PARAM_NAME
898
+ token and ensure that the colon after it is always T_COLON.
899
+ */
900
+
901
+ if ($ tokenIsArray === true
902
+ && preg_match ('`^[a-zA-Z_\x80-\xff]` ' , $ token [1 ]) === 1
903
+ ) {
904
+ // Get the next non-empty token.
905
+ for ($ i = ($ stackPtr + 1 ); $ i < $ numTokens ; $ i ++) {
906
+ if (is_array ($ tokens [$ i ]) === false
907
+ || isset (Util \Tokens::$ emptyTokens [$ tokens [$ i ][0 ]]) === false
908
+ ) {
909
+ break ;
910
+ }
911
+ }
912
+
913
+ if (isset ($ tokens [$ i ]) === true
914
+ && is_array ($ tokens [$ i ]) === false
915
+ && $ tokens [$ i ] === ': '
916
+ ) {
917
+ // Get the previous non-empty token.
918
+ for ($ j = ($ stackPtr - 1 ); $ j > 0 ; $ j --) {
919
+ if (is_array ($ tokens [$ j ]) === false
920
+ || isset (Util \Tokens::$ emptyTokens [$ tokens [$ j ][0 ]]) === false
921
+ ) {
922
+ break ;
923
+ }
924
+ }
925
+
926
+ if (is_array ($ tokens [$ j ]) === false
927
+ && ($ tokens [$ j ] === '( '
928
+ || $ tokens [$ j ] === ', ' )
929
+ ) {
930
+ $ newToken = [];
931
+ $ newToken ['code ' ] = T_PARAM_NAME ;
932
+ $ newToken ['type ' ] = 'T_PARAM_NAME ' ;
933
+ $ newToken ['content ' ] = $ token [1 ];
934
+ $ finalTokens [$ newStackPtr ] = $ newToken ;
935
+
936
+ $ newStackPtr ++;
937
+
938
+ // Modify the original token stack so that future checks, like
939
+ // determining T_COLON vs T_INLINE_ELSE can handle this correctly.
940
+ $ tokens [$ stackPtr ][0 ] = T_PARAM_NAME ;
941
+
942
+ if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
943
+ $ type = Util \Tokens::tokenName ($ token [0 ]);
944
+ echo "\t\t* token $ stackPtr changed from $ type to T_PARAM_NAME " .PHP_EOL ;
945
+ }
946
+
947
+ continue ;
948
+ }
949
+ }//end if
950
+ }//end if
951
+
896
952
/*
897
953
Before PHP 7.0, the "yield from" was tokenized as
898
954
T_YIELD, T_WHITESPACE and T_STRING. So look for
@@ -1701,76 +1757,98 @@ function return types. We want to keep the parenthesis map clean,
1701
1757
// Convert colons that are actually the ELSE component of an
1702
1758
// inline IF statement.
1703
1759
if (empty ($ insideInlineIf ) === false && $ newToken ['code ' ] === T_COLON ) {
1704
- // Make sure this isn't a return type separator.
1705
1760
$ isInlineIf = true ;
1761
+
1762
+ // Make sure this isn't a named parameter label.
1763
+ // Get the previous non-empty token.
1706
1764
for ($ i = ($ stackPtr - 1 ); $ i > 0 ; $ i --) {
1707
1765
if (is_array ($ tokens [$ i ]) === false
1708
- || ($ tokens [$ i ][0 ] !== T_DOC_COMMENT
1709
- && $ tokens [$ i ][0 ] !== T_COMMENT
1710
- && $ tokens [$ i ][0 ] !== T_WHITESPACE )
1766
+ || isset (Util \Tokens::$ emptyTokens [$ tokens [$ i ][0 ]]) === false
1711
1767
) {
1712
1768
break ;
1713
1769
}
1714
1770
}
1715
1771
1716
- if ($ tokens [$ i ] === ') ' ) {
1717
- $ parenCount = 1 ;
1718
- for ($ i --; $ i > 0 ; $ i --) {
1719
- if ($ tokens [$ i ] === '( ' ) {
1720
- $ parenCount --;
1721
- if ($ parenCount === 0 ) {
1722
- break ;
1723
- }
1724
- } else if ($ tokens [$ i ] === ') ' ) {
1725
- $ parenCount ++;
1726
- }
1772
+ if ($ tokens [$ i ][0 ] === T_PARAM_NAME ) {
1773
+ $ isInlineIf = false ;
1774
+ if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
1775
+ echo "\t\t* token is parameter label, not T_INLINE_ELSE " .PHP_EOL ;
1727
1776
}
1777
+ }
1728
1778
1729
- // We've found the open parenthesis, so if the previous
1730
- // non-empty token is FUNCTION or USE, this is a return type.
1731
- // Note that we need to skip T_STRING tokens here as these
1732
- // can be function names.
1733
- for ($ i --; $ i > 0 ; $ i --) {
1779
+ if ($ isInlineIf === true ) {
1780
+ // Make sure this isn't a return type separator.
1781
+ for ($ i = ($ stackPtr - 1 ); $ i > 0 ; $ i --) {
1734
1782
if (is_array ($ tokens [$ i ]) === false
1735
1783
|| ($ tokens [$ i ][0 ] !== T_DOC_COMMENT
1736
1784
&& $ tokens [$ i ][0 ] !== T_COMMENT
1737
- && $ tokens [$ i ][0 ] !== T_WHITESPACE
1738
- && $ tokens [$ i ][0 ] !== T_STRING )
1785
+ && $ tokens [$ i ][0 ] !== T_WHITESPACE )
1739
1786
) {
1740
1787
break ;
1741
1788
}
1742
1789
}
1743
1790
1744
- if ($ tokens [$ i ][0 ] === T_FUNCTION || $ tokens [$ i ][0 ] === T_FN || $ tokens [$ i ][0 ] === T_USE ) {
1745
- $ isInlineIf = false ;
1746
- if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
1747
- echo "\t\t* token is return type, not T_INLINE_ELSE " .PHP_EOL ;
1791
+ if ($ tokens [$ i ] === ') ' ) {
1792
+ $ parenCount = 1 ;
1793
+ for ($ i --; $ i > 0 ; $ i --) {
1794
+ if ($ tokens [$ i ] === '( ' ) {
1795
+ $ parenCount --;
1796
+ if ($ parenCount === 0 ) {
1797
+ break ;
1798
+ }
1799
+ } else if ($ tokens [$ i ] === ') ' ) {
1800
+ $ parenCount ++;
1801
+ }
1748
1802
}
1749
- }
1803
+
1804
+ // We've found the open parenthesis, so if the previous
1805
+ // non-empty token is FUNCTION or USE, this is a return type.
1806
+ // Note that we need to skip T_STRING tokens here as these
1807
+ // can be function names.
1808
+ for ($ i --; $ i > 0 ; $ i --) {
1809
+ if (is_array ($ tokens [$ i ]) === false
1810
+ || ($ tokens [$ i ][0 ] !== T_DOC_COMMENT
1811
+ && $ tokens [$ i ][0 ] !== T_COMMENT
1812
+ && $ tokens [$ i ][0 ] !== T_WHITESPACE
1813
+ && $ tokens [$ i ][0 ] !== T_STRING )
1814
+ ) {
1815
+ break ;
1816
+ }
1817
+ }
1818
+
1819
+ if ($ tokens [$ i ][0 ] === T_FUNCTION || $ tokens [$ i ][0 ] === T_FN || $ tokens [$ i ][0 ] === T_USE ) {
1820
+ $ isInlineIf = false ;
1821
+ if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
1822
+ echo "\t\t* token is return type, not T_INLINE_ELSE " .PHP_EOL ;
1823
+ }
1824
+ }
1825
+ }//end if
1750
1826
}//end if
1751
1827
1752
1828
// Check to see if this is a CASE or DEFAULT opener.
1753
- $ inlineIfToken = $ insideInlineIf [(count ($ insideInlineIf ) - 1 )];
1754
- for ($ i = $ stackPtr ; $ i > $ inlineIfToken ; $ i --) {
1755
- if (is_array ($ tokens [$ i ]) === true
1756
- && ($ tokens [$ i ][0 ] === T_CASE
1757
- || $ tokens [$ i ][0 ] === T_DEFAULT )
1758
- ) {
1759
- $ isInlineIf = false ;
1760
- if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
1761
- echo "\t\t* token is T_CASE or T_DEFAULT opener, not T_INLINE_ELSE " .PHP_EOL ;
1762
- }
1829
+ if ($ isInlineIf === true ) {
1830
+ $ inlineIfToken = $ insideInlineIf [(count ($ insideInlineIf ) - 1 )];
1831
+ for ($ i = $ stackPtr ; $ i > $ inlineIfToken ; $ i --) {
1832
+ if (is_array ($ tokens [$ i ]) === true
1833
+ && ($ tokens [$ i ][0 ] === T_CASE
1834
+ || $ tokens [$ i ][0 ] === T_DEFAULT )
1835
+ ) {
1836
+ $ isInlineIf = false ;
1837
+ if (PHP_CODESNIFFER_VERBOSITY > 1 ) {
1838
+ echo "\t\t* token is T_CASE or T_DEFAULT opener, not T_INLINE_ELSE " .PHP_EOL ;
1839
+ }
1763
1840
1764
- break ;
1765
- }
1841
+ break ;
1842
+ }
1766
1843
1767
- if (is_array ($ tokens [$ i ]) === false
1768
- && ($ tokens [$ i ] === '; '
1769
- || $ tokens [$ i ] === '{ ' )
1770
- ) {
1771
- break ;
1844
+ if (is_array ($ tokens [$ i ]) === false
1845
+ && ($ tokens [$ i ] === '; '
1846
+ || $ tokens [$ i ] === '{ ' )
1847
+ ) {
1848
+ break ;
1849
+ }
1772
1850
}
1773
- }
1851
+ }//end if
1774
1852
1775
1853
if ($ isInlineIf === true ) {
1776
1854
array_pop ($ insideInlineIf );
0 commit comments