/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $classes = array_keys($tokens->findGivenKind(T_CLASS)); $numClasses = count($classes); for ($i = 0; $i < $numClasses; ++$i) { $index = $classes[$i]; // is it inside a namespace? $nspIndex = $tokens->getPrevTokenOfKind($index, array(array(T_NAMESPACE, 'namespace'))); if (null !== $nspIndex) { $nspIndex = $tokens->getNextMeaningfulToken($nspIndex); // make sure it's not the global namespace, as PHP4 constructors are allowed in there if (!$tokens[$nspIndex]->equals('{')) { // unless it's the global namespace, the index currently points to the name $nspIndex = $tokens->getNextTokenOfKind($nspIndex, array(';', '{')); if ($tokens[$nspIndex]->equals(';')) { // the class is inside a (non-block) namespace, no PHP4-code should be in there break; } // the index points to the { of a block-namespace $nspEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nspIndex); if ($index < $nspEnd) { // the class is inside a block namespace, skip other classes that might be in it for ($j = $i + 1; $j < $numClasses; ++$j) { if ($classes[$j] < $nspEnd) { ++$i; } } // and continue checking the classes that might follow continue; } } } $classNameIndex = $tokens->getNextMeaningfulToken($index); $className = $tokens[$classNameIndex]->getContent(); $classStart = $tokens->getNextTokenOfKind($classNameIndex, array('{')); $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart); $this->fixConstructor($tokens, $className, $classStart, $classEnd); $this->fixParent($tokens, $classStart, $classEnd); } }
/** * @param Tokens $tokens * @param int $variableIndex * * @return bool */ private function isTypehintedNullableVariable(Tokens $tokens, $variableIndex) { $typehintedTokens = array(array(T_STRING), array(CT_ARRAY_TYPEHINT), ',', '('); $typehintedKinds = array(T_STRING, CT_ARRAY_TYPEHINT); if (PHP_VERSION_ID >= 50400) { $typehintedTokens[] = array(T_CALLABLE); $typehintedKinds[] = T_CALLABLE; } $prevMeaningfulTokenIndex = $tokens->getPrevTokenOfKind($variableIndex, $typehintedTokens); if (!$tokens[$prevMeaningfulTokenIndex]->isGivenKind($typehintedKinds)) { return false; } $nextMeaningfulTokenIndex = $tokens->getNextTokenOfKind($variableIndex, array(array(T_STRING), ',', ')')); $lowerCasedNextContent = strtolower($tokens[$nextMeaningfulTokenIndex]->getContent()); return 'null' === $lowerCasedNextContent; }
/** * @param Tokens $tokens * @param int $index Index of "=" * * @return bool */ private function isTypehintedNullableVariable(Tokens $tokens, $index) { $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)]; if (!$nextToken->equals(array(T_STRING, 'null'), false)) { return false; } $variableIndex = $tokens->getPrevMeaningfulToken($index); $searchTokens = array(',', '(', array(T_STRING), array(CT_ARRAY_TYPEHINT)); $typehintKinds = array(T_STRING, CT_ARRAY_TYPEHINT); if (defined('T_CALLABLE')) { $searchTokens[] = array(T_CALLABLE); $typehintKinds[] = T_CALLABLE; } $prevIndex = $tokens->getPrevTokenOfKind($variableIndex, $searchTokens); return $tokens[$prevIndex]->isGivenKind($typehintKinds); }
/** * @param Tokens $tokens * @param int $index * * @return string */ private function detectIndent(Tokens $tokens, $index) { while (true) { $whitespaceIndex = $tokens->getPrevTokenOfKind($index, array(array(T_WHITESPACE))); if (null === $whitespaceIndex) { return ''; } $whitespaceToken = $tokens[$whitespaceIndex]; if (false !== strpos($whitespaceToken->getContent(), "\n")) { break; } $prevToken = $tokens[$whitespaceIndex - 1]; if ($prevToken->isGivenKind(array(T_OPEN_TAG, T_COMMENT)) && "\n" === substr($prevToken->getContent(), -1)) { break; } $index = $whitespaceIndex; } $explodedContent = explode("\n", $whitespaceToken->getContent()); return end($explodedContent); }
/** * Return the first and last token index of the previous block. * * [0] First is either T_IF, T_ELSE or T_ELSEIF * [1] Last is either '}' or ';' / T_CLOSE_TAG for short notation blocks * * @param Tokens $tokens * @param int $index T_IF, T_ELSE, T_ELSEIF * * @return int[] */ private function getPreviousBlock(Tokens $tokens, $index) { $close = $previous = $tokens->getPrevMeaningfulToken($index); // short 'if' detection if ($tokens[$close]->equals('}')) { $previous = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $close, false); } $open = $tokens->getPrevTokenOfKind($previous, array(array(T_IF), array(T_ELSE), array(T_ELSEIF))); if ($tokens[$open]->isGivenKind(T_IF)) { $elseCandidate = $tokens->getPrevMeaningfulToken($open); if ($tokens[$elseCandidate]->isGivenKind(T_ELSE)) { $open = $elseCandidate; } } return array($open, $close); }