getTokens(); // Find the next non-empty token. $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { // Not a function call. return; } if (isset($tokens[$openBracket]['parenthesis_closer']) === false) { // Not a function call. return; } // Find the previous non-empty token. $search = PHP_CodeSniffer_Tokens::$emptyTokens; $search[] = T_BITWISE_AND; $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true); if ($tokens[$previous]['code'] === T_FUNCTION) { // It's a function definition, not a function call. return; } if ($tokens[$previous]['code'] === T_NEW) { // We are creating an object, not calling a function. return; } $closeBracket = $tokens[$openBracket]['parenthesis_closer']; if (($stackPtr + 1) !== $openBracket) { // Checking this: $value = my_function[*](...). $error = 'Space before opening parenthesis of function call prohibited'; $phpcsFile->addError($error, $stackPtr); } $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true); if ($tokens[$next]['code'] === T_SEMICOLON) { if (in_array($tokens[($closeBracket + 1)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { $error = 'Space after closing parenthesis of function call prohibited'; $phpcsFile->addError($error, $closeBracket); } } // Check if this is a single line or multi-line function call. if ($tokens[$openBracket]['line'] === $tokens[$closeBracket]['line']) { $this->processSingleLineCall($phpcsFile, $stackPtr, $openBracket, $tokens); } else { $this->processMultiLineCall($phpcsFile, $stackPtr, $openBracket, $tokens); } }//end process() /** * Processes single-line calls. * * @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 $openBracket The position of the openning bracket * in the stack passed in $tokens. * @param array $tokens The stack of tokens that make up * the file. * * @return void */ public function processSingleLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) { if ($tokens[($openBracket + 1)]['code'] === T_WHITESPACE) { // Checking this: $value = my_function([*]...). $error = 'Space after opening parenthesis of function call prohibited'; $phpcsFile->addError($error, $stackPtr); } $closer = $tokens[$openBracket]['parenthesis_closer']; if ($tokens[($closer - 1)]['code'] === T_WHITESPACE) { // Checking this: $value = my_function(...[*]). $between = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); // Only throw an error if there is some content between the parenthesis. // i.e., Checking for this: $value = my_function(). // If there is no content, then we would have thrown an error in the // previous IF statement because it would look like this: // $value = my_function( ). if ($between !== $closer) { $error = 'Space before closing parenthesis of function call prohibited'; $phpcsFile->addError($error, $closer); } } }//end processSingleLineCall() /** * Processes multi-line calls. * * @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 $openBracket The position of the openning bracket * in the stack passed in $tokens. * @param array $tokens The stack of tokens that make up * the file. * * @return void */ public function processMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens) { // We need to work out how far indented the function // call itself is, so we can work out how far to // indent the arguments. $functionIndent = 0; for ($i = ($stackPtr - 1); $i >= 0; $i--) { if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) { $i++; break; } } if ($tokens[$i]['code'] === T_WHITESPACE) { $functionIndent = strlen($tokens[$i]['content']); } // Each line between the parenthesis should be indented 4 spaces. $closeBracket = $tokens[$openBracket]['parenthesis_closer']; $lastLine = $tokens[$openBracket]['line']; for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { // Skip nested function calls. if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) { $i = $tokens[$i]['parenthesis_closer']; $lastLine = $tokens[$i]['line']; continue; } // Skip anonymous functions. if ($tokens[$i]['code'] === T_FUNCTION) { $openCurly = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, $i, $closeBracket); $i = $tokens[$openCurly]['bracket_closer'] + 1; if ($tokens[$i]['code'] === T_COMMA) $i++; continue; } if ($tokens[$i]['line'] !== $lastLine) { $lastLine = $tokens[$i]['line']; // We changed lines, so this should be a whitespace indent token. if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$heredocTokens) === true) { // Ignore heredoc indentation. continue; } if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) { if ($tokens[$i]['code'] === $tokens[($i - 1)]['code']) { // Ignore multi-line string indentation. continue; } } if ($tokens[$i]['line'] === $tokens[$closeBracket]['line']) { // Closing brace needs to be indented to the same level // as the function call. $expectedIndent = $functionIndent; } else { // Subsequent args must be aligned to the next tab stop and // at least 2 spaces further indented. $expectedIndent = $functionIndent - ($functionIndent % 4) + 4; if ($expectedIndent - $functionIndent < 2) { $expectedIndent += 4; } } if ($tokens[$i]['code'] !== T_WHITESPACE) { $foundIndent = 0; } else { $foundIndent = strlen($tokens[$i]['content']); } if ($expectedIndent !== $foundIndent) { $error = "Multi-line function call not indented correctly; expected $expectedIndent spaces but found $foundIndent"; $phpcsFile->addError($error, $i); } }//end if }//end for if ($tokens[($openBracket + 1)]['content'] !== $phpcsFile->eolChar) { $error = 'Opening parenthesis of a multi-line function call must be the last content on the line'; // skip error if next line starts with anonymous function. $nextFunc = $phpcsFile->findNext(T_FUNCTION, $openBracket, $closeBracket); if (!$nextFunc || $tokens[$nextFunc]['line'] !== $tokens[$openBracket]['line'] + 1) { $phpcsFile->addError($error, $stackPtr); } } $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBracket - 1), null, true); if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) { $error = 'Closing parenthesis of a multi-line function call must be on a line by itself'; $phpcsFile->addError($error, $closeBracket); } }//end processMultiLineCall() }//end class ?>