diff --git a/src/Definition/DoctrineAnnotations.php b/src/Definition/DoctrineAnnotations.php index e8ddf1c3..812443a9 100644 --- a/src/Definition/DoctrineAnnotations.php +++ b/src/Definition/DoctrineAnnotations.php @@ -7,6 +7,7 @@ use CuyZ\Valinor\Definition\Exception\InvalidReflectionParameter; use CuyZ\Valinor\Utility\Singleton; use ReflectionClass; +use ReflectionFunction; use ReflectionMethod; use ReflectionParameter; use ReflectionProperty; @@ -73,6 +74,10 @@ private function attributes(Reflector $reflection): array return []; } + if ($reflection instanceof ReflectionFunction) { + return []; + } + throw new InvalidReflectionParameter($reflection); } } diff --git a/src/Definition/FunctionDefinition.php b/src/Definition/FunctionDefinition.php index 0eac3185..2249bef1 100644 --- a/src/Definition/FunctionDefinition.php +++ b/src/Definition/FunctionDefinition.php @@ -13,6 +13,8 @@ final class FunctionDefinition private string $signature; + private Attributes $attributes; + private ?string $fileName; /** @var class-string|null */ @@ -30,6 +32,7 @@ final class FunctionDefinition public function __construct( string $name, string $signature, + Attributes $attributes, ?string $fileName, ?string $class, bool $isStatic, @@ -38,6 +41,7 @@ public function __construct( ) { $this->name = $name; $this->signature = $signature; + $this->attributes = $attributes; $this->fileName = $fileName; $this->class = $class; $this->isStatic = $isStatic; @@ -55,6 +59,11 @@ public function signature(): string return $this->signature; } + public function attributes(): Attributes + { + return $this->attributes; + } + public function fileName(): ?string { return $this->fileName; diff --git a/src/Definition/NativeAttributes.php b/src/Definition/NativeAttributes.php index 2bc5d3c6..8f82a2b3 100644 --- a/src/Definition/NativeAttributes.php +++ b/src/Definition/NativeAttributes.php @@ -4,15 +4,14 @@ namespace CuyZ\Valinor\Definition; -use CuyZ\Valinor\Definition\Exception\InvalidReflectionParameter; use Error; use ReflectionAttribute; use ReflectionClass; +use ReflectionFunction; use ReflectionMethod; use ReflectionParameter; use ReflectionProperty; use Reflector; - use Traversable; use function array_map; @@ -25,6 +24,10 @@ final class NativeAttributes implements Attributes /** @var array> */ private array $reflectionAttributes; + /** + * @PHP8.0 union + * @param ReflectionClass|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflection + */ public function __construct(Reflector $reflection) { $this->reflectionAttributes = $this->attributes($reflection); @@ -80,26 +83,12 @@ public function reflectionAttributes(): array } /** + * @PHP8.0 union + * @param ReflectionClass|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflection * @return array> */ private function attributes(Reflector $reflection): array { - if ($reflection instanceof ReflectionClass) { - return $reflection->getAttributes(); - } - - if ($reflection instanceof ReflectionProperty) { - return $reflection->getAttributes(); - } - - if ($reflection instanceof ReflectionMethod) { - return $reflection->getAttributes(); - } - - if ($reflection instanceof ReflectionParameter) { - return $reflection->getAttributes(); - } - - throw new InvalidReflectionParameter($reflection); + return $reflection->getAttributes(); } } diff --git a/src/Definition/Repository/AttributesRepository.php b/src/Definition/Repository/AttributesRepository.php index f5fc555c..7a1bf6b3 100644 --- a/src/Definition/Repository/AttributesRepository.php +++ b/src/Definition/Repository/AttributesRepository.php @@ -5,10 +5,18 @@ namespace CuyZ\Valinor\Definition\Repository; use CuyZ\Valinor\Definition\Attributes; +use ReflectionClass; +use ReflectionFunction; +use ReflectionMethod; +use ReflectionParameter; +use ReflectionProperty; use Reflector; /** @internal */ interface AttributesRepository { + /** + * @param ReflectionClass|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflector + */ public function for(Reflector $reflector): Attributes; } diff --git a/src/Definition/Repository/Cache/Compiler/FunctionDefinitionCompiler.php b/src/Definition/Repository/Cache/Compiler/FunctionDefinitionCompiler.php index 5a48ecc1..6e4202ac 100644 --- a/src/Definition/Repository/Cache/Compiler/FunctionDefinitionCompiler.php +++ b/src/Definition/Repository/Cache/Compiler/FunctionDefinitionCompiler.php @@ -15,11 +15,15 @@ final class FunctionDefinitionCompiler implements CacheCompiler { private TypeCompiler $typeCompiler; + private AttributesCompiler $attributesCompiler; + private ParameterDefinitionCompiler $parameterCompiler; public function __construct() { $this->typeCompiler = new TypeCompiler(); + $this->attributesCompiler = new AttributesCompiler(); + $this->parameterCompiler = new ParameterDefinitionCompiler($this->typeCompiler, new AttributesCompiler()); } @@ -32,6 +36,7 @@ public function compile($value): string iterator_to_array($value->parameters()) ); + $attributes = $this->attributesCompiler->compile($value->attributes()); $fileName = var_export($value->fileName(), true); $class = var_export($value->class(), true); $isStatic = var_export($value->isStatic(), true); @@ -42,6 +47,7 @@ public function compile($value): string new \CuyZ\Valinor\Definition\FunctionDefinition( '{$value->name()}', '{$value->signature()}', + $attributes, $fileName, $class, $isStatic, diff --git a/src/Definition/Repository/Reflection/ReflectionFunctionDefinitionRepository.php b/src/Definition/Repository/Reflection/ReflectionFunctionDefinitionRepository.php index 20eaba4b..417ffea7 100644 --- a/src/Definition/Repository/Reflection/ReflectionFunctionDefinitionRepository.php +++ b/src/Definition/Repository/Reflection/ReflectionFunctionDefinitionRepository.php @@ -23,9 +23,13 @@ final class ReflectionFunctionDefinitionRepository implements FunctionDefinition private ReflectionParameterDefinitionBuilder $parameterBuilder; + private AttributesRepository $attributesRepository; + public function __construct(TypeParserFactory $typeParserFactory, AttributesRepository $attributesRepository) { $this->typeParserFactory = $typeParserFactory; + $this->attributesRepository = $attributesRepository; + $this->parameterBuilder = new ReflectionParameterDefinitionBuilder($attributesRepository); } @@ -46,6 +50,7 @@ public function for(callable $function): FunctionDefinition return new FunctionDefinition( $reflection->getName(), Reflection::signature($reflection), + $this->attributesRepository->for($reflection), $reflection->getFileName() ?: null, // @PHP 8.0 nullsafe operator $class ? $class->name : null, diff --git a/tests/Fake/Definition/FakeFunctionDefinition.php b/tests/Fake/Definition/FakeFunctionDefinition.php index 32ee1c6a..d0c9346f 100644 --- a/tests/Fake/Definition/FakeFunctionDefinition.php +++ b/tests/Fake/Definition/FakeFunctionDefinition.php @@ -18,6 +18,7 @@ public static function new(string $fileName = null): FunctionDefinition return new FunctionDefinition( 'foo', 'foo:42-1337', + new FakeAttributes(), $fileName ?? 'foo/bar', stdClass::class, true, diff --git a/tests/Functional/Definition/Repository/Cache/Compiler/FunctionDefinitionCompilerTest.php b/tests/Functional/Definition/Repository/Cache/Compiler/FunctionDefinitionCompilerTest.php index dad59cb1..34ded9fd 100644 --- a/tests/Functional/Definition/Repository/Cache/Compiler/FunctionDefinitionCompilerTest.php +++ b/tests/Functional/Definition/Repository/Cache/Compiler/FunctionDefinitionCompilerTest.php @@ -9,6 +9,7 @@ use CuyZ\Valinor\Definition\ParameterDefinition; use CuyZ\Valinor\Definition\Parameters; use CuyZ\Valinor\Definition\Repository\Cache\Compiler\FunctionDefinitionCompiler; +use CuyZ\Valinor\Tests\Fake\Definition\FakeAttributes; use CuyZ\Valinor\Type\Types\NativeStringType; use Error; use PHPUnit\Framework\TestCase; @@ -30,6 +31,7 @@ public function test_function_is_compiled_correctly(): void $function = new FunctionDefinition( 'foo', 'foo:42-1337', + new FakeAttributes(), 'foo/bar', stdClass::class, true, diff --git a/tests/Unit/Definition/NativeAttributesTest.php b/tests/Unit/Definition/NativeAttributesTest.php index 41c462ab..3d27ab25 100644 --- a/tests/Unit/Definition/NativeAttributesTest.php +++ b/tests/Unit/Definition/NativeAttributesTest.php @@ -4,14 +4,13 @@ namespace CuyZ\Valinor\Tests\Unit\Definition; -use CuyZ\Valinor\Definition\Exception\InvalidReflectionParameter; use CuyZ\Valinor\Definition\NativeAttributes; -use CuyZ\Valinor\Tests\Fake\FakeReflector; use CuyZ\Valinor\Tests\Fixture\Attribute\AttributeWithArguments; use CuyZ\Valinor\Tests\Fixture\Attribute\BasicAttribute; use CuyZ\Valinor\Tests\Fixture\Object\ObjectWithAttributes; use PHPUnit\Framework\TestCase; use ReflectionClass; +use ReflectionFunction; use ReflectionMethod; use ReflectionParameter; use ReflectionProperty; @@ -96,11 +95,16 @@ public function test_parameter_attributes_are_fetched_correctly(): void self::assertCount(1, $attributes->ofType(BasicAttribute::class)); } - public function test_throws_on_incompatible_reflection(): void + public function test_function_attributes_are_fetched_correctly(): void { - $this->expectException(InvalidReflectionParameter::class); - $this->expectExceptionCode(1534263918); + $reflection = new ReflectionFunction( + #[BasicAttribute] + fn () => 'foo' + ); + $attributes = new NativeAttributes($reflection); - new NativeAttributes(new FakeReflector()); + self::assertCount(1, $attributes); + self::assertTrue($attributes->has(BasicAttribute::class)); + self::assertCount(1, $attributes->ofType(BasicAttribute::class)); } }