3 declare(strict_types=1);
5 namespace CuyZ\Valinor\Definition\Repository\Reflection;
7 use CuyZ\Valinor\Definition\Exception\TypesDoNotMatch;
8 use CuyZ\Valinor\Type\Parser\Exception\InvalidType;
9 use CuyZ\Valinor\Type\Parser\TypeParser;
10 use CuyZ\Valinor\Type\Type;
11 use CuyZ\Valinor\Type\Types\MixedType;
12 use CuyZ\Valinor\Type\Types\UnresolvableType;
13 use CuyZ\Valinor\Utility\Reflection\Reflection;
14 use ReflectionFunctionAbstract;
15 use ReflectionParameter;
16 use ReflectionProperty;
19 final class ReflectionTypeResolver
21 public function __construct(
22 private TypeParser $nativeParser,
23 private TypeParser $advancedParser
26 public function resolveType(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): Type
28 $nativeType = $this->nativeType($reflection);
29 $typeFromDocBlock = $this->typeFromDocBlock($reflection);
31 if (! $nativeType && ! $typeFromDocBlock) {
32 return MixedType::get();
36 /** @var Type $typeFromDocBlock */
37 return $typeFromDocBlock;
40 if (! $typeFromDocBlock) {
44 if (! $typeFromDocBlock instanceof UnresolvableType
45 && ! $nativeType instanceof UnresolvableType
46 && ! $typeFromDocBlock->matches($nativeType)
48 throw new TypesDoNotMatch($reflection, $typeFromDocBlock, $nativeType);
51 return $typeFromDocBlock;
54 private function typeFromDocBlock(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): ?Type
56 $type = $reflection instanceof ReflectionFunctionAbstract
57 ? Reflection::docBlockReturnType($reflection)
58 : Reflection::docBlockType($reflection);
64 return $this->parseType($type, $reflection, $this->advancedParser);
67 private function nativeType(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): ?Type
69 $reflectionType = $reflection instanceof ReflectionFunctionAbstract
70 ? $reflection->getReturnType()
71 : $reflection->getType();
73 if (! $reflectionType) {
77 $type = Reflection::flattenType($reflectionType);
79 if ($reflection instanceof ReflectionParameter && $reflection->isVariadic()) {
83 return $this->parseType($type, $reflection, $this->nativeParser);
86 private function parseType(string $raw, \ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection, TypeParser $parser): Type
89 return $parser->parse($raw);
90 } catch (InvalidType $exception) {
92 $signature = Reflection::signature($reflection);
94 if ($reflection instanceof ReflectionProperty) {
95 return UnresolvableType::forProperty($raw, $signature, $exception);
98 if ($reflection instanceof ReflectionParameter) {
99 return UnresolvableType::forParameter($raw, $signature, $exception);
102 return UnresolvableType::forMethodReturnType($raw, $signature, $exception);