%PDF- %PDF-
Direktori : /var/www/html/rental/vendor/phpspec/phpspec/src/PhpSpec/CodeAnalysis/ |
Current File : /var/www/html/rental/vendor/phpspec/phpspec/src/PhpSpec/CodeAnalysis/TokenizedTypeHintRewriter.php |
<?php /* * This file is part of PhpSpec, A php toolset to drive emergent * design by specification. * * (c) Marcello Duarte <marcello.duarte@gmail.com> * (c) Konstantin Kudryashov <ever.zet@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PhpSpec\CodeAnalysis; use PhpSpec\Loader\Transformer\TypeHintIndex; final class TokenizedTypeHintRewriter implements TypeHintRewriter { const STATE_DEFAULT = 0; const STATE_READING_CLASS = 1; const STATE_READING_FUNCTION = 2; const STATE_READING_ARGUMENTS = 3; const STATE_READING_FUNCTION_BODY = 4; private $state = self::STATE_DEFAULT; private $currentClass; private $currentFunction; private $currentBodyLevel; private $typehintTokens = array( T_WHITESPACE, T_STRING, T_NS_SEPARATOR ); /** * @var TypeHintIndex */ private $typeHintIndex; /** * @var NamespaceResolver */ private $namespaceResolver; /** * @param TypeHintIndex $typeHintIndex * @param NamespaceResolver $namespaceResolver */ public function __construct(TypeHintIndex $typeHintIndex, NamespaceResolver $namespaceResolver) { $this->typeHintIndex = $typeHintIndex; $this->namespaceResolver = $namespaceResolver; } /** * @param string $classDefinition * * @return string */ public function rewrite($classDefinition) { $this->namespaceResolver->analyse($classDefinition); $this->reset(); $tokens = $this->stripTypeHints(token_get_all($classDefinition)); $tokensToString = $this->tokensToString($tokens); return $tokensToString; } private function reset() { $this->state = self::STATE_DEFAULT; $this->currentClass = ''; $this->currentFunction = ''; } /** * @param array $tokens * @return array $tokens */ private function stripTypeHints($tokens) { foreach ($tokens as $index => $token) { if ($this->isToken($token, '{')) { $this->currentBodyLevel++; } elseif ($this->isToken($token, '}')) { $this->currentBodyLevel--; } switch ($this->state) { case self::STATE_READING_ARGUMENTS: if (')' == $token) { $this->state = self::STATE_READING_CLASS; } elseif ($this->tokenHasType($token, T_VARIABLE)) { $this->extractTypehints($tokens, $index, $token); } break; case self::STATE_READING_FUNCTION: if ('(' == $token) { $this->state = self::STATE_READING_ARGUMENTS; } elseif ($this->tokenHasType($token, T_STRING) && !$this->currentFunction) { $this->currentFunction = $token[1]; } break; case self::STATE_READING_CLASS: if ('{' == $token && $this->currentFunction) { $this->state = self::STATE_READING_FUNCTION_BODY; $this->currentBodyLevel = 1; } elseif ('}' == $token && $this->currentClass) { $this->state = self::STATE_DEFAULT; $this->currentClass = null; } elseif ($this->tokenHasType($token, T_STRING) && !$this->currentClass && $this->shouldExtractTokensOfClass($token[1])) { $this->currentClass = $token[1]; } elseif ($this->tokenHasType($token, T_FUNCTION) && $this->currentClass) { $this->state = self::STATE_READING_FUNCTION; } break; case self::STATE_READING_FUNCTION_BODY: if ('}' == $token && $this->currentBodyLevel === 0) { $this->currentFunction = ''; $this->state = self::STATE_READING_CLASS; } break; default: if ($this->tokenHasType($token, T_CLASS)) { $this->state = self::STATE_READING_CLASS; } } } return $tokens; } /** * @param array $tokens * @return string */ private function tokensToString($tokens) { return join('', array_map(function ($token) { return is_array($token) ? $token[1] : $token; }, $tokens)); } /** * @param array $tokens * @param integer $index * @param array $token */ private function extractTypehints(&$tokens, $index, $token) { $typehint = ''; for ($i = $index - 1; in_array($tokens[$i][0], $this->typehintTokens); $i--) { $typehint = $tokens[$i][1] . $typehint; if (T_WHITESPACE !== $tokens[$i][0]) { unset($tokens[$i]); } } if ($typehint = trim($typehint)) { $class = $this->namespaceResolver->resolve($this->currentClass); try { $typehintFcqn = $this->namespaceResolver->resolve($typehint); $this->typeHintIndex->add( $class, trim($this->currentFunction), $token[1], $typehintFcqn ); } catch (DisallowedScalarTypehintException $e) { $this->typeHintIndex->addInvalid( $class, trim($this->currentFunction), $token[1], $e ); } } } /** * @param array|string $token * @param string $type * * @return bool */ private function tokenHasType($token, $type) { return is_array($token) && $type == $token[0]; } /** * @param string $className * * @return bool */ private function shouldExtractTokensOfClass($className) { return substr($className, -4) == 'Spec'; } /** * @param array|string $token * @param string $string * * @return bool */ private function isToken($token, $string) { return $token == $string || (is_array($token) && $token[1] == $string); } }