3 declare(strict_types=1);
5 namespace CuyZ\Valinor\Definition\Repository\Reflection;
7 use CuyZ\Valinor\Definition\FunctionDefinition;
8 use CuyZ\Valinor\Definition\Parameters;
9 use CuyZ\Valinor\Definition\Repository\AttributesRepository;
10 use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
11 use CuyZ\Valinor\Type\Parser\Factory\Specifications\AliasSpecification;
12 use CuyZ\Valinor\Type\Parser\Factory\Specifications\ClassContextSpecification;
13 use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory;
14 use CuyZ\Valinor\Utility\Reflection\Reflection;
15 use ReflectionFunction;
16 use ReflectionParameter;
18 use function str_ends_with;
21 final class ReflectionFunctionDefinitionRepository implements FunctionDefinitionRepository
23 private TypeParserFactory $typeParserFactory;
25 private AttributesRepository $attributesRepository;
27 private ReflectionParameterDefinitionBuilder $parameterBuilder;
29 public function __construct(TypeParserFactory $typeParserFactory, AttributesRepository $attributesRepository)
31 $this->typeParserFactory = $typeParserFactory;
32 $this->attributesRepository = $attributesRepository;
33 $this->parameterBuilder = new ReflectionParameterDefinitionBuilder($attributesRepository);
36 public function for(callable $function): FunctionDefinition
38 $reflection = Reflection::function($function);
40 $typeResolver = $this->typeResolver($reflection);
42 $parameters = array_map(
43 fn (ReflectionParameter $parameter) => $this->parameterBuilder->for($parameter, $typeResolver),
44 $reflection->getParameters()
47 $name = $reflection->getName();
48 $class = $reflection->getClosureScopeClass();
49 $returnType = $typeResolver->resolveType($reflection);
50 $isClosure = $name === '{closure}' || str_ends_with($name, '\\{closure}');
52 return new FunctionDefinition(
54 Reflection::signature($reflection),
55 $this->attributesRepository->for($reflection),
56 $reflection->getFileName() ?: null,
58 $reflection->getClosureThis() === null,
60 new Parameters(...$parameters),
65 private function typeResolver(ReflectionFunction $reflection): ReflectionTypeResolver
67 $class = $reflection->getClosureScopeClass();
69 $nativeSpecifications = [];
70 $advancedSpecification = [new AliasSpecification($reflection)];
72 if ($class !== null) {
73 $nativeSpecifications[] = new ClassContextSpecification($class->name);
74 $advancedSpecification[] = new ClassContextSpecification($class->name);
77 $nativeParser = $this->typeParserFactory->get(...$nativeSpecifications);
78 $advancedParser = $this->typeParserFactory->get(...$advancedSpecification);
80 return new ReflectionTypeResolver($nativeParser, $advancedParser);