misc: fetch attributes for function definition

This commit is contained in:
Romain Canon 2022-08-26 11:31:30 +02:00
parent c37ac1e259
commit ec494cec48
9 changed files with 54 additions and 25 deletions

View File

@ -7,6 +7,7 @@ namespace CuyZ\Valinor\Definition;
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 @@ final class DoctrineAnnotations implements Attributes
return [];
}
if ($reflection instanceof ReflectionFunction) {
return [];
}
throw new InvalidReflectionParameter($reflection);
}
}

View File

@ -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 @@ final class FunctionDefinition
) {
$this->name = $name;
$this->signature = $signature;
$this->attributes = $attributes;
$this->fileName = $fileName;
$this->class = $class;
$this->isStatic = $isStatic;
@ -55,6 +59,11 @@ final class FunctionDefinition
return $this->signature;
}
public function attributes(): Attributes
{
return $this->attributes;
}
public function fileName(): ?string
{
return $this->fileName;

View File

@ -4,15 +4,14 @@ declare(strict_types=1);
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<ReflectionAttribute<object>> */
private array $reflectionAttributes;
/**
* @PHP8.0 union
* @param ReflectionClass<object>|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflection
*/
public function __construct(Reflector $reflection)
{
$this->reflectionAttributes = $this->attributes($reflection);
@ -80,26 +83,12 @@ final class NativeAttributes implements Attributes
}
/**
* @PHP8.0 union
* @param ReflectionClass<object>|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflection
* @return array<ReflectionAttribute<object>>
*/
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();
}
}

View File

@ -5,10 +5,18 @@ declare(strict_types=1);
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<object>|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflector
*/
public function for(Reflector $reflector): Attributes;
}

View File

@ -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 @@ final class FunctionDefinitionCompiler implements CacheCompiler
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 @@ final class FunctionDefinitionCompiler implements CacheCompiler
new \CuyZ\Valinor\Definition\FunctionDefinition(
'{$value->name()}',
'{$value->signature()}',
$attributes,
$fileName,
$class,
$isStatic,

View File

@ -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 @@ final class ReflectionFunctionDefinitionRepository implements 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,

View File

@ -18,6 +18,7 @@ final class FakeFunctionDefinition
return new FunctionDefinition(
'foo',
'foo:42-1337',
new FakeAttributes(),
$fileName ?? 'foo/bar',
stdClass::class,
true,

View File

@ -9,6 +9,7 @@ use CuyZ\Valinor\Definition\FunctionDefinition;
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 @@ final class FunctionDefinitionCompilerTest extends TestCase
$function = new FunctionDefinition(
'foo',
'foo:42-1337',
new FakeAttributes(),
'foo/bar',
stdClass::class,
true,

View File

@ -4,14 +4,13 @@ declare(strict_types=1);
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 @@ final class NativeAttributesTest extends TestCase
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));
}
}