src/Tokenizer/Tokens.php
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 null;
        }

        // 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] = 'DUMMY';
                }
                $token = new Token($token);
            }

            if ($token->isWhitespace() || $token->isComment() || '' === $token->getContent()) {
                throw new \InvalidArgumentException(sprintf('Non-meaningful token at position: %s.', $key));
            }
        }

        if (!self::isLegacyMode()) {
            foreach ($sequence as $token) {
                if (!$this->isTokenKindFound($this->extractTokenKind($token))) {
                    return null;
                }
            }
        }

        // 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, [$firstToken], $firstCs);

            // ensure we found a match and didn't get past the end index
            if (null === $index || $index > $end) {
                return null;
            }

            // initialise the result array with the current index
            $result = [$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 null;
                }

                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;
            }
        }
    }
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 null;
        }

        // 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] = 'DUMMY';
                }
                $token = new Token($token);
            }

            if ($token->isWhitespace() || $token->isComment() || '' === $token->getContent()) {
                throw new \InvalidArgumentException(sprintf('Non-meaningful token at position: %s.', $key));
            }
        }

        if (!self::isLegacyMode()) {
            foreach ($sequence as $token) {
                if (!$this->isTokenKindFound($this->extractTokenKind($token))) {
                    return null;
                }
            }
        }

        // 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, [$firstToken], $firstCs);

            // ensure we found a match and didn't get past the end index
            if (null === $index || $index > $end) {
                return null;
            }

            // initialise the result array with the current index
            $result = [$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 null;
                }

                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;
            }
        }
    }
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 null ; } // 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 ] = 'DUMMY' ; } $ token = new Token ( $ token ) ; } if ( $ token -> isWhitespace ( ) || $ token -> isComment ( ) || '' === $ token -> getContent ( ) ) { throw new \ InvalidArgumentException ( sprintf ( 'Non-meaningful token at position: %s.' , $ key ) ) ; } } if ( ! self :: isLegacyMode ( ) ) { foreach ( $ sequence as $ token ) { if ( ! $ this -> isTokenKindFound ( $ this -> extractTokenKind ( $ token ) ) ) { return null ; } } } // 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 , [ $ firstToken ] , $ firstCs ) ; // ensure we found a match and didn't get past the end index if ( null === $ index || $ index > $ end ) { return null ; } // initialise the result array with the current index $ result = [ $ 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 null ; } 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 ; } } }
Find a sequence of meaningful tokens and returns the array of their locations.

@param array                 $sequence      an array of tokens (kinds) (same format used by getNextTokenOfKind)
@param int                   $start         start index, defaulting to the start of the file
@param int                   $end           end index, defaulting to the end of the file
@param array<int, bool>|bool $caseSensitive 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 null|array<int, Token> an array containing the tokens matching the sequence elements, indexed by their position
Find a sequence of meaningful tokens and returns the array of their locations .