PhpCsFixer\Tokenizer\Tokens::findSequence PHP Method

findSequence() public method

Find a sequence of meaningful tokens and returns the array of their locations.
public findSequence ( array $sequence, integer $start, integer $end = null, boolean | array $caseSensitive = true ) : array | null
$sequence array an array of tokens (same format used by getNextTokenOfKind)
$start integer start index, defaulting to the start of the file
$end integer end index, defaulting to the end of the file
$caseSensitive boolean | array global case sensitiveness or an array of booleans, whose keys should match the ones used in $others. If any is missing, the default case-sensitive comparison is used
return array | null an array containing the tokens matching the sequence elements, indexed by their position
    public function findSequence(array $sequence, $start = 0, $end = null, $caseSensitive = true)
    {
        $sequenceCount = count($sequence);
        if (0 === $sequenceCount) {
            throw new \InvalidArgumentException('Invalid sequence.');
        }
        // $end defaults to the end of the collection
        $end = null === $end ? count($this) - 1 : min($end, count($this) - 1);
        if ($start + $sequenceCount - 1 > $end) {
            return;
        }
        // make sure the sequence content is "meaningful"
        foreach ($sequence as $key => $token) {
            // if not a Token instance already, we convert it to verify the meaningfulness
            if (!$token instanceof Token) {
                if (is_array($token) && !isset($token[1])) {
                    // fake some content as it is required by the Token constructor,
                    // although optional for search purposes
                    $token[1] = '';
                }
                $token = new Token($token);
            }
            if ($token->isWhitespace() || $token->isComment() || $token->isEmpty()) {
                throw new \InvalidArgumentException(sprintf('Non-meaningful token at position: %s.', $key));
            }
        }
        // remove the first token from the sequence, so we can freely iterate through the sequence after a match to
        // the first one is found
        $key = key($sequence);
        $firstCs = Token::isKeyCaseSensitive($caseSensitive, $key);
        $firstToken = $sequence[$key];
        unset($sequence[$key]);
        // begin searching for the first token in the sequence (start included)
        $index = $start - 1;
        while (null !== $index && $index <= $end) {
            $index = $this->getNextTokenOfKind($index, array($firstToken), $firstCs);
            // ensure we found a match and didn't get past the end index
            if (null === $index || $index > $end) {
                return;
            }
            // initialise the result array with the current index
            $result = array($index => $this[$index]);
            // advance cursor to the current position
            $currIdx = $index;
            // iterate through the remaining tokens in the sequence
            foreach ($sequence as $key => $token) {
                $currIdx = $this->getNextMeaningfulToken($currIdx);
                // ensure we didn't go too far
                if (null === $currIdx || $currIdx > $end) {
                    return;
                }
                if (!$this[$currIdx]->equals($token, Token::isKeyCaseSensitive($caseSensitive, $key))) {
                    // not a match, restart the outer loop
                    continue 2;
                }
                // append index to the result array
                $result[$currIdx] = $this[$currIdx];
            }
            // do we have a complete match?
            // hint: $result is bigger than $sequence since the first token has been removed from the latter
            if (count($sequence) < count($result)) {
                return $result;
            }
        }
    }

Usage Example

 /**
  * Looks up Tokens sequence for suitable candidates and delivers boundaries information,
  * which can be supplied by other methods in this abstract class.
  *
  * @param string   $functionNameToSearch
  * @param Tokens   $tokens
  * @param int      $start
  * @param int|null $end
  *
  * @return int[]|null returns $functionName, $openParenthesis, $closeParenthesis packed into array
  */
 protected function find($functionNameToSearch, Tokens $tokens, $start = 0, $end = null)
 {
     // make interface consistent with findSequence
     $end = null === $end ? $tokens->count() : $end;
     // find raw sequence which we can analyse for context
     $candidateSequence = array(array(T_STRING, $functionNameToSearch), '(');
     $matches = $tokens->findSequence($candidateSequence, $start, $end, false);
     if (null === $matches) {
         // not found, simply return without further attempts
         return;
     }
     // translate results for humans
     list($functionName, $openParenthesis) = array_keys($matches);
     // first criteria check: shall look like function call
     $functionNamePrefix = $tokens->getPrevMeaningfulToken($functionName);
     $functionNamePrecedingToken = $tokens[$functionNamePrefix];
     if ($functionNamePrecedingToken->isGivenKind(array(T_DOUBLE_COLON, T_NEW, T_OBJECT_OPERATOR, T_FUNCTION))) {
         // this expression is differs from expected, resume
         return $this->find($functionNameToSearch, $tokens, $openParenthesis, $end);
     }
     // second criteria check: ensure namespace is the root one
     if ($functionNamePrecedingToken->isGivenKind(T_NS_SEPARATOR)) {
         $namespaceCandidate = $tokens->getPrevMeaningfulToken($functionNamePrefix);
         $namespaceCandidateToken = $tokens[$namespaceCandidate];
         if ($namespaceCandidateToken->isGivenKind(array(T_NEW, T_STRING, CT::T_NAMESPACE_OPERATOR))) {
             // here can be added complete namespace scan
             // this expression is differs from expected, resume
             return $this->find($functionNameToSearch, $tokens, $openParenthesis, $end);
         }
     }
     // final step: find closing parenthesis
     $closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);
     return array($functionName, $openParenthesis, $closeParenthesis);
 }
All Usage Examples Of PhpCsFixer\Tokenizer\Tokens::findSequence