Server IP : 66.29.132.124 / Your IP : 3.145.65.133 Web Server : LiteSpeed System : Linux business141.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64 User : wavevlvu ( 1524) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/wavevlvu/book24.ng/vendor/phpdocumentor/type-resolver/src/Types/ |
Upload File : |
<?php declare(strict_types=1); /** * This file is part of phpDocumentor. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. * * @link http://phpdoc.org */ namespace phpDocumentor\Reflection\Types; use ArrayIterator; use InvalidArgumentException; use ReflectionClass; use ReflectionClassConstant; use ReflectionMethod; use ReflectionParameter; use ReflectionProperty; use Reflector; use RuntimeException; use UnexpectedValueException; use function define; use function defined; use function file_exists; use function file_get_contents; use function get_class; use function in_array; use function is_string; use function strrpos; use function substr; use function token_get_all; use function trim; use const T_AS; use const T_CLASS; use const T_CURLY_OPEN; use const T_DOLLAR_OPEN_CURLY_BRACES; use const T_NAME_FULLY_QUALIFIED; use const T_NAME_QUALIFIED; use const T_NAMESPACE; use const T_NS_SEPARATOR; use const T_STRING; use const T_USE; if (!defined('T_NAME_QUALIFIED')) { define('T_NAME_QUALIFIED', 'T_NAME_QUALIFIED'); } if (!defined('T_NAME_FULLY_QUALIFIED')) { define('T_NAME_FULLY_QUALIFIED', 'T_NAME_FULLY_QUALIFIED'); } /** * Convenience class to create a Context for DocBlocks when not using the Reflection Component of phpDocumentor. * * For a DocBlock to be able to resolve types that use partial namespace names or rely on namespace imports we need to * provide a bit of context so that the DocBlock can read that and based on it decide how to resolve the types to * Fully Qualified names. * * @see Context for more information. */ final class ContextFactory { /** The literal used at the end of a use statement. */ private const T_LITERAL_END_OF_USE = ';'; /** The literal used between sets of use statements */ private const T_LITERAL_USE_SEPARATOR = ','; /** * Build a Context given a Class Reflection. * * @see Context for more information on Contexts. */ public function createFromReflector(Reflector $reflector): Context { if ($reflector instanceof ReflectionClass) { //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable /** @var ReflectionClass<object> $reflector */ return $this->createFromReflectionClass($reflector); } if ($reflector instanceof ReflectionParameter) { return $this->createFromReflectionParameter($reflector); } if ($reflector instanceof ReflectionMethod) { return $this->createFromReflectionMethod($reflector); } if ($reflector instanceof ReflectionProperty) { return $this->createFromReflectionProperty($reflector); } if ($reflector instanceof ReflectionClassConstant) { return $this->createFromReflectionClassConstant($reflector); } throw new UnexpectedValueException('Unhandled \Reflector instance given: ' . get_class($reflector)); } private function createFromReflectionParameter(ReflectionParameter $parameter): Context { $class = $parameter->getDeclaringClass(); if (!$class) { throw new InvalidArgumentException('Unable to get class of ' . $parameter->getName()); } return $this->createFromReflectionClass($class); } private function createFromReflectionMethod(ReflectionMethod $method): Context { $class = $method->getDeclaringClass(); return $this->createFromReflectionClass($class); } private function createFromReflectionProperty(ReflectionProperty $property): Context { $class = $property->getDeclaringClass(); return $this->createFromReflectionClass($class); } private function createFromReflectionClassConstant(ReflectionClassConstant $constant): Context { //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable /** @phpstan-var ReflectionClass<object> $class */ $class = $constant->getDeclaringClass(); return $this->createFromReflectionClass($class); } /** * @phpstan-param ReflectionClass<object> $class */ private function createFromReflectionClass(ReflectionClass $class): Context { $fileName = $class->getFileName(); $namespace = $class->getNamespaceName(); if (is_string($fileName) && file_exists($fileName)) { $contents = file_get_contents($fileName); if ($contents === false) { throw new RuntimeException('Unable to read file "' . $fileName . '"'); } return $this->createForNamespace($namespace, $contents); } return new Context($namespace, []); } /** * Build a Context for a namespace in the provided file contents. * * @see Context for more information on Contexts. * * @param string $namespace It does not matter if a `\` precedes the namespace name, * this method first normalizes. * @param string $fileContents The file's contents to retrieve the aliases from with the given namespace. */ public function createForNamespace(string $namespace, string $fileContents): Context { $namespace = trim($namespace, '\\'); $useStatements = []; $currentNamespace = ''; $tokens = new ArrayIterator(token_get_all($fileContents)); while ($tokens->valid()) { $currentToken = $tokens->current(); switch ($currentToken[0]) { case T_NAMESPACE: $currentNamespace = $this->parseNamespace($tokens); break; case T_CLASS: // Fast-forward the iterator through the class so that any // T_USE tokens found within are skipped - these are not // valid namespace use statements so should be ignored. $braceLevel = 0; $firstBraceFound = false; while ($tokens->valid() && ($braceLevel > 0 || !$firstBraceFound)) { $currentToken = $tokens->current(); if ( $currentToken === '{' || in_array($currentToken[0], [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES], true) ) { if (!$firstBraceFound) { $firstBraceFound = true; } ++$braceLevel; } if ($currentToken === '}') { --$braceLevel; } $tokens->next(); } break; case T_USE: if ($currentNamespace === $namespace) { $useStatements += $this->parseUseStatement($tokens); } break; } $tokens->next(); } return new Context($namespace, $useStatements); } /** * Deduce the name from tokens when we are at the T_NAMESPACE token. * * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens */ private function parseNamespace(ArrayIterator $tokens): string { // skip to the first string or namespace separator $this->skipToNextStringOrNamespaceSeparator($tokens); $name = ''; $acceptedTokens = [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED]; while ($tokens->valid() && in_array($tokens->current()[0], $acceptedTokens, true)) { $name .= $tokens->current()[1]; $tokens->next(); } return $name; } /** * Deduce the names of all imports when we are at the T_USE token. * * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens * * @return string[] * @psalm-return array<string, string> */ private function parseUseStatement(ArrayIterator $tokens): array { $uses = []; while ($tokens->valid()) { $this->skipToNextStringOrNamespaceSeparator($tokens); $uses += $this->extractUseStatements($tokens); $currentToken = $tokens->current(); if ($currentToken[0] === self::T_LITERAL_END_OF_USE) { return $uses; } } return $uses; } /** * Fast-forwards the iterator as longs as we don't encounter a T_STRING or T_NS_SEPARATOR token. * * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens */ private function skipToNextStringOrNamespaceSeparator(ArrayIterator $tokens): void { while ($tokens->valid()) { $currentToken = $tokens->current(); if (in_array($currentToken[0], [T_STRING, T_NS_SEPARATOR], true)) { break; } if ($currentToken[0] === T_NAME_QUALIFIED) { break; } if (defined('T_NAME_FULLY_QUALIFIED') && $currentToken[0] === T_NAME_FULLY_QUALIFIED) { break; } $tokens->next(); } } /** * Deduce the namespace name and alias of an import when we are at the T_USE token or have not reached the end of * a USE statement yet. This will return a key/value array of the alias => namespace. * * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens * * @return string[] * @psalm-return array<string, string> * * @psalm-suppress TypeDoesNotContainType */ private function extractUseStatements(ArrayIterator $tokens): array { $extractedUseStatements = []; $groupedNs = ''; $currentNs = ''; $currentAlias = ''; $state = 'start'; while ($tokens->valid()) { $currentToken = $tokens->current(); $tokenId = is_string($currentToken) ? $currentToken : $currentToken[0]; $tokenValue = is_string($currentToken) ? null : $currentToken[1]; switch ($state) { case 'start': switch ($tokenId) { case T_STRING: case T_NS_SEPARATOR: $currentNs .= (string) $tokenValue; $currentAlias = $tokenValue; break; case T_NAME_QUALIFIED: case T_NAME_FULLY_QUALIFIED: $currentNs .= (string) $tokenValue; $currentAlias = substr( (string) $tokenValue, (int) (strrpos((string) $tokenValue, '\\')) + 1 ); break; case T_CURLY_OPEN: case '{': $state = 'grouped'; $groupedNs = $currentNs; break; case T_AS: $state = 'start-alias'; break; case self::T_LITERAL_USE_SEPARATOR: case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } break; case 'start-alias': switch ($tokenId) { case T_STRING: $currentAlias = $tokenValue; break; case self::T_LITERAL_USE_SEPARATOR: case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } break; case 'grouped': switch ($tokenId) { case T_STRING: case T_NS_SEPARATOR: $currentNs .= (string) $tokenValue; $currentAlias = $tokenValue; break; case T_AS: $state = 'grouped-alias'; break; case self::T_LITERAL_USE_SEPARATOR: $state = 'grouped'; $extractedUseStatements[(string) $currentAlias] = $currentNs; $currentNs = $groupedNs; $currentAlias = ''; break; case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } break; case 'grouped-alias': switch ($tokenId) { case T_STRING: $currentAlias = $tokenValue; break; case self::T_LITERAL_USE_SEPARATOR: $state = 'grouped'; $extractedUseStatements[(string) $currentAlias] = $currentNs; $currentNs = $groupedNs; $currentAlias = ''; break; case self::T_LITERAL_END_OF_USE: $state = 'end'; break; default: break; } } if ($state === 'end') { break; } $tokens->next(); } if ($groupedNs !== $currentNs) { $extractedUseStatements[(string) $currentAlias] = $currentNs; } return $extractedUseStatements; } }