Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,54 @@ In this case, a class may be marked with either `Screen` or `Audio`, but not bot

In this example, `$displayInfoA->type` will be an instance of `Screen`, `$displayInfoB->type` will be an instance of `Audio`, and `$displayInfoC->type` will be `null`.

### Interface using attributes

Interfaces may also implement attributes. This is useful for cases in which you want to define a type map at the interface level.

Note: in this case, make sure the attribute class implements the `Inheritable` interface, so that implementing classes can inherit it.

```php
use Crell\AttributeUtils\Inheritable;

#[Attribute(Attribute::TARGET_CLASS)]
final class Application implements Inheritable
{
public function __construct(
public readonly string $name,
) {
}
}

#[Application(name: 'app')]
interface Something
{
}

enum MyEnum: string implements Something
{
case A = 'a';
case B = 'b';
}

#[Application(name: 'other-app')]
enum AnotherEnum: string implements Something
{
case A = 'a';
case B = 'b';
}


$analyzer = new Crell\AttributeUtils\Analyzer();

/** @var Application $anotherEnumAttributes */
$enumAttributes = $analyzer->analyze(MyEnum::class, Application::class);
print $enumAttributes->name . PHP_EOL; // Prints 'app'

/** @var Application $classAttributes */
$anotherEnumAttributes = $analyzer->analyze(AnotherEnum::class, Application::class);
print $anotherEnumAttributes->name . PHP_EOL; // Prints 'other-app'
```

## Change log

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
Expand Down
5 changes: 2 additions & 3 deletions src/AttributeParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,7 @@ protected function attributeInheritanceTree(\Reflector $subject, string $attribu
\ReflectionMethod::class => $this->classElementInheritanceTree($subject),
\ReflectionClassConstant::class => $this->classElementInheritanceTree($subject),
\ReflectionParameter::class => $this->parameterInheritanceTree($subject),
// If it's an enum, there's nothing to inherit so just stub that out.
\ReflectionEnum::class => [],
\ReflectionEnum::class => $this->classInheritanceTree($subject),
};
}
}
Expand All @@ -235,7 +234,7 @@ protected function attributeInheritanceTree(\Reflector $subject, string $attribu
*
* This includes both classes and interfaces.
*
* @param \ReflectionClass<object> $subject
* @param \ReflectionClass<object>|\ReflectionEnum<\UnitEnum> $subject
* The reflection of the class for which we want the ancestors.
* @return iterable<\ReflectionClass<object>>
* @throws \ReflectionException
Expand Down
10 changes: 10 additions & 0 deletions tests/ClassAnalyzerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
use Crell\AttributeUtils\Records\ClassWithScopesMulti;
use Crell\AttributeUtils\Records\ClassWithScopesNotDefault;
use Crell\AttributeUtils\Records\ClassWithSubAttributes;
use Crell\AttributeUtils\Records\EnumWithInterface;
use Crell\AttributeUtils\Records\LabeledApp;
use Crell\AttributeUtils\Records\MissingPropertyAttributeArguments;
use Crell\AttributeUtils\Records\MultiuseClass;
Expand Down Expand Up @@ -416,6 +417,15 @@ public static function attributeTestProvider(): \Generator
},
];

yield 'Enum implementing interface' => [
'subject' => EnumWithInterface::class,
'attribute' => BasicClass::class,
'test' => static function(mixed $classDef) {
self::assertEquals(5, $classDef->a);
self::assertEquals(10, $classDef->b);
},
];

yield 'Field takes defaults from class' => [
'subject' => PropertyThatTakesClassDefault::class,
'attribute' => PropertyTakesClassDefaultClass::class,
Expand Down
11 changes: 11 additions & 0 deletions tests/Records/EnumWithInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Crell\AttributeUtils\Records;

enum EnumWithInterface: int implements AnInterface
{
case A = 1;
case B = 2;
}