PHP_CodeSniffer_File::findStartOfStatement PHP Method

findStartOfStatement() public method

Returns the position of the first non-whitespace token in a statement.
public findStartOfStatement ( integer $start, integer | array $ignore = null ) : integer
$start integer The position to start searching from in the token stack.
$ignore integer | array Token types that should not be considered stop points.
return integer
    public function findStartOfStatement($start, $ignore = null)
    {
        $endTokens = PHP_CodeSniffer_Tokens::$blockOpeners;
        $endTokens[T_COLON] = true;
        $endTokens[T_COMMA] = true;
        $endTokens[T_DOUBLE_ARROW] = true;
        $endTokens[T_SEMICOLON] = true;
        $endTokens[T_OPEN_TAG] = true;
        $endTokens[T_CLOSE_TAG] = true;
        $endTokens[T_OPEN_SHORT_ARRAY] = true;
        if ($ignore !== null) {
            $ignore = (array) $ignore;
            foreach ($ignore as $code) {
                if (isset($endTokens[$code]) === true) {
                    unset($endTokens[$code]);
                }
            }
        }
        $lastNotEmpty = $start;
        for ($i = $start; $i >= 0; $i--) {
            if (isset($endTokens[$this->_tokens[$i]['code']]) === true) {
                // Found the end of the previous statement.
                return $lastNotEmpty;
            }
            if (isset($this->_tokens[$i]['scope_opener']) === true && $i === $this->_tokens[$i]['scope_closer']) {
                // Found the end of the previous scope block.
                return $lastNotEmpty;
            }
            // Skip nested statements.
            if (isset($this->_tokens[$i]['bracket_opener']) === true && $i === $this->_tokens[$i]['bracket_closer']) {
                $i = $this->_tokens[$i]['bracket_opener'];
            } else {
                if (isset($this->_tokens[$i]['parenthesis_opener']) === true && $i === $this->_tokens[$i]['parenthesis_closer']) {
                    $i = $this->_tokens[$i]['parenthesis_opener'];
                }
            }
            if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$this->_tokens[$i]['code']]) === false) {
                $lastNotEmpty = $i;
            }
        }
        //end for
        return 0;
    }

