Determine if the passed token has a condition of one of the passed types.
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $varName = ltrim($tokens[$stackPtr]['content'], '$'); $phpReservedVars = array('_SERVER', '_GET', '_POST', '_REQUEST', '_SESSION', '_ENV', '_COOKIE', '_FILES', 'GLOBALS', 'http_response_header', 'HTTP_RAW_POST_DATA', 'php_errormsg'); // If it's a php reserved var, then its ok. if (in_array($varName, $phpReservedVars) === true) { return; } // There is no way for us to know if the var is public or private, // so we have to ignore a leading underscore if there is one and just // check the main part of the variable name. $originalVarName = $varName; if (substr($varName, 0, 1) === '_') { $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), $stackPtr - 1, null, true); if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { // The variable lives within a class, and is referenced like // this: MyClass::$_variable, so we don't know its scope. $inClass = true; } else { $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE, T_TRAIT)); } if ($inClass === true) { $varName = substr($varName, 1); } } if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { $error = 'Variable "%s" is not in valid camel caps format'; $data = array($originalVarName); $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param integer $stackPtr The position of the current token * in the stack passed in $tokens. * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['scope_closer']) === false) { // Probably an interface method. return; } $closeBrace = $tokens[$stackPtr]['scope_closer']; $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, $closeBrace - 1, null, true); $braceLine = $tokens[$closeBrace]['line']; $prevLine = $tokens[$prevContent]['line']; $found = $braceLine - $prevLine - 1; if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true) { // Nested function. if ($found < 0) { $error = 'Closing brace of nested function must be on a new line'; $phpcsFile->addError($error, $closeBrace, 'ContentBeforeClose'); } elseif ($found > 0) { $error = 'Expected 0 blank lines before closing brace of nested function; %s found'; $data = array($found); $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeNestedClose', $data); } } else { if ($found !== 0) { $error = 'Expected 0 blank lines before closing function brace; %s found'; $data = array($found); $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeClose', $data); } } }
/** * Processes the tokens that this sniff is interested in. * * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. * @param int $stackPtr The position in the stack where * the token was found. * * @return void * @see PHP_CodeSniffer_Sniff::process() */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $token = $tokens[$stackPtr]['content']; // Only accept class member functions if (false === $phpcsFile->hasCondition($stackPtr, T_CLASS)) { return; } $nextTokenIndex = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 1, null, true); $methodName = $tokens[$nextTokenIndex]['content']; $methodProperties = $phpcsFile->getMethodProperties($stackPtr); switch ($methodName) { case '__call': $this->_checkCall($phpcsFile, $stackPtr, $methodName, $methodProperties); break; case '__get': $this->_checkGet($phpcsFile, $stackPtr, $methodName, $methodProperties); break; case '__isset': $this->_checkIsset($phpcsFile, $stackPtr, $methodName, $methodProperties); break; case '__set': $this->_checkSet($phpcsFile, $stackPtr, $methodName, $methodProperties); break; case '__toString': $this->_checkToString($phpcsFile, $stackPtr, $methodName, $methodProperties); break; case '__unset': $this->_checkUnset($phpcsFile, $stackPtr, $methodName, $methodProperties); break; default: break; } }
/** * Processes the function tokens within the class. * * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. * @param int $stackPtr The position where the token was found. * @param int $currScope The current scope opener token. * * @return void */ protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) { $tokens = $phpcsFile->getTokens(); $methodName = $phpcsFile->getDeclarationName($stackPtr); if ($methodName === null) { // Ignore closures. return; } if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { // Ignore nested functions. return; } $modifier = null; for ($i = $stackPtr - 1; $i > 0; $i--) { if ($tokens[$i]['line'] < $tokens[$stackPtr]['line']) { break; } else { if (isset(PHP_CodeSniffer_Tokens::$scopeModifiers[$tokens[$i]['code']]) === true) { $modifier = $i; break; } } } if ($modifier === null) { $error = 'Visibility must be declared on method "%s"'; $data = array($methodName); $phpcsFile->addError($error, $stackPtr, 'Missing', $data); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { $error = 'The use of inner functions is forbidden'; $phpcsFile->addError($error, $stackPtr); } }
/** * Check if this use statement is part of the namespace block. * * @param PHP_CodeSniffer_File $phpcsFile * @param int $stackPtr * @return bool */ private function _shouldIgnoreUse(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // keyword inside closure $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, NULL, TRUE); if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { return TRUE; } // use trait in class if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === TRUE) { return TRUE; } // use trait in trait if ($phpcsFile->hasCondition($stackPtr, T_TRAIT) === TRUE) { return TRUE; } return FALSE; }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens.. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['code'] === T_FUNCTION) { $methodProps = $phpcsFile->getMethodProperties($stackPtr); // Abstract methods do not require a closing comment. if ($methodProps['is_abstract'] === true) { return; } // Closures do not require a closing comment. if ($methodProps['is_closure'] === true) { return; } // If this function is in an interface then we don't require // a closing comment. if ($phpcsFile->hasCondition($stackPtr, T_INTERFACE) === true) { return; } if (isset($tokens[$stackPtr]['scope_closer']) === false) { $error = 'Possible parse error: non-abstract method defined as abstract'; $phpcsFile->addWarning($error, $stackPtr); return; } $decName = $phpcsFile->getDeclarationName($stackPtr); $comment = '//end ' . $decName . '()'; } else { if ($tokens[$stackPtr]['code'] === T_CLASS) { $comment = '//end class'; } else { $comment = '//end interface'; } } //end if if (isset($tokens[$stackPtr]['scope_closer']) === false) { $error = 'Possible parse error: '; $error .= $tokens[$stackPtr]['content']; $error .= ' missing opening or closing brace'; $phpcsFile->addWarning($error, $stackPtr); return; } $closingBracket = $tokens[$stackPtr]['scope_closer']; if ($closingBracket === null) { // Possible inline structure. Other tests will handle it. return; } $error = 'Expected ' . $comment; if (isset($tokens[$closingBracket + 1]) === false || $tokens[$closingBracket + 1]['code'] !== T_COMMENT) { $phpcsFile->addError($error, $closingBracket); return; } if (rtrim($tokens[$closingBracket + 1]['content']) !== $comment) { $phpcsFile->addError($error, $closingBracket); return; } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['scope_opener']) === false) { // Probably an interface method. return; } $openBrace = $tokens[$stackPtr]['scope_opener']; $nextContent = $phpcsFile->findNext(T_WHITESPACE, $openBrace + 1, null, true); if ($nextContent === $tokens[$stackPtr]['scope_closer']) { // The next bit of content is the closing brace, so this // is an empty function and should have a blank line // between the opening and closing braces. return; } $braceLine = $tokens[$openBrace]['line']; $nextLine = $tokens[$nextContent]['line']; $found = $nextLine - $braceLine - 1; if ($found > 0) { $error = "Expected 0 blank lines after opening function brace; {$found} found"; $phpcsFile->addError($error, $openBrace); } if ($phpcsFile->tokenizerType === 'JS') { // Do some additional checking before the function brace. $nestedFunction = $phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true; $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; $lineDifference = $braceLine - $functionLine; if ($nestedFunction === true) { if ($lineDifference > 0) { $error = "Expected 0 blank lines before openning brace of nested function; {$found} found"; $phpcsFile->addError($error, $openBrace); } } else { if ($lineDifference === 0) { $error = 'Opening brace should be on a new line'; $phpcsFile->addError($error, $openBrace); return; } if ($lineDifference > 1) { $ender = 'line'; if ($lineDifference - 1 !== 1) { $ender .= 's'; } $error = 'Opening brace should be on the line after the declaration; found ' . ($lineDifference - 1) . ' blank ' . $ender; $phpcsFile->addError($error, $openBrace); return; } } //end if } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] === T_EQUAL) { // Ignore closures. return; } $error = 'The use of inner functions is forbidden'; $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); } }
/** * Check if this use statement is part of the namespace block. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * * @return void */ private function _shouldIgnoreUse(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Ignore USE keywords inside closures. $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) { return true; } // Ignore USE keywords for traits. if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { return true; } return false; }
/** * This methods checks for return statements. * * If there is a doc comment like "@return void". * A forbidden return statement is in this context all return statement * expect "return;". * Like "return $foo;", "return 5;", "return null;", ... * * If there is a doc comment like "@return int", "@return bool", ... * A forbidden return statement is in this context "return;" * Because in a method with defined @return statement there must not be empty * return statements. * * @param array $tokens Token array of file * @param integer $tokenStart Integer, token number where the checks will begin * @param integer $tokenEnd Integer, token number where the checks will end * @param bool $nonEmpty If true, function returns true if there is a * non empty return statement like "return $foo;" * If false, function returns true if there is * a empty return statement like "return;" * * @return bool */ protected function checkAvailableReturnStatement(array $tokens, $tokenStart, $tokenEnd, $nonEmpty = true) { $returnStatementResult = false; do { $returnResult = null; $result = $this->currentFile->findNext(array(T_RETURN), $tokenStart, $tokenEnd); // If there is a return statement in this function / method, try to // find the next token, expect whitespaces. if ($result !== false) { $returnResult = $this->currentFile->findNext(array(T_WHITESPACE), $result + 1, $tokenEnd, true, null, true); } // If there is no return-Statement between $tokenStart and // $tokenEnd, stop here with the loop. if ($result === false) { $tokenStart = $tokenEnd; // If there is a return-Statement between $tokenStart and $tokenEnd, // check if the this return statement is part of an anonymous // functions. In this case, this will be ignored. } else { if ($nonEmpty === true && $this->currentFile->hasCondition($result, T_CLOSURE) === true) { break; // If there is a return-Statement between $tokenStart and $tokenEnd, // check if the next relevant token is a T_SEMICOLON. If no, this // is a normal return statement like "return $foo;". } else { if ($nonEmpty === true && $result !== false && $returnResult !== false && $tokens[$returnResult]['code'] !== T_SEMICOLON) { $returnStatementResult = true; break; // If there is a return-Statement between $tokenStart and $tokenEnd, // check if the next relevant token is a T_SEMICOLON. If yes, this // is a empty return statement like "return;". } else { if ($nonEmpty === false && $result !== false && $returnResult !== false && $tokens[$returnResult]['code'] === T_SEMICOLON) { $returnStatementResult = true; break; // If no case is affected, raise the pointer :). } else { $tokenStart = $result + 1; } } } } //end if } while ($tokenStart < $tokenEnd); return $returnStatementResult; }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['scope_closer']) === false) { // Probably an interface method. return; } $closeBrace = $tokens[$stackPtr]['scope_closer']; $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, $closeBrace - 1, null, true); // Special case for empty JS functions if ($phpcsFile->tokenizerType === 'JS' && $prevContent === $tokens[$stackPtr]['scope_opener']) { // In this case, the opening and closing brace must be // right next to each other. if ($tokens[$stackPtr]['scope_closer'] !== $tokens[$stackPtr]['scope_opener'] + 1) { $error = 'The opening and closing braces of empty functions must be directly next to each other; e.g., function () {}'; $phpcsFile->addError($error, $closeBrace, 'SpacingBetween'); } return; } $braceLine = $tokens[$closeBrace]['line']; $prevLine = $tokens[$prevContent]['line']; $found = $braceLine - $prevLine - 1; if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true) { // Nested function. if ($found < 0) { $error = 'Closing brace of nested function must be on a new line'; $phpcsFile->addError($error, $closeBrace, 'ContentBeforeClose'); } else { if ($found > 0) { $error = 'Expected 0 blank lines before closing brace of nested function; %s found'; $data = array($found); $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeNestedClose', $data); } } } else { if ($found !== 1) { $error = 'Expected 1 blank line before closing function brace; %s found'; $data = array($found); $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeClose', $data); } } }
/** * Processes the function tokens within the class. * * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. * @param int $stackPtr The position where the token was found. * @param int $currScope The current scope opener token. * * @return void */ protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) { $tokens = $phpcsFile->getTokens(); $className = $stackPtr - 1; if ($tokens[$className]['code'] === T_SELF) { if (strtolower($tokens[$className]['content']) !== $tokens[$className]['content']) { $error = 'Must use "self::" for local static member reference; found "%s::"'; $data = array($tokens[$className]['content']); $phpcsFile->addError($error, $className, 'IncorrectCase', $data); return; } } else { if ($tokens[$className]['code'] === T_STRING) { // Make sure this is another class reference. $declarationName = $phpcsFile->getDeclarationName($currScope); if ($declarationName === $tokens[$className]['content']) { // Class name is the same as the current class, which is not allowed // except if being used inside a closure. if ($phpcsFile->hasCondition($stackPtr, T_CLOSURE) === false) { $error = 'Must use "self::" for local static member reference'; $phpcsFile->addError($error, $className, 'NotUsed'); return; } } } } if ($tokens[$stackPtr - 1]['code'] === T_WHITESPACE) { $found = strlen($tokens[$stackPtr - 1]['content']); $error = 'Expected 0 spaces before double colon; %s found'; $data = array($found); $phpcsFile->addError($error, $className, 'SpaceBefore', $data); } if ($tokens[$stackPtr + 1]['code'] === T_WHITESPACE) { $found = strlen($tokens[$stackPtr + 1]['content']); $error = 'Expected 0 spaces after double colon; %s found'; $data = array($found); $phpcsFile->addError($error, $className, 'SpaceAfter', $data); } }
/** * Processes the tokens that this sniff is interested in. * * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found. * @param int $stackPtr The position in the stack where * the token was found. * * @return void * @see PHP_CodeSniffer_Sniff::process() */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $token = $tokens[$stackPtr]['content']; // Only accept class member functions if (false === $phpcsFile->hasCondition($stackPtr, T_CLASS)) { return; } $nextTokenIndex = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 1, null, true); $methodName = $tokens[$nextTokenIndex]['content']; $methodProperties = $phpcsFile->getMethodProperties($stackPtr); if (true === $methodProperties['is_abstract']) { // Warning for abstract static declared functions if (true === $methodProperties['is_static']) { $warning = sprintf('Abstract function "%s" should not be declared static!', $methodName); $phpcsFile->addWarning($warning, $stackPtr); } // Error for static abstract declared functions if ('private' === $methodProperties['scope']) { $error = sprintf('Abstract function "%s" can not be declared private!', $methodName); $phpcsFile->addError($error, $stackPtr); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $constName = $tokens[$stackPtr]['content']; // If this token is in a heredoc, ignore it. if ($phpcsFile->hasCondition($stackPtr, T_START_HEREDOC) === true) { return; } // Special case for PHPUnit. if ($constName === 'PHPUnit_MAIN_METHOD') { return; } // If the next non-whitespace token after this token // is not an opening parenthesis then it is not a function call. $openBracket = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { $functionKeyword = $phpcsFile->findPrevious(array(T_WHITESPACE, T_COMMA, T_COMMENT, T_STRING, T_NS_SEPARATOR), $stackPtr - 1, null, true); $declarations = array(T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT, T_IMPLEMENTS, T_EXTENDS, T_INSTANCEOF, T_NEW, T_NAMESPACE, T_USE, T_AS, T_GOTO, T_INSTEADOF); if (in_array($tokens[$functionKeyword]['code'], $declarations) === true) { // This is just a declaration; no constants here. return; } if ($tokens[$functionKeyword]['code'] === T_CONST) { // This is a class constant. if (strtoupper($constName) !== $constName) { $error = 'Class constants must be uppercase; expected %s but found %s'; $data = array(strtoupper($constName), $constName); $phpcsFile->addError($error, $stackPtr, 'ClassConstantNotUpperCase', $data); } return; } // Is this a class name? $nextPtr = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($tokens[$nextPtr]['code'] === T_DOUBLE_COLON) { return; } // Is this a namespace name? if ($tokens[$nextPtr]['code'] === T_NS_SEPARATOR) { return; } // Is this an insteadof name? if ($tokens[$nextPtr]['code'] === T_INSTEADOF) { return; } // Is this a type hint? if ($tokens[$nextPtr]['code'] === T_VARIABLE || $phpcsFile->isReference($nextPtr) === true) { return; } // Is this a member var name? $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { return; } // Is this a variable name, in the form ${varname} ? if ($tokens[$prevPtr]['code'] === T_OPEN_CURLY_BRACKET) { $nextPtr = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($tokens[$nextPtr]['code'] === T_CLOSE_CURLY_BRACKET) { return; } } // Is this a namespace name? if ($tokens[$prevPtr]['code'] === T_NS_SEPARATOR) { return; } // Is this an instance of declare() $prevPtrDeclare = $phpcsFile->findPrevious(array(T_WHITESPACE, T_OPEN_PARENTHESIS), $stackPtr - 1, null, true); if ($tokens[$prevPtrDeclare]['code'] === T_DECLARE) { return; } // Is this a goto label target? if ($tokens[$nextPtr]['code'] === T_COLON) { if (in_array($tokens[$prevPtr]['code'], array(T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_COLON), true)) { return; } } // This is a real constant. if (strtoupper($constName) !== $constName) { $error = 'Constants must be uppercase; expected %s but found %s'; $data = array(strtoupper($constName), $constName); $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); } } else { if (strtolower($constName) === 'define' || strtolower($constName) === 'constant') { /* This may be a "define" or "constant" function call. */ // Make sure this is not a method call. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR || $tokens[$prev]['code'] === T_DOUBLE_COLON) { return; } // The next non-whitespace token must be the constant name. $constPtr = $phpcsFile->findNext(T_WHITESPACE, $openBracket + 1, null, true); if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } $constName = $tokens[$constPtr]['content']; // Check for constants like self::CONSTANT. $prefix = ''; $splitPos = strpos($constName, '::'); if ($splitPos !== false) { $prefix = substr($constName, 0, $splitPos + 2); $constName = substr($constName, $splitPos + 2); } if (strtoupper($constName) !== $constName) { $error = 'Constants must be uppercase; expected %s but found %s'; $data = array($prefix . strtoupper($constName), $prefix . $constName); $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); } } } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $constName = $tokens[$stackPtr]['content']; // If this token is in a heredoc, ignore it. if ($phpcsFile->hasCondition($stackPtr, T_START_HEREDOC) === true) { return; } // Special case for PHP 5.5 class name resolution. if (strtolower($constName) === 'class' && $tokens[$stackPtr - 1]['code'] === T_DOUBLE_COLON) { return; } // Special case for PHPUnit. if ($constName === 'PHPUnit_MAIN_METHOD') { return; } // If the next non-whitespace token after this token // is not an opening parenthesis then it is not a function call. for ($openBracket = $stackPtr + 1; $openBracket < $phpcsFile->numTokens; $openBracket++) { if ($tokens[$openBracket]['code'] !== T_WHITESPACE) { break; } } if ($openBracket === $phpcsFile->numTokens) { return; } if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { $functionKeyword = $phpcsFile->findPrevious(array(T_WHITESPACE, T_COMMA, T_COMMENT, T_STRING, T_NS_SEPARATOR), $stackPtr - 1, null, true); if ($tokens[$functionKeyword]['code'] !== T_CONST) { return; } // This is a class constant. if (strtoupper($constName) !== $constName) { if (strtolower($constName) === $constName) { $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'lower'); } else { $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'mixed'); } $error = 'Class constants must be uppercase; expected %s but found %s'; $data = array(strtoupper($constName), $constName); $phpcsFile->addError($error, $stackPtr, 'ClassConstantNotUpperCase', $data); } else { $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'upper'); } return; } //end if if (strtolower($constName) !== 'define') { return; } /* This may be a "define" function call. */ // Make sure this is not a method call. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR || $tokens[$prev]['code'] === T_DOUBLE_COLON) { return; } // The next non-whitespace token must be the constant name. $constPtr = $phpcsFile->findNext(T_WHITESPACE, $openBracket + 1, null, true); if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } $constName = $tokens[$constPtr]['content']; // Check for constants like self::CONSTANT. $prefix = ''; $splitPos = strpos($constName, '::'); if ($splitPos !== false) { $prefix = substr($constName, 0, $splitPos + 2); $constName = substr($constName, $splitPos + 2); } if (strtoupper($constName) !== $constName) { if (strtolower($constName) === $constName) { $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'lower'); } else { $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'mixed'); } $error = 'Constants must be uppercase; expected %s but found %s'; $data = array($prefix . strtoupper($constName), $prefix . $constName); $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); } else { $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'upper'); } }
/** * Check what type of 'use' statement a token is part of. * * The T_USE token has multiple different uses: * * 1. In a closure: function () use ( $var ) {} * 2. In a class, to import a trait: use Trait_Name * 3. In a namespace, to import a class: use Some\Class; * * This function will check the token and return 'closure', 'trait', or 'class', * based on which of these uses the use is being used for. * * @param int $stackPtr The position of the token to check. * * @return string The type of use. */ protected function get_use_type($stackPtr) { // USE keywords inside closures. $next = $this->phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if (T_OPEN_PARENTHESIS === $this->tokens[$next]['code']) { return 'closure'; } // USE keywords for traits. if ($this->phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_TRAIT))) { return 'trait'; } // USE keywords for classes to import to a namespace. return 'class'; }
/** * Processes this sniff, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param integer $stackPtr The position of the current token in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($stackPtr == $phpcsFile->numTokens - 1) { //-- We reached the end of the file - without a closing tag if ($tokens[$stackPtr]['code'] == T_WHITESPACE) { $lastCode = $tokens[$stackPtr - 1]['code']; if ($lastCode != T_CLOSE_CURLY_BRACKET && $lastCode !== T_SEMICOLON) { //-- If the second last is not a curly bracket or a semicolon $phpcsFile->addError('Additional whitespace found at end of file', $stackPtr); } } else { if (strpos($tokens[$stackPtr]['content'], $phpcsFile->eolChar) === false) { //-- Files must end with an empty line $phpcsFile->addError('Please end your files with an empty line.', $stackPtr); } } } if ($tokens[$stackPtr]['code'] === T_OPEN_TAG) { /* Check for start of file whitespace. */ if ($phpcsFile->tokenizerType !== 'PHP') { // The first token is always the open tag inserted when tokenizsed // and the second token is always the first piece of content in // the file. If the second token is whitespace, there was // whitespace at the start of the file. if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { return; } } else { // If its the first token, then there is no space. if ($stackPtr === 0) { return; } for ($i = $stackPtr - 1; $i >= 0; $i--) { // If we find something that isn't inline html // then there is something previous in the file. if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { return; } // If we have ended up with inline html make sure it isn't just whitespace. $tokenContent = trim($tokens[$i]['content']); if ($tokenContent !== '') { return; } } //for } //end if $phpcsFile->addError('Additional whitespace found at start of file', $stackPtr); } else { if ($phpcsFile->numTokens == $stackPtr - 1) { //-- Wereached the end of the file - without a closing tag die('BB'); } else { if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) { /* Check for end of file whitespace. */ if ($phpcsFile->tokenizerType === 'JS') { // The last token is always the close tag inserted when tokenizsed // and the second last token is always the last piece of content in // the file. If the second last token is whitespace, there was // whitespace at the end of the file. if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) { return; } } else { if ($phpcsFile->tokenizerType === 'CSS') { // The last two tokens are always the close tag and whitespace // inserted when tokenizsed and the third last token is always the // last piece of content in the file. If the third last token is // whitespace, there was whitespace at the end of the file. if ($tokens[$stackPtr - 3]['code'] !== T_WHITESPACE) { return; } // Adjust the pointer to give the correct line number for the error. $stackPtr -= 2; } else { if (isset($tokens[$stackPtr + 1]) === false) { // The close PHP token is the last in the file. return; } for ($i = $stackPtr + 1; $i < $phpcsFile->numTokens; $i++) { // If we find something that isn't inline html then there // is more to the file. if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { return; } // If we have ended up with inline html make sure it // isn't just whitespace. $tokenContent = trim($tokens[$i]['content']); if (empty($tokenContent) === false) { return; } } //for } } $phpcsFile->addError('Additional whitespace found at end of file', $stackPtr); } else { /* Check for end of line whitespace. */ if (strpos($tokens[$stackPtr]['content'], $phpcsFile->eolChar) === false) { return; } $tokenContent = rtrim($tokens[$stackPtr]['content'], $phpcsFile->eolChar); if (empty($tokenContent) === false) { if (preg_match('|^.*\\s+$|', $tokenContent) !== 0) { $phpcsFile->addError('Whitespace found at end of line', $stackPtr); } } /* Check for multiple blanks lines in a function or class. */ if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || $phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { if ($tokens[$stackPtr - 1]['line'] < $tokens[$stackPtr]['line'] && $tokens[$stackPtr - 2]['line'] === $tokens[$stackPtr - 1]['line']) { // This is an empty line and the line before this one is not // empty, so this could be the start of a multiple empty // line block. $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr, null, true); $lines = $tokens[$next]['line'] - $tokens[$stackPtr]['line']; if ($lines > 1) { $error = 'Functions and classes must not contain multiple empty lines in a row;' . " found {$lines} empty lines"; $phpcsFile->addError($error, $stackPtr); } } } } } } //end if }
/** * Processes this sniff, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['code'] === T_OPEN_TAG) { /* Check for start of file whitespace. */ if ($phpcsFile->tokenizerType !== 'PHP') { // The first token is always the open tag inserted when tokenizsed // and the second token is always the first piece of content in // the file. If the second token is whitespace, there was // whitespace at the start of the file. if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { return; } } else { // If its the first token, then there is no space. if ($stackPtr === 0) { return; } for ($i = $stackPtr - 1; $i >= 0; $i--) { // If we find something that isn't inline html then there is something previous in the file. if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { return; } // If we have ended up with inline html make sure it isn't just whitespace. $tokenContent = trim($tokens[$i]['content']); if ($tokenContent !== '') { return; } } } //end if $phpcsFile->addError('Additional whitespace found at start of file', $stackPtr, 'StartFile'); } else { if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) { /* Check for end of file whitespace. */ if ($phpcsFile->tokenizerType === 'JS') { // The last token is always the close tag inserted when tokenized // and the second last token is always the last piece of content in // the file. If the second last token is whitespace, there was // whitespace at the end of the file. $stackPtr--; } else { if ($phpcsFile->tokenizerType === 'CSS') { // The last two tokens are always the close tag and whitespace // inserted when tokenizsed and the third last token is always the // last piece of content in the file. If the third last token is // whitespace, there was whitespace at the end of the file. $stackPtr -= 2; } } if ($phpcsFile->tokenizerType === 'PHP') { if (isset($tokens[$stackPtr + 1]) === false) { // The close PHP token is the last in the file. return; } for ($i = $stackPtr + 1; $i < $phpcsFile->numTokens; $i++) { // If we find something that isn't inline html then there // is more to the file. if ($tokens[$i]['type'] !== 'T_INLINE_HTML') { return; } // If we have ended up with inline html make sure it // isn't just whitespace. $tokenContent = trim($tokens[$i]['content']); if (empty($tokenContent) === false) { return; } } } else { // The pointer is now looking at the last content in the file and // not the fake PHP end tag the tokenizer inserted. if ($tokens[$stackPtr]['code'] !== T_WHITESPACE) { return; } // Allow a single newline at the end of the last line in the file. if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE && $tokens[$stackPtr]['content'] === $phpcsFile->eolChar) { return; } } $phpcsFile->addError('Additional whitespace found at end of file', $stackPtr, 'EndFile'); } else { /* Check for end of line whitespace. */ // Ignore whitespace that is not at the end of a line. if (strpos($tokens[$stackPtr]['content'], $phpcsFile->eolChar) === false) { return; } // Ignore blank lines if required. if ($this->ignoreBlankLines === true && $tokens[$stackPtr - 1]['line'] !== $tokens[$stackPtr]['line']) { return; } $tokenContent = rtrim($tokens[$stackPtr]['content'], $phpcsFile->eolChar); if (empty($tokenContent) === false) { if ($tokenContent !== rtrim($tokenContent)) { $phpcsFile->addError('Whitespace found at end of line', $stackPtr, 'EndLine'); } } /* Check for multiple blanks lines in a function. */ if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { if ($tokens[$stackPtr - 1]['line'] < $tokens[$stackPtr]['line'] && $tokens[$stackPtr - 2]['line'] === $tokens[$stackPtr - 1]['line']) { // This is an empty line and the line before this one is not // empty, so this could be the start of a multiple empty // line block. $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr, null, true); $lines = $tokens[$next]['line'] - $tokens[$stackPtr]['line']; if ($lines > 1) { $error = 'Functions must not contain multiple empty lines in a row; found %s empty lines'; $data = array($lines); $phpcsFile->addError($error, $stackPtr, 'EmptyLines', $data); } } } } } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $constName = $tokens[$stackPtr]['content']; // If this token is in a heredoc, ignore it. if ($phpcsFile->hasCondition($stackPtr, T_START_HEREDOC) === true) { return; } // If the next non-whitespace token after this token // is not an opening parenthesis then it is not a function call. $openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { $functionKeyword = $phpcsFile->findPrevious(array(T_WHITESPACE, T_COMMA, T_COMMENT, T_STRING), ($stackPtr - 1), null, true); $declarations = array( T_FUNCTION, T_CLASS, T_INTERFACE, T_IMPLEMENTS, T_EXTENDS, T_INSTANCEOF, T_NEW, ); if (in_array($tokens[$functionKeyword]['code'], $declarations) === true) { // This is just a declaration; no constants here. return; } if ($tokens[$functionKeyword]['code'] === T_CONST) { // This is a class constant. if (strtoupper($constName) !== $constName) { $error = 'Class constants must be uppercase; expected '.strtoupper($constName)." but found $constName"; $phpcsFile->addError($error, $stackPtr, 'ClassConstantNotUpperCase'); } return; } // Is this a class name? $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); if ($tokens[$nextPtr]['code'] === T_DOUBLE_COLON) { return; } // Is this a type hint? if ($tokens[$nextPtr]['code'] === T_VARIABLE) { return; } else if ($phpcsFile->isReference($nextPtr) === true) { return; } // Is this a member var name? $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) { return; } // Is this an instance of declare() $prevPtr = $phpcsFile->findPrevious(array(T_WHITESPACE, T_OPEN_PARENTHESIS), ($stackPtr - 1), null, true); if ($tokens[$prevPtr]['code'] === T_DECLARE) { return; } // This is a real constant. if (strtoupper($constName) !== $constName) { $error = 'Constants must be uppercase; expected '.strtoupper($constName)." but found $constName"; $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase'); } } else if (strtolower($constName) === 'define' || strtolower($constName) === 'constant') { /* This may be a "define" or "constant" function call. */ // Make sure this is not a method call. $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR) { return; } // The next non-whitespace token must be the constant name. $constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } $constName = $tokens[$constPtr]['content']; if (strtoupper($constName) !== $constName) { $error = 'Constants must be uppercase; expected '.strtoupper($constName)." but found $constName"; $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase'); } }//end if }//end process()
/** * Processes the variable found within a double quoted string. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param integer $stackPtr The position of the double quoted string. * @return void */ protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $phpReservedVars = array('_SERVER', '_GET', '_POST', '_REQUEST', '_SESSION', '_ENV', '_COOKIE', '_FILES', 'GLOBALS'); if (preg_match_all('|[^\\\\]\\$([a-zA-Z0-9_]+)|', $tokens[$stackPtr]['content'], $matches) !== 0) { foreach ($matches[1] as $varName) { // If it's a php reserved var, then its ok. if (in_array($varName, $phpReservedVars) === true) { continue; } // There is no way for us to know if the var is public or private, // so we have to ignore a leading underscore if there is one and just // check the main part of the variable name. $originalVarName = $varName; if (substr($varName, 0, 1) === '_') { if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) { $varName = substr($varName, 1); } } if ($this->_isValidVar($varName) === false) { $error = 'Variable "%s" is not in valid camel caps format'; $data = array($originalVarName); $phpcsFile->addFixableError($error, $stackPtr, 'StringVarNotCamelCaps', $data); if ($phpcsFile->fixer->enabled === true) { $originalVarName = '$' . $originalVarName; $newVarName = '$' . lcfirst(Inflector::camelize(strtolower($originalVarName))); $tokens[$stackPtr]['content'] = str_replace($originalVarName, $newVarName, $tokens[$stackPtr]['content']); } } } } }
/** * Processes the function tokens within the class. * * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. * @param int $stackPtr The position where the token was found. * @param int $currScope The current scope opener token. * * @return void */ protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) { // Is this the first throw token within the current function scope? // If so, we have to validate other throw tokens within the same scope. $previousThrow = $phpcsFile->findPrevious(T_THROW, $stackPtr - 1, $currScope); if ($previousThrow !== false) { return; } $tokens = $phpcsFile->getTokens(); $find = PHP_CodeSniffer_Tokens::$methodPrefixes; $find[] = T_WHITESPACE; $commentEnd = $phpcsFile->findPrevious($find, $currScope - 1, null, true); if ($tokens[$commentEnd]['code'] === T_COMMENT) { // Function is using the wrong type of comment. return; } if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG && $tokens[$commentEnd]['code'] !== T_COMMENT) { // Function doesn't have a doc comment. return; } $currScopeEnd = $tokens[$currScope]['scope_closer']; // Find all the exception type token within the current scope. $throwTokens = array(); $currPos = $stackPtr; $foundThrows = false; while ($currPos < $currScopeEnd && $currPos !== false) { if ($phpcsFile->hasCondition($currPos, T_CLOSURE) === false) { $foundThrows = true; /* If we can't find a NEW, we are probably throwing a variable, so we ignore it, but they still need to provide at least one @throws tag, even through we don't know the exception class. */ $nextToken = $phpcsFile->findNext(T_WHITESPACE, $currPos + 1, null, true); if ($tokens[$nextToken]['code'] === T_NEW) { $currException = $phpcsFile->findNext(array(T_NS_SEPARATOR, T_STRING), $currPos, $currScopeEnd, false, null, true); if ($currException !== false) { $endException = $phpcsFile->findNext(array(T_NS_SEPARATOR, T_STRING), $currException + 1, $currScopeEnd, true, null, true); if ($endException === false) { $throwTokens[] = $tokens[$currException]['content']; } else { $throwTokens[] = $phpcsFile->getTokensAsString($currException, $endException - $currException); } } //end if } //end if } //end if $currPos = $phpcsFile->findNext(T_THROW, $currPos + 1, $currScopeEnd); } //end while if ($foundThrows === false) { return; } // Only need one @throws tag for each type of exception thrown. $throwTokens = array_unique($throwTokens); $throwTags = array(); $commentStart = $tokens[$commentEnd]['comment_opener']; foreach ($tokens[$commentStart]['comment_tags'] as $tag) { if ($tokens[$tag]['content'] !== '@throws') { continue; } if ($tokens[$tag + 2]['code'] === T_DOC_COMMENT_STRING) { $exception = $tokens[$tag + 2]['content']; $space = strpos($exception, ' '); if ($space !== false) { $exception = substr($exception, 0, $space); } $throwTags[$exception] = true; } } if (empty($throwTags) === true) { $error = 'Missing @throws tag in function comment'; $phpcsFile->addError($error, $commentEnd, 'Missing'); return; } else { if (empty($throwTokens) === true) { // If token count is zero, it means that only variables are being // thrown, so we need at least one @throws tag (checked above). // Nothing more to do. return; } } // Make sure @throws tag count matches throw token count. $tokenCount = count($throwTokens); $tagCount = count($throwTags); if ($tokenCount !== $tagCount) { $error = 'Expected %s @throws tag(s) in function comment; %s found'; $data = array($tokenCount, $tagCount); $phpcsFile->addError($error, $commentEnd, 'WrongNumber', $data); return; } foreach ($throwTokens as $throw) { if (isset($throwTags[$throw]) === false) { $error = 'Missing @throws tag for "%s" exception'; $data = array($throw); $phpcsFile->addError($error, $commentEnd, 'Missing', $data); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['parenthesis_opener']) === true && isset($tokens[$stackPtr]['parenthesis_closer']) === true) { $parenOpener = $tokens[$stackPtr]['parenthesis_opener']; $parenCloser = $tokens[$stackPtr]['parenthesis_closer']; if ($tokens[$parenOpener + 1]['code'] === T_WHITESPACE) { $gap = $tokens[$parenOpener + 1]['length']; $error = 'Expected 0 spaces after opening bracket; %s found'; $data = array($gap); $fix = $phpcsFile->addFixableError($error, $parenOpener + 1, 'SpacingAfterOpenBrace', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($parenOpener + 1, ''); } if ($gap === 0) { $phpcsFile->recordMetric($stackPtr, 'Spaces after control structure open parenthesis', 'newline'); } else { $phpcsFile->recordMetric($stackPtr, 'Spaces after control structure open parenthesis', $gap); } } else { $phpcsFile->recordMetric($stackPtr, 'Spaces after control structure open parenthesis', 0); } if ($tokens[$parenOpener]['line'] === $tokens[$parenCloser]['line'] && $tokens[$parenCloser - 1]['code'] === T_WHITESPACE) { $gap = $tokens[$parenCloser - 1]['length']; $error = 'Expected 0 spaces before closing bracket; %s found'; $data = array($gap); $fix = $phpcsFile->addFixableError($error, $parenCloser - 1, 'SpaceBeforeCloseBrace', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($parenCloser - 1, ''); } if ($gap === 0) { $phpcsFile->recordMetric($stackPtr, 'Spaces before control structure close parenthesis', 'newline'); } else { $phpcsFile->recordMetric($stackPtr, 'Spaces before control structure close parenthesis', $gap); } } else { $phpcsFile->recordMetric($stackPtr, 'Spaces before control structure close parenthesis', 0); } } //end if if (isset($tokens[$stackPtr]['scope_closer']) === false) { return; } $scopeOpener = $tokens[$stackPtr]['scope_opener']; $scopeCloser = $tokens[$stackPtr]['scope_closer']; for ($firstContent = $scopeOpener + 1; $firstContent < $phpcsFile->numTokens; $firstContent++) { if ($tokens[$firstContent]['code'] !== T_WHITESPACE) { break; } } if ($tokens[$firstContent]['line'] >= $tokens[$scopeOpener]['line'] + 2) { $error = 'Blank line found at start of control structure'; $fix = $phpcsFile->addFixableError($error, $scopeOpener, 'SpacingAfterOpen'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $i = $scopeOpener + 1; while ($tokens[$i]['line'] !== $tokens[$firstContent]['line']) { $phpcsFile->fixer->replaceToken($i, ''); $i++; } $phpcsFile->fixer->addNewline($scopeOpener); $phpcsFile->fixer->endChangeset(); } } if ($firstContent !== $scopeCloser) { $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, $scopeCloser - 1, null, true); if ($tokens[$lastContent]['line'] <= $tokens[$scopeCloser]['line'] - 2) { $errorToken = $scopeCloser; for ($i = $scopeCloser - 1; $i > $lastContent; $i--) { if ($tokens[$i]['line'] < $tokens[$scopeCloser]['line']) { $errorToken = $i; break; } } $error = 'Blank line found at end of control structure'; $fix = $phpcsFile->addFixableError($error, $errorToken, 'SpacingBeforeClose'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $i = $scopeCloser - 1; for ($i = $scopeCloser - 1; $i > $lastContent; $i--) { if ($tokens[$i]['line'] === $tokens[$scopeCloser]['line']) { continue; } if ($tokens[$i]['line'] === $tokens[$lastContent]['line']) { break; } $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->endChangeset(); } } //end if } //end if $trailingContent = $phpcsFile->findNext(T_WHITESPACE, $scopeCloser + 1, null, true); if ($tokens[$trailingContent]['code'] === T_COMMENT) { // Special exception for code where the comment about // an ELSE or ELSEIF is written between the control structures. $nextCode = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $scopeCloser + 1, null, true); if ($tokens[$nextCode]['code'] === T_ELSE || $tokens[$nextCode]['code'] === T_ELSEIF) { $trailingContent = $nextCode; } } //end if if ($tokens[$trailingContent]['code'] === T_ELSE) { if ($tokens[$stackPtr]['code'] === T_IF) { // IF with ELSE. return; } } if ($tokens[$trailingContent]['code'] === T_WHILE && $tokens[$stackPtr]['code'] === T_DO) { // DO with WHILE. return; } if ($tokens[$trailingContent]['code'] === T_CLOSE_TAG) { // At the end of the script or embedded code. return; } if (isset($tokens[$trailingContent]['scope_condition']) === true && $tokens[$trailingContent]['scope_condition'] !== $trailingContent && isset($tokens[$trailingContent]['scope_opener']) === true && $tokens[$trailingContent]['scope_opener'] !== $trailingContent) { // Another control structure's closing brace. $owner = $tokens[$trailingContent]['scope_condition']; if ($tokens[$owner]['code'] === T_FUNCTION) { // The next content is the closing brace of a function // so normal function rules apply and we can ignore it. return; } if ($tokens[$owner]['code'] === T_CLOSURE && ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || $phpcsFile->hasCondition($stackPtr, T_CLOSURE) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true)) { return; } // ONGR Return statements must have blank line before them otherwise there should be no blank lines. if ($tokens[$trailingContent]['line'] !== $tokens[$scopeCloser]['line'] + 1 && $tokens[$trailingContent]['code'] !== T_RETURN) { $error = 'Blank line found after control structure'; $fix = $phpcsFile->addFixableError($error, $scopeCloser, 'LineAfterClose'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $i = $scopeCloser + 1; while ($tokens[$i]['line'] !== $tokens[$trailingContent]['line']) { $phpcsFile->fixer->replaceToken($i, ''); $i++; } $phpcsFile->fixer->addNewline($scopeCloser); $phpcsFile->fixer->endChangeset(); } } } //ONGR We do not require blank line after the control structure. // else if ($tokens[$trailingContent]['code'] !== T_ELSE // && $tokens[$trailingContent]['code'] !== T_ELSEIF // && $tokens[$trailingContent]['code'] !== T_CATCH // && $tokens[$trailingContent]['line'] === ($tokens[$scopeCloser]['line'] + 1) // ) { // $error = 'No blank line found after control structure'; // $fix = $phpcsFile->addFixableError($error, $scopeCloser, 'NoLineAfterClose'); // if ($fix === true) { // $phpcsFile->fixer->addNewline($scopeCloser); // } // }//end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['scope_closer']) === false) { // Probably an interface method. return; } $closeBrace = $tokens[$stackPtr]['scope_closer']; $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, $closeBrace - 1, null, true); // Special case for empty JS functions. if ($phpcsFile->tokenizerType === 'JS' && $prevContent === $tokens[$stackPtr]['scope_opener']) { // In this case, the opening and closing brace must be // right next to each other. if ($tokens[$stackPtr]['scope_closer'] !== $tokens[$stackPtr]['scope_opener'] + 1) { $error = 'The opening and closing braces of empty functions must be directly next to each other; e.g., function () {}'; $fix = $phpcsFile->addFixableError($error, $closeBrace, 'SpacingBetween'); if ($fix === true && $phpcsFile->fixer->enabled === true) { $phpcsFile->fixer->beginChangeset(); for ($i = $tokens[$stackPtr]['scope_opener'] + 1; $i < $closeBrace; $i++) { $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->endChangeset(); } } return; } $braceLine = $tokens[$closeBrace]['line']; $prevLine = $tokens[$prevContent]['line']; $found = $braceLine - $prevLine - 1; if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true) { // Nested function. if ($found < 0) { $error = 'Closing brace of nested function must be on a new line'; $fix = $phpcsFile->addFixableError($error, $closeBrace, 'ContentBeforeClose'); if ($fix === true && $phpcsFile->fixer->enabled === true) { $phpcsFile->fixer->addNewlineBefore($closeBrace); } } else { if ($found > 0) { $error = 'Expected 0 blank lines before closing brace of nested function; %s found'; $data = array($found); $fix = $phpcsFile->addFixableError($error, $closeBrace, 'SpacingBeforeNestedClose', $data); if ($fix === true && $phpcsFile->fixer->enabled === true) { $phpcsFile->fixer->beginChangeset(); for ($i = $prevContent + 1; $i < $closeBrace; $i++) { // Try and maintain indentation. if ($tokens[$i]['line'] === $braceLine) { break; } $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->addNewlineBefore($i); $phpcsFile->fixer->endChangeset(); } } } //end if } else { if ($found !== 1) { $error = 'Expected 1 blank line before closing function brace; %s found'; $data = array($found); $fix = $phpcsFile->addFixableError($error, $closeBrace, 'SpacingBeforeClose', $data); if ($fix === true && $phpcsFile->fixer->enabled === true) { if ($found > 1) { $phpcsFile->fixer->beginChangeset(); for ($i = $prevContent + 1; $i < $closeBrace - 1; $i++) { $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->replaceToken($i, $phpcsFile->eolChar); $phpcsFile->fixer->endChangeset(); } else { // Try and maintain indentation. if ($tokens[$closeBrace - 1]['code'] === T_WHITESPACE) { $phpcsFile->fixer->addNewlineBefore($closeBrace - 1); } else { $phpcsFile->fixer->addNewlineBefore($closeBrace); } } } } //end if } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $varName = ltrim($tokens[$stackPtr]['content'], '$'); $phpReservedVars = array('_SERVER', '_GET', '_POST', '_REQUEST', '_SESSION', '_ENV', '_COOKIE', '_FILES', 'GLOBALS', 'http_response_header', 'HTTP_RAW_POST_DATA', 'php_errormsg'); // If it's a php reserved var, then its ok. if (in_array($varName, $phpReservedVars) === true) { return; } $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), $stackPtr + 1, null, true); if ($tokens[$objOperator]['code'] === T_OBJECT_OPERATOR) { // Check to see if we are using a variable from an object. $var = $phpcsFile->findNext(array(T_WHITESPACE), $objOperator + 1, null, true); if ($tokens[$var]['code'] === T_STRING) { // Either a var name or a function call, so check for bracket. $bracket = $phpcsFile->findNext(array(T_WHITESPACE), $var + 1, null, true); if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { $objVarName = $tokens[$var]['content']; // There is no way for us to know if the var is public or private, // so we have to ignore a leading underscore if there is one and just // check the main part of the variable name. $originalVarName = $objVarName; if (substr($objVarName, 0, 1) === '_') { $objVarName = substr($objVarName, 1); } if (PHP_CodeSniffer::isCamelCaps($objVarName, false, true, false) === false) { $error = 'Variable "%s" is not in valid camel caps format'; $data = array($originalVarName); $phpcsFile->addError($error, $var, 'NotCamelCaps', $data); } else { if (preg_match('|\\d|', $objVarName)) { $warning = 'Variable "%s" contains numbers but this is discouraged'; $data = array($originalVarName); $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); } } } //end if } //end if } //end if // There is no way for us to know if the var is public or private, // so we have to ignore a leading underscore if there is one and just // check the main part of the variable name. $originalVarName = $varName; if (substr($varName, 0, 1) === '_') { $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), $stackPtr - 1, null, true); if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { // The variable lives within a class, and is referenced like // this: MyClass::$_variable, so we don't know its scope. $inClass = true; } else { $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE, T_TRAIT)); } if ($inClass === true) { $varName = substr($varName, 1); } } if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { $error = 'Variable "%s" is not in valid camel caps format'; $data = array($originalVarName); $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); } else { if (preg_match('|\\d|', $varName)) { $warning = 'Variable "%s" contains numbers but this is discouraged'; $data = array($originalVarName); $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]['scope_opener']) === false) { // Probably an interface method. return; } $openBrace = $tokens[$stackPtr]['scope_opener']; $nextContent = $phpcsFile->findNext(T_WHITESPACE, $openBrace + 1, null, true); if ($nextContent === $tokens[$stackPtr]['scope_closer']) { // The next bit of content is the closing brace, so this // is an empty function and should have a blank line // between the opening and closing braces. return; } $braceLine = $tokens[$openBrace]['line']; $nextLine = $tokens[$nextContent]['line']; $found = $nextLine - $braceLine - 1; if ($found > 0) { $error = 'Expected 0 blank lines after opening function brace; %s found'; $data = array($found); $fix = $phpcsFile->addFixableError($error, $openBrace, 'SpacingAfter', $data); if ($fix === true && $phpcsFile->fixer->enabled === true) { $phpcsFile->fixer->beginChangeset(); for ($i = $openBrace + 1; $i < $nextContent; $i++) { if ($tokens[$i]['line'] === $nextLine) { break; } $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->addNewline($openBrace); $phpcsFile->fixer->endChangeset(); } } if ($phpcsFile->tokenizerType === 'JS') { // Do some additional checking before the function brace. $nestedFunction = $phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true; $functionLine = $tokens[$tokens[$stackPtr]['parenthesis_closer']]['line']; $lineDifference = $braceLine - $functionLine; if ($nestedFunction === true) { if ($lineDifference > 0) { $error = 'Opening brace should be on the same line as the function keyword'; $fix = $phpcsFile->addFixableError($error, $openBrace, 'SpacingAfterNested'); if ($fix === true && $phpcsFile->fixer->enabled === true) { $phpcsFile->fixer->beginChangeset(); for ($i = $openBrace - 1; $i > $stackPtr; $i--) { if ($tokens[$i]['code'] !== T_WHITESPACE) { break; } $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->addContentBefore($openBrace, ' '); $phpcsFile->fixer->endChangeset(); } } } else { if ($lineDifference === 0) { $error = 'Opening brace should be on a new line'; $fix = $phpcsFile->addFixableError($error, $openBrace, 'ContentBefore'); if ($fix === true && $phpcsFile->fixer->enabled === true) { $phpcsFile->fixer->addNewlineBefore($openBrace); } return; } if ($lineDifference > 1) { $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)'; $data = array($lineDifference - 1); $fix = $phpcsFile->addError($error, $openBrace, 'SpacingBefore', $data); if ($fix === true && $phpcsFile->fixer->enabled === true) { $phpcsFile->fixer->beginChangeset(); for ($i = $openBrace - 1; $i > $stackPtr; $i--) { if ($tokens[$i]['code'] !== T_WHITESPACE) { break; } $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->addNewlineBefore($openBrace); $phpcsFile->fixer->endChangeset(); } return; } //end if } //end if } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); //remove the section "parenthesis_opener" if (isset($tokens[$stackPtr]['scope_closer']) === false) { return; } $scopeOpener = $tokens[$stackPtr]['scope_opener']; $scopeCloser = $tokens[$stackPtr]['scope_closer']; for ($firstContent = $scopeOpener + 1; $firstContent < $phpcsFile->numTokens; $firstContent++) { if ($tokens[$firstContent]['code'] !== T_WHITESPACE) { break; } } if ($tokens[$firstContent]['line'] >= $tokens[$scopeOpener]['line'] + 2) { $error = 'Blank line found at start of control structure'; $fix = $phpcsFile->addFixableError($error, $scopeOpener, 'SpacingAfterOpen'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $i = $scopeOpener + 1; while ($tokens[$i]['line'] !== $tokens[$firstContent]['line']) { $phpcsFile->fixer->replaceToken($i, ''); $i++; } $phpcsFile->fixer->addNewline($scopeOpener); $phpcsFile->fixer->endChangeset(); } } if ($firstContent !== $scopeCloser) { $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, $scopeCloser - 1, null, true); if ($tokens[$lastContent]['line'] <= $tokens[$scopeCloser]['line'] - 2) { $errorToken = $scopeCloser; for ($i = $scopeCloser - 1; $i > $lastContent; $i--) { if ($tokens[$i]['line'] < $tokens[$scopeCloser]['line']) { $errorToken = $i; break; } } $error = 'Blank line found at end of control structure'; $fix = $phpcsFile->addFixableError($error, $errorToken, 'SpacingBeforeClose'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $i = $scopeCloser - 1; for ($i = $scopeCloser - 1; $i > $lastContent; $i--) { if ($tokens[$i]['line'] === $tokens[$scopeCloser]['line']) { continue; } if ($tokens[$i]['line'] === $tokens[$lastContent]['line']) { break; } $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->endChangeset(); } } //end if } //end if $trailingContent = $phpcsFile->findNext(T_WHITESPACE, $scopeCloser + 1, null, true); if ($tokens[$trailingContent]['code'] === T_COMMENT) { // Special exception for code where the comment about // an ELSE or ELSEIF is written between the control structures. $nextCode = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $scopeCloser + 1, null, true); if ($tokens[$nextCode]['code'] === T_ELSE || $tokens[$nextCode]['code'] === T_ELSEIF) { $trailingContent = $nextCode; } } //end if if ($tokens[$trailingContent]['code'] === T_ELSE) { if ($tokens[$stackPtr]['code'] === T_IF) { // IF with ELSE. return; } } if ($tokens[$trailingContent]['code'] === T_WHILE && $tokens[$stackPtr]['code'] === T_DO) { // DO with WHILE. return; } if ($tokens[$trailingContent]['code'] === T_CLOSE_TAG) { // At the end of the script or embedded code. return; } if (isset($tokens[$trailingContent]['scope_condition']) === true && $tokens[$trailingContent]['scope_condition'] !== $trailingContent && isset($tokens[$trailingContent]['scope_opener']) === true && $tokens[$trailingContent]['scope_opener'] !== $trailingContent) { // Another control structure's closing brace. $owner = $tokens[$trailingContent]['scope_condition']; if ($tokens[$owner]['code'] === T_FUNCTION) { // The next content is the closing brace of a function // so normal function rules apply and we can ignore it. return; } if ($tokens[$owner]['code'] === T_CLOSURE && ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true || $phpcsFile->hasCondition($stackPtr, T_CLOSURE) === true || isset($tokens[$stackPtr]['nested_parenthesis']) === true)) { return; } if ($tokens[$trailingContent]['line'] !== $tokens[$scopeCloser]['line'] + 1) { $error = 'Blank line found after control structure'; $fix = $phpcsFile->addFixableError($error, $scopeCloser, 'LineAfterClose'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $i = $scopeCloser + 1; while ($tokens[$i]['line'] !== $tokens[$trailingContent]['line']) { $phpcsFile->fixer->replaceToken($i, ''); $i++; } $phpcsFile->fixer->addNewline($scopeCloser); $phpcsFile->fixer->endChangeset(); } } } else { if ($tokens[$trailingContent]['code'] !== T_ELSE && $tokens[$trailingContent]['code'] !== T_ELSEIF && $tokens[$trailingContent]['code'] !== T_CATCH && $tokens[$trailingContent]['code'] !== T_COMMENT && $tokens[$trailingContent]['code'] !== T_WHILE && $tokens[$trailingContent]['line'] === $tokens[$scopeCloser]['line'] + 1) { $error = 'No blank line found after control structure'; $fix = $phpcsFile->addFixableError($error, $scopeCloser, 'NoLineAfterClose'); if ($fix === true) { $phpcsFile->fixer->addNewline($scopeCloser); } } } //end if }
/** * Processes the variable found within a double quoted string. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the double quoted * string. * * @return void */ protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $phpReservedVars = array('_SERVER', '_GET', '_POST', '_REQUEST', '_SESSION', '_ENV', '_COOKIE', '_FILES', 'GLOBALS'); if (preg_match_all('|[^\\\\]\\$([a-zA-Z0-9_]+)|', $tokens[$stackPtr]['content'], $matches) !== 0) { foreach ($matches[1] as $varName) { // If it's a php reserved var, then its ok. if (in_array($varName, $phpReservedVars) === true) { continue; } // There is no way for us to know if the var is public or private, // so we have to ignore a leading underscore if there is one and just // check the main part of the variable name. $originalVarName = $varName; if (substr($varName, 0, 1) === '_') { if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) { $varName = substr($varName, 1); } } if (self::isUnderscores($varName, false, true, false) === false) { $varName = $matches[0]; $error = "Variable \"{$originalVarName}\" is not in valid camel caps format"; $phpcsFile->addError($error, $stackPtr); } else { if (preg_match('|\\d|', $varName)) { $warning = "Variable \"{$originalVarName}\" contains numbers but this is discouraged"; $phpcsFile->addWarning($warning, $stackPtr); } } } } //end if }
/** * Processes the variable found within a double quoted string. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the double quoted * string. * * @return void */ protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $phpReservedVars = array('_SERVER', '_GET', '_POST', '_REQUEST', '_SESSION', '_ENV', '_COOKIE', '_FILES', 'GLOBALS'); if (preg_match_all('|[^\\\\]\\${?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) { foreach ($matches[1] as $varName) { // If it's a php reserved var, then its ok. if (in_array($varName, $phpReservedVars) === true) { continue; } // There is no way for us to know if the var is public or private, // so we have to ignore a leading underscore if there is one and just // check the main part of the variable name. $originalVarName = $varName; if (substr($varName, 0, 1) === '_') { if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) { $varName = substr($varName, 1); } } if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { $varName = $matches[0]; $error = 'Variable "%s" is not in valid camel caps format'; $data = array($originalVarName); $phpcsFile->addError($error, $stackPtr, 'StringNotCamelCaps', $data); } } } //end if }
/** * Search if Function has a Return Statement * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * @param int $continueSearch If found a return in Condition of a closure * than continue to search * * @return bool */ protected function functionHasReturnStatement(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $continueSearch = null) { $tokens = $phpcsFile->getTokens(); $sFunctionToken = $tokens[$stackPtr]; $returnStatement = false; if (isset($sFunctionToken['scope_closer']) and isset($sFunctionToken['scope_opener'])) { $startSearch = $continueSearch !== null ? $continueSearch : $sFunctionToken['scope_opener']; $returnStatement = $phpcsFile->findNext(T_RETURN, $startSearch, $sFunctionToken['scope_closer']); } if ($returnStatement !== false) { if ($phpcsFile->hasCondition($returnStatement, T_CLOSURE)) { return $this->functionHasReturnStatement($phpcsFile, $stackPtr, $returnStatement + 1); } else { return true; } } return false; }