@@ -602,7 +602,10 @@ public function start($contents=null)
602602 // If short open tags are off but the file being checked uses
603603 // short open tags, the whole content will be inline HTML
604604 // and nothing will be checked. So try and handle this case.
605- if ($ foundCode === false && $ this ->tokenizerType === 'PHP ' ) {
605+ // We don't show this error for STDIN because we can't be sure the content
606+ // actually came directly from the user. It could be something like
607+ // refs from a Git pre-push hook.
608+ if ($ foundCode === false && $ this ->tokenizerType === 'PHP ' && $ this ->_file !== 'STDIN ' ) {
606609 $ shortTags = (bool ) ini_get ('short_open_tag ' );
607610 if ($ shortTags === false ) {
608611 $ error = 'No PHP code was found in this file and short open tags are not allowed by this install of PHP. This file may be using short open tags but PHP does not allow them. ' ;
@@ -1942,7 +1945,9 @@ private static function _recurseScopeMap(
19421945 // scope tokens. E.g., if (1) 1; 1 ? (1 ? 1 : 1) : 1;
19431946 // If an IF statement below this one has an opener but no
19441947 // keyword, the opener will be incorrectly assigned to this IF statement.
1945- if (($ currType === T_IF || $ currType === T_ELSE )
1948+ // The same case also applies to USE statements, which don't have to have
1949+ // openers, so a following USE statement can cause an incorrect brace match.
1950+ if (($ currType === T_IF || $ currType === T_ELSE || $ currType === T_USE )
19461951 && $ opener === null
19471952 && $ tokens [$ i ]['code ' ] === T_SEMICOLON
19481953 ) {
@@ -2645,25 +2650,23 @@ private static function _createLevelMap(&$tokens, $tokenizer, $eolChar)
26452650
26462651
26472652 /**
2648- * Returns the declaration names for T_CLASS, T_INTERFACE and T_FUNCTION tokens .
2653+ * Returns the declaration names for classes, interfaces, and functions .
26492654 *
26502655 * @param int $stackPtr The position of the declaration token which
26512656 * declared the class, interface or function.
26522657 *
26532658 * @return string|null The name of the class, interface or function.
2654- * or NULL if the function is a closure .
2659+ * or NULL if the function or class is anonymous .
26552660 * @throws PHP_CodeSniffer_Exception If the specified token is not of type
2656- * T_FUNCTION, T_CLASS or T_INTERFACE.
2661+ * T_FUNCTION, T_CLASS, T_ANON_CLASS,
2662+ * or T_INTERFACE.
26572663 */
26582664 public function getDeclarationName ($ stackPtr )
26592665 {
26602666 $ tokenCode = $ this ->_tokens [$ stackPtr ]['code ' ];
2661- if ($ tokenCode !== T_FUNCTION
2662- && $ tokenCode !== T_CLASS
2663- && $ tokenCode !== T_INTERFACE
2664- && $ tokenCode !== T_TRAIT
2665- ) {
2666- throw new PHP_CodeSniffer_Exception ('Token type " ' .$ this ->_tokens [$ stackPtr ]['type ' ].'" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT ' );
2667+
2668+ if ($ tokenCode === T_ANON_CLASS ) {
2669+ return null ;
26672670 }
26682671
26692672 if ($ tokenCode === T_FUNCTION
@@ -2672,6 +2675,14 @@ public function getDeclarationName($stackPtr)
26722675 return null ;
26732676 }
26742677
2678+ if ($ tokenCode !== T_FUNCTION
2679+ && $ tokenCode !== T_CLASS
2680+ && $ tokenCode !== T_INTERFACE
2681+ && $ tokenCode !== T_TRAIT
2682+ ) {
2683+ throw new PHP_CodeSniffer_Exception ('Token type " ' .$ this ->_tokens [$ stackPtr ]['type ' ].'" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT ' );
2684+ }
2685+
26752686 $ content = null ;
26762687 for ($ i = $ stackPtr ; $ i < $ this ->numTokens ; $ i ++) {
26772688 if ($ this ->_tokens [$ i ]['code ' ] === T_STRING ) {
@@ -2731,46 +2742,53 @@ public function isAnonymousFunction($stackPtr)
27312742
27322743
27332744 /**
2734- * Returns the method parameters for the specified T_FUNCTION token.
2745+ * Returns the method parameters for the specified function token.
27352746 *
27362747 * Each parameter is in the following format:
27372748 *
27382749 * <code>
27392750 * 0 => array(
2751+ * 'token' => int, // The position of the var in the token stack.
27402752 * 'name' => '$var', // The variable name.
2741- * 'pass_by_reference' => false, // Passed by reference.
2742- * 'type_hint' => string, // Type hint for array or custom type
2753+ * 'content' => string, // The full content of the variable definition.
2754+ * 'pass_by_reference' => boolean, // Is the variable passed by reference?
2755+ * 'type_hint' => string, // The type hint for the variable.
2756+ * 'nullable_type' => boolean, // Is the variable using a nullable type?
27432757 * )
27442758 * </code>
27452759 *
27462760 * Parameters with default values have an additional array index of
27472761 * 'default' with the value of the default as a string.
27482762 *
2749- * @param int $stackPtr The position in the stack of the T_FUNCTION token
2763+ * @param int $stackPtr The position in the stack of the function token
27502764 * to acquire the parameters for.
27512765 *
27522766 * @return array
27532767 * @throws PHP_CodeSniffer_Exception If the specified $stackPtr is not of
2754- * type T_FUNCTION.
2768+ * type T_FUNCTION or T_CLOSURE .
27552769 */
27562770 public function getMethodParameters ($ stackPtr )
27572771 {
2758- if ($ this ->_tokens [$ stackPtr ]['code ' ] !== T_FUNCTION ) {
2759- throw new PHP_CodeSniffer_Exception ('$stackPtr must be of type T_FUNCTION ' );
2772+ if ($ this ->_tokens [$ stackPtr ]['code ' ] !== T_FUNCTION
2773+ && $ this ->_tokens [$ stackPtr ]['code ' ] !== T_CLOSURE
2774+ ) {
2775+ throw new PHP_CodeSniffer_Exception ('$stackPtr must be of type T_FUNCTION or T_CLOSURE ' );
27602776 }
27612777
27622778 $ opener = $ this ->_tokens [$ stackPtr ]['parenthesis_opener ' ];
27632779 $ closer = $ this ->_tokens [$ stackPtr ]['parenthesis_closer ' ];
27642780
27652781 $ vars = array ();
27662782 $ currVar = null ;
2783+ $ paramStart = ($ opener + 1 );
27672784 $ defaultStart = null ;
27682785 $ paramCount = 0 ;
27692786 $ passByReference = false ;
27702787 $ variableLength = false ;
27712788 $ typeHint = '' ;
2789+ $ nullableType = false ;
27722790
2773- for ($ i = ( $ opener + 1 ) ; $ i <= $ closer ; $ i ++) {
2791+ for ($ i = $ paramStart ; $ i <= $ closer ; $ i ++) {
27742792 // Check to see if this token has a parenthesis or bracket opener. If it does
27752793 // it's likely to be an array which might have arguments in it. This
27762794 // could cause problems in our parsing below, so lets just skip to the
@@ -2801,7 +2819,15 @@ public function getMethodParameters($stackPtr)
28012819 break ;
28022820 case T_ARRAY_HINT :
28032821 case T_CALLABLE :
2804- $ typeHint = $ this ->_tokens [$ i ]['content ' ];
2822+ $ typeHint .= $ this ->_tokens [$ i ]['content ' ];
2823+ break ;
2824+ case T_SELF :
2825+ case T_PARENT :
2826+ case T_STATIC :
2827+ // Self is valid, the others invalid, but were probably intended as type hints.
2828+ if (isset ($ defaultStart ) === false ) {
2829+ $ typeHint .= $ this ->_tokens [$ i ]['content ' ];
2830+ }
28052831 break ;
28062832 case T_STRING :
28072833 // This is a string, so it may be a type hint, but it could
@@ -2838,6 +2864,12 @@ public function getMethodParameters($stackPtr)
28382864 $ typeHint .= $ this ->_tokens [$ i ]['content ' ];
28392865 }
28402866 break ;
2867+ case T_NULLABLE :
2868+ if ($ defaultStart === null ) {
2869+ $ nullableType = true ;
2870+ $ typeHint .= $ this ->_tokens [$ i ]['content ' ];
2871+ }
2872+ break ;
28412873 case T_CLOSE_PARENTHESIS :
28422874 case T_COMMA :
28432875 // If it's null, then there must be no parameters for this
@@ -2846,26 +2878,27 @@ public function getMethodParameters($stackPtr)
28462878 continue ;
28472879 }
28482880
2849- $ vars [$ paramCount ] = array ();
2850- $ vars [$ paramCount ]['name ' ] = $ this ->_tokens [$ currVar ]['content ' ];
2881+ $ vars [$ paramCount ] = array ();
2882+ $ vars [$ paramCount ]['token ' ] = $ currVar ;
2883+ $ vars [$ paramCount ]['name ' ] = $ this ->_tokens [$ currVar ]['content ' ];
2884+ $ vars [$ paramCount ]['content ' ] = trim ($ this ->getTokensAsString ($ paramStart , ($ i - $ paramStart )));
28512885
28522886 if ($ defaultStart !== null ) {
2853- $ vars [$ paramCount ]['default ' ]
2854- = $ this ->getTokensAsString (
2855- $ defaultStart ,
2856- ($ i - $ defaultStart )
2857- );
2887+ $ vars [$ paramCount ]['default ' ] = trim ($ this ->getTokensAsString ($ defaultStart , ($ i - $ defaultStart )));
28582888 }
28592889
28602890 $ vars [$ paramCount ]['pass_by_reference ' ] = $ passByReference ;
28612891 $ vars [$ paramCount ]['variable_length ' ] = $ variableLength ;
28622892 $ vars [$ paramCount ]['type_hint ' ] = $ typeHint ;
2893+ $ vars [$ paramCount ]['nullable_type ' ] = $ nullableType ;
28632894
28642895 // Reset the vars, as we are about to process the next parameter.
28652896 $ defaultStart = null ;
2897+ $ paramStart = ($ i + 1 );
28662898 $ passByReference = false ;
28672899 $ variableLength = false ;
28682900 $ typeHint = '' ;
2901+ $ nullableType = false ;
28692902
28702903 $ paramCount ++;
28712904 break ;
@@ -3000,6 +3033,7 @@ public function getMemberProperties($stackPtr)
30003033 $ ptr = array_pop ($ conditions );
30013034 if (isset ($ this ->_tokens [$ ptr ]) === false
30023035 || ($ this ->_tokens [$ ptr ]['code ' ] !== T_CLASS
3036+ && $ this ->_tokens [$ ptr ]['code ' ] !== T_ANON_CLASS
30033037 && $ this ->_tokens [$ ptr ]['code ' ] !== T_TRAIT )
30043038 ) {
30053039 if (isset ($ this ->_tokens [$ ptr ]) === true
@@ -3683,7 +3717,9 @@ public function findExtendedClassName($stackPtr)
36833717 return false ;
36843718 }
36853719
3686- if ($ this ->_tokens [$ stackPtr ]['code ' ] !== T_CLASS ) {
3720+ if ($ this ->_tokens [$ stackPtr ]['code ' ] !== T_CLASS
3721+ && $ this ->_tokens [$ stackPtr ]['code ' ] !== T_ANON_CLASS
3722+ ) {
36873723 return false ;
36883724 }
36893725
@@ -3732,7 +3768,9 @@ public function findImplementedInterfaceNames($stackPtr)
37323768 return false ;
37333769 }
37343770
3735- if ($ this ->_tokens [$ stackPtr ]['code ' ] !== T_CLASS ) {
3771+ if ($ this ->_tokens [$ stackPtr ]['code ' ] !== T_CLASS
3772+ && $ this ->_tokens [$ stackPtr ]['code ' ] !== T_ANON_CLASS
3773+ ) {
37363774 return false ;
37373775 }
37383776
0 commit comments