Usage Example

 /**
  * 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 opening 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.
     $start = $phpcsFile->findStartOfStatement($stackPtr);
     foreach (array('stackPtr', 'start') as $checkToken) {
         $x = ${$checkToken};
         for ($i = $x - 1; $i >= 0; $i--) {
             if ($tokens[$i]['line'] !== $tokens[$x]['line']) {
                 $i++;
                 break;
             }
         }
         if ($i <= 0) {
             $functionIndent = 0;
         } else {
             if ($tokens[$i]['code'] === T_WHITESPACE) {
                 $functionIndent = strlen($tokens[$i]['content']);
             } else {
                 if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING) {
                     $functionIndent = 0;
                 } else {
                     $trimmed = ltrim($tokens[$i]['content']);
                     if ($trimmed === '') {
                         if ($tokens[$i]['code'] === T_INLINE_HTML) {
                             $functionIndent = strlen($tokens[$i]['content']);
                         } else {
                             $functionIndent = $tokens[$i]['column'] - 1;
                         }
                     } else {
                         $functionIndent = strlen($tokens[$i]['content']) - strlen($trimmed);
                     }
                 }
             }
         }
         $varName = $checkToken . 'Indent';
         ${$varName} = $functionIndent;
     }
     //end foreach
     $functionIndent = max($startIndent, $stackPtrIndent);
     $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $openBracket + 1, null, true);
     if ($tokens[$next]['line'] === $tokens[$openBracket]['line']) {
         $error = 'Opening parenthesis of a multi-line function call must be the last content on the line';
         $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentAfterOpenBracket');
         if ($fix === true) {
             $phpcsFile->fixer->addContent($openBracket, $phpcsFile->eolChar . str_repeat(' ', $functionIndent + $this->indent));
         }
     }
     $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
     $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';
         $fix = $phpcsFile->addFixableError($error, $closeBracket, 'CloseBracketLine');
         if ($fix === true) {
             $phpcsFile->fixer->addContentBefore($closeBracket, $phpcsFile->eolChar . str_repeat(' ', $functionIndent + $this->indent));
         }
     }
     // Each line between the parenthesis should be indented n spaces.
     $lastLine = $tokens[$openBracket]['line'];
     $argStart = null;
     $argEnd = null;
     $inArg = false;
     for ($i = $openBracket + 1; $i < $closeBracket; $i++) {
         if ($i > $argStart && $i < $argEnd) {
             $inArg = true;
         } else {
             $inArg = false;
         }
         if ($tokens[$i]['line'] !== $lastLine) {
             $lastLine = $tokens[$i]['line'];
             // Ignore heredoc indentation.
             if (isset(PHP_CodeSniffer_Tokens::$heredocTokens[$tokens[$i]['code']]) === true) {
                 continue;
             }
             // Ignore multi-line string indentation.
             if (isset(PHP_CodeSniffer_Tokens::$stringTokens[$tokens[$i]['code']]) === true && $tokens[$i]['code'] === $tokens[$i - 1]['code']) {
                 continue;
             }
             // Ignore inline HTML.
             if ($tokens[$i]['code'] === T_INLINE_HTML) {
                 continue;
             }
             // We changed lines, so this should be a whitespace indent token, but first make
             // sure it isn't a blank line because we don't need to check indent unless there
             // is actually some code to indent.
             if ($tokens[$i]['code'] === T_WHITESPACE) {
                 $nextCode = $phpcsFile->findNext(T_WHITESPACE, $i + 1, $closeBracket + 1, true);
                 if ($tokens[$nextCode]['line'] !== $lastLine) {
                     if ($inArg === false) {
                         $error = 'Empty lines are not allowed in multi-line function calls';
                         $fix = $phpcsFile->addFixableError($error, $i, 'EmptyLine');
                         if ($fix === true) {
                             $phpcsFile->fixer->replaceToken($i, '');
                         }
                     }
                     continue;
                 }
             } else {
                 $nextCode = $i;
             }
             if ($tokens[$nextCode]['line'] === $tokens[$closeBracket]['line']) {
                 // Closing brace needs to be indented to the same level
                 // as the function call.
                 $inArg = false;
                 $expectedIndent = $functionIndent;
             } else {
                 $expectedIndent = $functionIndent + $this->indent;
             }
             if ($tokens[$i]['code'] !== T_WHITESPACE && $tokens[$i]['code'] !== T_DOC_COMMENT_WHITESPACE) {
                 // Just check if it is a multi-line block comment. If so, we can
                 // calculate the indent from the whitespace before the content.
                 if ($tokens[$i]['code'] === T_COMMENT && $tokens[$i - 1]['code'] === T_COMMENT) {
                     $trimmed = ltrim($tokens[$i]['content']);
                     $foundIndent = strlen($tokens[$i]['content']) - strlen($trimmed);
                 } else {
                     $foundIndent = 0;
                 }
             } else {
                 $foundIndent = strlen($tokens[$i]['content']);
             }
             if ($foundIndent < $expectedIndent || $inArg === false && $expectedIndent !== $foundIndent) {
                 $error = 'Multi-line function call not indented correctly; expected %s spaces but found %s';
                 $data = array($expectedIndent, $foundIndent);
                 $fix = $phpcsFile->addFixableError($error, $i, 'Indent', $data);
                 if ($fix === true) {
                     $padding = str_repeat(' ', $expectedIndent);
                     if ($foundIndent === 0) {
                         $phpcsFile->fixer->addContentBefore($i, $padding);
                     } else {
                         if ($tokens[$i]['code'] === T_COMMENT) {
                             $comment = $padding . ltrim($tokens[$i]['content']);
                             $phpcsFile->fixer->replaceToken($i, $comment);
                         } else {
                             $phpcsFile->fixer->replaceToken($i, $padding);
                         }
                     }
                 }
             }
             //end if
             if ($inArg === false) {
                 $argStart = $nextCode;
                 $argEnd = $phpcsFile->findEndOfStatement($nextCode);
             }
         }
         //end if
         // If we are within an argument we should be ignoring commas
         // as these are not signaling the end of an argument.
         if ($inArg === false && $tokens[$i]['code'] === T_COMMA) {
             $next = $phpcsFile->findNext(array(T_WHITESPACE, T_COMMENT), $i + 1, $closeBracket, true);
             if ($next === false) {
                 continue;
             }
             if ($this->allowMultipleArguments === false) {
                 // Comma has to be the last token on the line.
                 if ($tokens[$i]['line'] === $tokens[$next]['line']) {
                     $error = 'Only one argument is allowed per line in a multi-line function call';
                     $fix = $phpcsFile->addFixableError($error, $next, 'MultipleArguments');
                     if ($fix === true) {
                         $phpcsFile->fixer->beginChangeset();
                         for ($x = $next - 1; $x > $i; $x--) {
                             if ($tokens[$x]['code'] !== T_WHITESPACE) {
                                 break;
                             }
                             $phpcsFile->fixer->replaceToken($x, '');
                         }
                         $phpcsFile->fixer->addContentBefore($next, $phpcsFile->eolChar . str_repeat(' ', $functionIndent + $this->indent));
                         $phpcsFile->fixer->endChangeset();
                     }
                 }
             }
             //end if
             $argStart = $next;
             $argEnd = $phpcsFile->findEndOfStatement($next);
         }
         //end if
     }
     //end for
 }
All Usage Examples Of PHP_CodeSniffer_File::findStartOfStatement