/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') { return; } $commentLine = $tokens[$stackPtr]['line']; $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$lastContent]['line'] !== $commentLine) { return; } if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { return; } // Special case for JS files. if ($tokens[$lastContent]['code'] === T_COMMA || $tokens[$lastContent]['code'] === T_SEMICOLON) { $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, $lastContent - 1, null, true); if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) { return; } } $error = 'Comments may not appear after statements'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Found'); if ($fix === true) { $phpcsFile->fixer->addNewlineBefore($stackPtr); } }
/** * 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. * * @return void */ protected function processMemberVar(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['content'][1] === '_') { $error = 'Property name "%s" should not be prefixed with an underscore to indicate visibility'; $data = array($tokens[$stackPtr]['content']); $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); } // Detect multiple properties defined at the same time. Throw an error // for this, but also only process the first property in the list so we don't // repeat errors. $find = Tokens::$scopeModifiers; $find = array_merge($find, array(T_VARIABLE, T_VAR, T_SEMICOLON)); $prev = $phpcsFile->findPrevious($find, $stackPtr - 1); if ($tokens[$prev]['code'] === T_VARIABLE) { return; } if ($tokens[$prev]['code'] === T_VAR) { $error = 'The var keyword must not be used to declare a property'; $phpcsFile->addError($error, $stackPtr, 'VarUsed'); } $next = $phpcsFile->findNext(array(T_VARIABLE, T_SEMICOLON), $stackPtr + 1); if ($tokens[$next]['code'] === T_VARIABLE) { $error = 'There must not be more than one property declared per statement'; $phpcsFile->addError($error, $stackPtr, 'Multiple'); } $modifier = $phpcsFile->findPrevious(Tokens::$scopeModifiers, $stackPtr); if ($modifier === false || $tokens[$modifier]['line'] !== $tokens[$stackPtr]['line']) { $error = 'Visibility must be declared on property "%s"'; $data = array($tokens[$stackPtr]['content']); $phpcsFile->addError($error, $stackPtr, 'ScopeMissing', $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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Ignore this.something and other uses of "this" that are not // direct assignments. $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($tokens[$next]['code'] !== T_SEMICOLON) { if ($tokens[$next]['line'] === $tokens[$stackPtr]['line']) { return; } } // Something must be assigned to "this". $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] !== T_EQUAL) { return; } // A variable needs to be assigned to "this". $prev = $phpcsFile->findPrevious(T_WHITESPACE, $prev - 1, null, true); if ($tokens[$prev]['code'] !== T_STRING) { return; } // We can only assign "this" to a var called "self". if ($tokens[$prev]['content'] !== 'self' && $tokens[$prev]['content'] !== '_self') { $error = 'Keyword "this" can only be assigned to a variable called "self" or "_self"'; $phpcsFile->addError($error, $prev, 'NotSelf'); } }
/** * 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 */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Find the content of each class definition name. $classNames = array(); $next = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, $stackPtr + 1); if ($next === false) { // No class definitions in the file. return; } // Save the class names in a "scope", // to prevent false positives with @media blocks. $scope = 'main'; $find = array(T_CLOSE_CURLY_BRACKET, T_OPEN_CURLY_BRACKET, T_COMMENT, T_OPEN_TAG); while ($next !== false) { $prev = $phpcsFile->findPrevious($find, $next - 1); // Check if an inner block was closed. $beforePrev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $prev - 1, null, true); if ($beforePrev !== false && $tokens[$beforePrev]['code'] === T_CLOSE_CURLY_BRACKET) { $scope = 'main'; } // Create a sorted name for the class so we can compare classes // even when the individual names are all over the place. $name = ''; for ($i = $prev + 1; $i < $next; $i++) { $name .= $tokens[$i]['content']; } $name = trim($name); $name = str_replace("\n", ' ', $name); $name = preg_replace('|[\\s]+|', ' ', $name); $name = str_replace(', ', ',', $name); $names = explode(',', $name); sort($names); $name = implode(',', $names); if ($name[0] === '@') { // Media block has its own "scope". $scope = $name; } else { if (isset($classNames[$scope][$name]) === true) { $first = $classNames[$scope][$name]; $error = 'Duplicate class definition found; first defined on line %s'; $data = array($tokens[$first]['line']); $phpcsFile->addError($error, $next, 'Found', $data); } else { $classNames[$scope][$name] = $next; } } $next = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, $next + 1); } //end while }
/** * 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 */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($next === false) { return; } if ($tokens[$next]['code'] !== T_CLOSE_TAG) { $found = $tokens[$next]['line'] - $tokens[$stackPtr]['line'] - 1; if ($found !== 1) { $error = 'Expected one blank line after closing brace of class definition; %s found'; $data = array($found); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterClose', $data); if ($fix === true) { if ($found === 0) { $phpcsFile->fixer->addNewline($stackPtr); } else { $nextContent = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); $phpcsFile->fixer->beginChangeset(); for ($i = $stackPtr + 1; $i < $nextContent - 1; $i++) { $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->addNewline($i); $phpcsFile->fixer->endChangeset(); } } } //end if } //end if // Ignore nested style definitions from here on. The spacing before the closing brace // (a single blank line) will be enforced by the above check, which ensures there is a // blank line after the last nested class. $found = $phpcsFile->findPrevious(T_CLOSE_CURLY_BRACKET, $stackPtr - 1, $tokens[$stackPtr]['bracket_opener']); if ($found !== false) { return; } $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true); if ($prev === false) { return; } if ($tokens[$prev]['line'] === $tokens[$stackPtr]['line']) { $error = 'Closing brace of class definition must be on new line'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentBeforeClose'); if ($fix === true) { $phpcsFile->fixer->addNewlineBefore($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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Check if the next non whitespace token is a string. $index = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($tokens[$index]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } // Make sure it is the only thing in the square brackets. $next = $phpcsFile->findNext(T_WHITESPACE, $index + 1, null, true); if ($tokens[$next]['code'] !== T_CLOSE_SQUARE_BRACKET) { return; } // Allow indexes that have dots in them because we can't write // them in dot notation. $content = trim($tokens[$index]['content'], '"\' '); if (strpos($content, '.') !== false) { return; } // Also ignore reserved words. if ($content === 'super') { return; } // Token before the opening square bracket cannot be a var name. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] === T_STRING) { $error = 'Object indexes must be written in dot notation'; $phpcsFile->addError($error, $prev, 'Found'); } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Make sure this file only contains PHP code. for ($i = 0; $i < $phpcsFile->numTokens; $i++) { if ($tokens[$i]['code'] === T_INLINE_HTML && trim($tokens[$i]['content']) !== '') { return $phpcsFile->numTokens; } } // Find the last non-empty token. for ($last = $phpcsFile->numTokens - 1; $last > 0; $last--) { if (trim($tokens[$last]['content']) !== '') { break; } } if ($tokens[$last]['code'] === T_CLOSE_TAG) { $error = 'A closing tag is not permitted at the end of a PHP file'; $fix = $phpcsFile->addFixableError($error, $last, 'NotAllowed'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->replaceToken($last, $phpcsFile->eolChar); $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $last - 1, null, true); if ($tokens[$prev]['code'] !== T_SEMICOLON && $tokens[$prev]['code'] !== T_CLOSE_CURLY_BRACKET) { $phpcsFile->fixer->addContent($prev, ';'); } $phpcsFile->fixer->endChangeset(); } $phpcsFile->recordMetric($stackPtr, 'PHP closing tag at end of PHP-only file', 'yes'); } else { $phpcsFile->recordMetric($stackPtr, 'PHP closing tag at end of PHP-only file', 'no'); } // Ignore the rest of the file. return $phpcsFile->numTokens; }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $prevType = $tokens[$stackPtr - 1]['code']; if (isset(Tokens::$emptyTokens[$prevType]) === false) { return; } $nonSpace = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 2, null, true); if ($tokens[$nonSpace]['code'] === T_SEMICOLON) { // Empty statement. return; } $expected = $tokens[$nonSpace]['content'] . ';'; $found = $phpcsFile->getTokensAsString($nonSpace, $stackPtr - $nonSpace) . ';'; $error = 'Space found before semicolon; expected "%s" but found "%s"'; $data = array($expected, $found); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Incorrect', $data); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); for ($i = $stackPtr - 1; $i > $nonSpace; $i--) { $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->endChangeset(); } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $find = Tokens::$methodPrefixes; $find[] = T_WHITESPACE; $commentEnd = $phpcsFile->findPrevious($find, $stackPtr - 1, null, true); if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG && $tokens[$commentEnd]['code'] !== T_COMMENT) { $phpcsFile->addError('Missing class doc comment', $stackPtr, 'Missing'); $phpcsFile->recordMetric($stackPtr, 'Class has doc comment', 'no'); return; } $phpcsFile->recordMetric($stackPtr, 'Class has doc comment', 'yes'); if ($tokens[$commentEnd]['code'] === T_COMMENT) { $phpcsFile->addError('You must use "/**" style comments for a class comment', $stackPtr, 'WrongStyle'); return; } if ($tokens[$commentEnd]['line'] !== $tokens[$stackPtr]['line'] - 1) { $error = 'There must be no blank lines after the class comment'; $phpcsFile->addError($error, $commentEnd, 'SpacingAfter'); } $commentStart = $tokens[$commentEnd]['comment_opener']; foreach ($tokens[$commentStart]['comment_tags'] as $tag) { $error = '%s tag is not allowed in class comment'; $data = array($tokens[$tag]['content']); $phpcsFile->addWarning($error, $tag, 'TagNotAllowed', $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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $firstContent = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); // If the first non-whitespace token is not an opening parenthesis, then we are not concerned. if ($tokens[$firstContent]['code'] !== T_OPEN_PARENTHESIS) { $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'no'); return; } $end = $phpcsFile->findNext(array(T_SEMICOLON, T_CLOSE_TAG), $stackPtr, null, false); // If the token before the semi-colon is not a closing parenthesis, then we are not concerned. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $end - 1, null, true); if ($tokens[$prev]['code'] !== T_CLOSE_PARENTHESIS) { $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'no'); return; } // If the parenthesis don't match, then we are not concerned. if ($tokens[$firstContent]['parenthesis_closer'] !== $prev) { $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'no'); return; } $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'yes'); if ($phpcsFile->findNext(Tokens::$operators, $stackPtr, $end, false) === false) { // There are no arithmetic operators in this. $error = 'Echoed strings should not be bracketed'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'HasBracket'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->replaceToken($firstContent, ''); $phpcsFile->fixer->replaceToken($end - 1, ''); $phpcsFile->fixer->endChangeset(); } } }
/** * Processes this sniff, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // PHP 5.4 introduced a shorthand array declaration syntax, so we need // to ignore the these type of array declarations because this sniff is // only dealing with array usage. if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) { $openBracket = $stackPtr; } else { if (isset($tokens[$stackPtr]['bracket_opener']) === false) { return; } $openBracket = $tokens[$stackPtr]['bracket_opener']; } $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $openBracket - 1, null, true); if ($tokens[$prev]['code'] === T_EQUAL) { return; } // Square brackets can not have a space before them. $prevType = $tokens[$stackPtr - 1]['code']; if (isset(Tokens::$emptyTokens[$prevType]) === true) { $nonSpace = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 2, null, true); $expected = $tokens[$nonSpace]['content'] . $tokens[$stackPtr]['content']; $found = $phpcsFile->getTokensAsString($nonSpace, $stackPtr - $nonSpace) . $tokens[$stackPtr]['content']; $error = 'Space found before square bracket; expected "%s" but found "%s"'; $data = array($expected, $found); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceBeforeBracket', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr - 1, ''); } } // Open square brackets can't ever have spaces after them. if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) { $nextType = $tokens[$stackPtr + 1]['code']; if (isset(Tokens::$emptyTokens[$nextType]) === true) { $nonSpace = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 2, null, true); $expected = $tokens[$stackPtr]['content'] . $tokens[$nonSpace]['content']; $found = $phpcsFile->getTokensAsString($stackPtr, $nonSpace - $stackPtr + 1); $error = 'Space found after square bracket; expected "%s" but found "%s"'; $data = array($expected, $found); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterBracket', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr + 1, ''); } } } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $find = Tokens::$methodPrefixes; $find[] = T_WHITESPACE; $commentEnd = $phpcsFile->findPrevious($find, $stackPtr - 1, null, true); if ($tokens[$commentEnd]['code'] === T_COMMENT) { // Inline comments might just be closing comments for // control structures or functions instead of function comments // using the wrong comment type. If there is other code on the line, // assume they relate to that code. $prev = $phpcsFile->findPrevious($find, $commentEnd - 1, null, true); if ($prev !== false && $tokens[$prev]['line'] === $tokens[$commentEnd]['line']) { $commentEnd = $prev; } } if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG && $tokens[$commentEnd]['code'] !== T_COMMENT) { $phpcsFile->addError('Missing function doc comment', $stackPtr, 'Missing'); $phpcsFile->recordMetric($stackPtr, 'Function has doc comment', 'no'); return; } else { $phpcsFile->recordMetric($stackPtr, 'Function has doc comment', 'yes'); } if ($tokens[$commentEnd]['code'] === T_COMMENT) { $phpcsFile->addError('You must use "/**" style comments for a function comment', $stackPtr, 'WrongStyle'); return; } if ($tokens[$commentEnd]['line'] !== $tokens[$stackPtr]['line'] - 1) { $error = 'There must be no blank lines after the function comment'; $phpcsFile->addError($error, $commentEnd, 'SpacingAfter'); } $commentStart = $tokens[$commentEnd]['comment_opener']; foreach ($tokens[$commentStart]['comment_tags'] as $tag) { if ($tokens[$tag]['content'] === '@see') { // Make sure the tag isn't empty. $string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd); if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) { $error = 'Content missing for @see tag in function comment'; $phpcsFile->addError($error, $tag, 'EmptySees'); } } } $this->processReturn($phpcsFile, $stackPtr, $commentStart); $this->processThrows($phpcsFile, $stackPtr, $commentStart); $this->processParams($phpcsFile, $stackPtr, $commentStart); }
/** * 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(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) { $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 (Common::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); } } //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 (Common::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 int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Equal sign can't be the last thing on the line. $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($next === false) { // Bad assignment. return; } if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) { $error = 'Multi-line assignments must have the equal sign on the second line'; $phpcsFile->addError($error, $stackPtr, 'EqualSignLine'); return; } // Make sure it is the first thing on the line, otherwise we ignore it. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, false, true); if ($prev === false) { // Bad assignment. return; } if ($tokens[$prev]['line'] === $tokens[$stackPtr]['line']) { return; } // Find the required indent based on the ident of the previous line. $assignmentIndent = 0; $prevLine = $tokens[$prev]['line']; for ($i = $prev - 1; $i >= 0; $i--) { if ($tokens[$i]['line'] !== $prevLine) { $i++; break; } } if ($tokens[$i]['code'] === T_WHITESPACE) { $assignmentIndent = strlen($tokens[$i]['content']); } // Find the actual indent. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1); $expectedIndent = $assignmentIndent + $this->indent; $foundIndent = strlen($tokens[$prev]['content']); if ($foundIndent !== $expectedIndent) { $error = 'Multi-line assignment not indented correctly; expected %s spaces but found %s'; $data = array($expectedIndent, $foundIndent); $phpcsFile->addError($error, $stackPtr, 'Indent', $data); } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Make sure it is an API function. We know this by the doc comment. $commentEnd = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr); $commentStart = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $commentEnd - 1); $comment = $phpcsFile->getTokensAsString($commentStart, $commentEnd - $commentStart); if (strpos($comment, '* @api') === false) { return; } // Find all the vars passed in as we are only interested in comparisons // to NULL for these specific variables. $foundVars = array(); $open = $tokens[$stackPtr]['parenthesis_opener']; $close = $tokens[$stackPtr]['parenthesis_closer']; for ($i = $open + 1; $i < $close; $i++) { if ($tokens[$i]['code'] === T_VARIABLE) { $foundVars[$tokens[$i]['content']] = true; } } if (empty($foundVars) === true) { return; } $start = $tokens[$stackPtr]['scope_opener']; $end = $tokens[$stackPtr]['scope_closer']; for ($i = $start + 1; $i < $end; $i++) { if ($tokens[$i]['code'] !== T_VARIABLE || isset($foundVars[$tokens[$i]['content']]) === false) { continue; } $operator = $phpcsFile->findNext(T_WHITESPACE, $i + 1, null, true); if ($tokens[$operator]['code'] !== T_IS_IDENTICAL && $tokens[$operator]['code'] !== T_IS_NOT_IDENTICAL) { continue; } $nullValue = $phpcsFile->findNext(T_WHITESPACE, $operator + 1, null, true); if ($tokens[$nullValue]['code'] !== T_NULL) { continue; } $error = 'Values submitted via Ajax requests should not be compared directly to NULL; use empty() instead'; $phpcsFile->addWarning($error, $nullValue, 'Found'); } //end for }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $className = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if (strtolower($tokens[$className]['content']) === 'debug') { $method = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); $error = 'Call to debug function Debug::%s() must be removed'; $data = array($tokens[$method]['content']); $phpcsFile->addError($error, $stackPtr, 'Found', $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 */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Do not check nested style definitions as, for example, in @media style rules. $nested = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, $stackPtr + 1, $tokens[$stackPtr]['bracket_closer']); if ($nested !== false) { return; } // Find the first blank line before this opening brace, unless we get // to another style definition, comment or the start of the file. $endTokens = array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET, T_OPEN_TAG => T_OPEN_TAG); $endTokens += Tokens::$commentTokens; $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true); $foundContent = false; $currentLine = $tokens[$prev]['line']; for ($i = $stackPtr - 1; $i >= 0; $i--) { if (isset($endTokens[$tokens[$i]['code']]) === true) { break; } if ($tokens[$i]['line'] === $currentLine) { if ($tokens[$i]['code'] !== T_WHITESPACE) { $foundContent = true; } continue; } // We changed lines. if ($foundContent === false) { // Before we throw an error, make sure we are not looking // at a gap before the style definition. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $i, null, true); if ($prev !== false && isset($endTokens[$tokens[$prev]['code']]) === false) { $error = 'Blank lines are not allowed between class names'; $phpcsFile->addError($error, $i + 1, 'BlankLinesFound'); } break; } $foundContent = false; $currentLine = $tokens[$i]['line']; } //end for }
/** * Process the tokens that this sniff is listening for. * * @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 */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $allowedTokens = Tokens::$emptyTokens; $allowedTokens[] = T_BITWISE_AND; $prev = $phpcsFile->findPrevious($allowedTokens, $stackPtr - 1, null, true); $allowedTokens = array(T_EQUAL => true, T_DOUBLE_ARROW => true, T_THROW => true, T_RETURN => true, T_INLINE_THEN => true, T_INLINE_ELSE => true); if (isset($allowedTokens[$tokens[$prev]['code']]) === false) { $error = 'New objects must be assigned to a variable'; $phpcsFile->addError($error, $stackPtr, 'NotAssigned'); } }
/** * Process the tokens that this sniff is listening for. * * @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 */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] === T_COMMA) { $error = 'Last member of object must not be followed by a comma'; $fix = $phpcsFile->addFixableError($error, $prev, 'Missing'); if ($fix === true) { $phpcsFile->fixer->replaceToken($prev, ''); } } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['content'] !== 'join') { return; } $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] !== T_OBJECT_OPERATOR) { return; } $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $prev - 1, null, true); if ($tokens[$prev]['code'] === T_CLOSE_SQUARE_BRACKET) { $opener = $tokens[$prev]['bracket_opener']; if ($tokens[$opener - 1]['code'] !== T_STRING) { // This means the array is declared inline, like x = [a,b,c].join() // and not elsewhere, like x = y[a].join() // The first is not allowed while the second is. $error = 'Joining strings using inline arrays is not allowed; use the + operator instead'; $phpcsFile->addError($error, $stackPtr, 'ArrayNotAllowed'); } } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $tokenizer = $phpcsFile->tokenizerType; $openBracket = $tokens[$stackPtr]['parenthesis_opener']; $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; if ($tokens[$stackPtr]['code'] === T_FOR) { // We only want to check the condition in FOR loops. $start = $phpcsFile->findNext(T_SEMICOLON, $openBracket + 1); $end = $phpcsFile->findPrevious(T_SEMICOLON, $closeBracket - 1); } else { $start = $openBracket; $end = $closeBracket; } for ($i = $start + 1; $i < $end; $i++) { if ($tokens[$i]['code'] === T_STRING && isset($this->forbiddenFunctions[$tokenizer][$tokens[$i]['content']]) === true) { $functionName = $tokens[$i]['content']; if ($tokenizer === 'JS') { // Needs to be in the form object.function to be valid. $prev = $phpcsFile->findPrevious(T_WHITESPACE, $i - 1, null, true); if ($prev === false || $tokens[$prev]['code'] !== T_OBJECT_OPERATOR) { continue; } $functionName = 'object.' . $functionName; } else { // Make sure it isn't a member var. if ($tokens[$i - 1]['code'] === T_OBJECT_OPERATOR) { continue; } $functionName .= '()'; } $error = 'The use of %s inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead'; $data = array($functionName); $phpcsFile->addError($error, $i, 'Found', $data); } //end if } //end for }
/** * 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 */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] !== T_STYLE) { // The colon is not part of a style definition. return; } if ($tokens[$prev]['content'] === 'progid') { // Special case for IE filters. return; } if ($tokens[$stackPtr - 1]['code'] === T_WHITESPACE) { $error = 'There must be no space before a colon in a style definition'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Before'); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr - 1, ''); } } if ($tokens[$stackPtr + 1]['code'] === T_SEMICOLON) { // Empty style definition, ignore it. return; } if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space after colon in style definition; 0 found'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoneAfter'); if ($fix === true) { $phpcsFile->fixer->addContent($stackPtr, ' '); } } else { $content = $tokens[$stackPtr + 1]['content']; if (strpos($content, $phpcsFile->eolChar) === false) { $length = strlen($content); if ($length !== 1) { $error = 'Expected 1 space after colon in style definition; %s found'; $data = array($length); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'After', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr + 1, ' '); } } } else { $error = 'Expected 1 space after colon in style definition; newline found'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'AfterNewline'); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr + 1, ' '); } } } //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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Make sure this is a function call. $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($next === false) { // Not a function call. return; } if ($tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { // Not a function call. return; } $prev = $phpcsFile->findPrevious(array(T_WHITESPACE, T_BITWISE_AND), $stackPtr - 1, null, true); if ($tokens[$prev]['code'] === T_FUNCTION) { // Function declaration, not a function call. return; } if ($tokens[$prev]['code'] === T_NS_SEPARATOR) { // Namespaced class/function, not an inbuilt function. return; } if ($tokens[$prev]['code'] === T_NEW) { // Object creation, not an inbuilt function. return; } if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR) { // Not an inbuilt function. return; } if ($tokens[$prev]['code'] === T_DOUBLE_COLON) { // Not an inbuilt function. return; } // Make sure it is an inbuilt PHP function. // PHP_CodeSniffer can possibly include user defined functions // through the use of vendor/autoload.php. $content = $tokens[$stackPtr]['content']; if (isset($this->builtInFunctions[strtolower($content)]) === false) { return; } if ($content !== strtolower($content)) { $error = 'Calls to inbuilt PHP functions must be lowercase; expected "%s" but found "%s"'; $data = array(strtolower($content), $content); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'CallUppercase', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr, strtolower($content)); } } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $ignore = array(T_DOUBLE_COLON => true, T_OBJECT_OPERATOR => true, T_FUNCTION => true, T_CONST => true); $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if (isset($ignore[$tokens[$prevToken]['code']]) === true) { // Not a call to a PHP function. return; } $function = strtolower($tokens[$stackPtr]['content']); if ($function === 'php_sapi_name') { $error = 'Use the PHP_SAPI constant instead of calling php_sapi_name()'; $phpcsFile->addError($error, $stackPtr, 'FunctionFound'); } }
/** * 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(File $phpcsFile, $stackPtr) { if ($phpcsFile->findNext(T_INLINE_HTML, $stackPtr + 1) !== false) { return $phpcsFile->numTokens + 1; } // Skip to the end of the file. $tokens = $phpcsFile->getTokens(); $lastToken = $phpcsFile->numTokens - 1; // Hard-coding the expected \n in this sniff as it is PSR-2 specific and // PSR-2 enforces the use of unix style newlines. if (substr($tokens[$lastToken]['content'], -1) !== "\n") { $error = 'Expected 1 newline at end of file; 0 found'; $fix = $phpcsFile->addFixableError($error, $lastToken, 'NoneFound'); if ($fix === true) { $phpcsFile->fixer->addNewline($lastToken); } $phpcsFile->recordMetric($stackPtr, 'Number of newlines at EOF', '0'); return $phpcsFile->numTokens + 1; } // Go looking for the last non-empty line. $lastLine = $tokens[$lastToken]['line']; if ($tokens[$lastToken]['code'] === T_WHITESPACE) { $lastCode = $phpcsFile->findPrevious(T_WHITESPACE, $lastToken - 1, null, true); } else { $lastCode = $lastToken; } $lastCodeLine = $tokens[$lastCode]['line']; $blankLines = $lastLine - $lastCodeLine + 1; $phpcsFile->recordMetric($stackPtr, 'Number of newlines at EOF', $blankLines); if ($blankLines > 1) { $error = 'Expected 1 blank line at end of file; %s found'; $data = array($blankLines); $fix = $phpcsFile->addFixableError($error, $lastCode, 'TooMany', $data); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->replaceToken($lastCode, rtrim($tokens[$lastCode]['content'])); for ($i = $lastCode + 1; $i < $lastToken; $i++) { $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->replaceToken($lastToken, $phpcsFile->eolChar); $phpcsFile->fixer->endChangeset(); } } // Skip the rest of the file. return $phpcsFile->numTokens + 1; }
/** * 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(File $phpcsFile, $stackPtr) { // Work out which type of file this is for. $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['code'] === T_STRING_CONCAT) { if ($phpcsFile->tokenizerType === 'JS') { return; } } else { if ($phpcsFile->tokenizerType === 'PHP') { return; } } $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($prev === false || $next === false) { return; } if (isset(Tokens::$stringTokens[$tokens[$prev]['code']]) === true && isset(Tokens::$stringTokens[$tokens[$next]['code']]) === true) { if ($tokens[$prev]['content'][0] === $tokens[$next]['content'][0]) { // Before we throw an error for PHP, allow strings to be // combined if they would have < and ? next to each other because // this trick is sometimes required in PHP strings. if ($phpcsFile->tokenizerType === 'PHP') { $prevChar = substr($tokens[$prev]['content'], -2, 1); $nextChar = $tokens[$next]['content'][1]; $combined = $prevChar . $nextChar; if ($combined === '?' . '>' || $combined === '<' . '?') { return; } } if ($this->allowMultiline === true && $tokens[$prev]['line'] !== $tokens[$next]['line']) { return; } $error = 'String concat is not required here; use a single string instead'; if ($this->error === true) { $phpcsFile->addError($error, $stackPtr, 'Found'); } else { $phpcsFile->addWarning($error, $stackPtr, 'Found'); } } //end if } //end if }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // If this is an inline condition (ie. there is no scope opener), then // return, as this is not a new scope. if (isset($tokens[$stackPtr]['scope_closer']) === false) { return; } // We need to actually find the first piece of content on this line, // as if this is a method with tokens before it (public, static etc) // or an if with an else before it, then we need to start the scope // checking from there, rather than the current token. $lineStart = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true); $startColumn = $tokens[$lineStart]['column']; $scopeStart = $tokens[$stackPtr]['scope_opener']; $scopeEnd = $tokens[$stackPtr]['scope_closer']; // Check that the closing brace is on it's own line. $lastContent = $phpcsFile->findPrevious(array(T_INLINE_HTML, T_WHITESPACE, T_OPEN_TAG), $scopeEnd - 1, $scopeStart, true); if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) { $error = 'Closing brace must be on a line by itself'; $fix = $phpcsFile->addFixableError($error, $scopeEnd, 'ContentBefore'); if ($fix === true) { $phpcsFile->fixer->addNewlineBefore($scopeEnd); } return; } // Check now that the closing brace is lined up correctly. $lineStart = $phpcsFile->findFirstOnLine(T_WHITESPACE, $scopeEnd, true); $braceIndent = $tokens[$lineStart]['column']; if ($tokens[$stackPtr]['code'] !== T_DEFAULT && $tokens[$stackPtr]['code'] !== T_CASE && $braceIndent !== $startColumn) { $error = 'Closing brace indented incorrectly; expected %s spaces, found %s'; $data = array($startColumn - 1, $braceIndent - 1); $fix = $phpcsFile->addFixableError($error, $scopeEnd, 'Indent', $data); if ($fix === true) { $diff = $startColumn - $braceIndent; if ($diff > 0) { $phpcsFile->fixer->addContentBefore($scopeEnd, str_repeat(' ', $diff)); } else { $phpcsFile->fixer->substrToken($scopeEnd - 1, 0, $diff); } } } //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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Ignore default value assignments in function definitions. $function = $phpcsFile->findPrevious(T_FUNCTION, $stackPtr - 1, null, false, null, true); if ($function !== false) { $opener = $tokens[$function]['parenthesis_opener']; $closer = $tokens[$function]['parenthesis_closer']; if ($opener < $stackPtr && $closer > $stackPtr) { return; } } // Ignore values in array definitions. $array = $phpcsFile->findNext(T_ARRAY, $stackPtr + 1, null, false, null, true); if ($array !== false) { return; } // Ignore function calls. $ignore = array(T_STRING, T_WHITESPACE, T_OBJECT_OPERATOR); $next = $phpcsFile->findNext($ignore, $stackPtr + 1, null, true); if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS && $tokens[$next - 1]['code'] === T_STRING) { // Code will look like: $var = myFunction( // and will be ignored. return; } $endStatement = $phpcsFile->findNext(T_SEMICOLON, $stackPtr + 1); if ($tokens[$stackPtr]['conditions'] !== $tokens[$endStatement]['conditions']) { // This statement doesn't end with a semicolon, which is the case for // the last expression in a for loop. return; } for ($i = $stackPtr + 1; $i < $endStatement; $i++) { if (isset(Tokens::$comparisonTokens[$tokens[$i]['code']]) === true || $tokens[$i]['code'] === T_INLINE_THEN) { $error = 'The value of a comparison must not be assigned to a variable'; $phpcsFile->addError($error, $stackPtr, 'AssignedComparison'); break; } if (isset(Tokens::$booleanOperators[$tokens[$i]['code']]) === true || $tokens[$i]['code'] === T_BOOLEAN_NOT) { $error = 'The value of a boolean operation must not be assigned to a variable'; $phpcsFile->addError($error, $stackPtr, 'AssignedBool'); break; } } }
/** * Processes this sniff, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being checked. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Check there is one space before the operator. if ($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space before logical operator; 0 found'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpaceBefore'); if ($fix === true) { $phpcsFile->fixer->addContentBefore($stackPtr, ' '); } } else { $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$stackPtr]['line'] === $tokens[$prev]['line'] && strlen($tokens[$stackPtr - 1]['content']) !== 1) { $found = strlen($tokens[$stackPtr - 1]['content']); $error = 'Expected 1 space before logical operator; %s found'; $data = array($found); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'TooMuchSpaceBefore', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr - 1, ' '); } } } // Check there is one space after the operator. if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space after logical operator; 0 found'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpaceAfter'); if ($fix === true) { $phpcsFile->fixer->addContent($stackPtr, ' '); } } else { $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true); if ($tokens[$stackPtr]['line'] === $tokens[$next]['line'] && strlen($tokens[$stackPtr + 1]['content']) !== 1) { $found = strlen($tokens[$stackPtr + 1]['content']); $error = 'Expected 1 space after logical operator; %s found'; $data = array($found); $fix = $phpcsFile->addFixableError($error, $stackPtr, 'TooMuchSpaceAfter', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($stackPtr + 1, ' '); } } } }
/** * 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(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $function = $phpcsFile->getCondition($stackPtr, T_FUNCTION); if ($function === false) { // Not a nested function. return; } $class = $phpcsFile->getCondition($stackPtr, T_ANON_CLASS); if ($class !== false && $class > $function) { // Ignore methods in anon classes. return; } $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'); }