Installation:
composer require windwalker/attributes ^4.0
Add to composer.json if using a framework like Laravel:
"require": {
"windwalker/attributes": "^4.0"
}
First Use Case:
Define a custom attribute (e.g., #[Route] for API endpoints):
use WindWalker\Attributes\Attribute;
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Route
{
public function __construct(public string $path) {}
}
Resolve attributes in a class/method:
use WindWalker\Attributes\Attributes;
class UserController {
#[Route('/users')]
public function index() {}
}
$reflection = new \ReflectionClass(UserController::class);
$attributes = Attributes::get($reflection->getMethod('index'));
$route = $attributes->get(Route::class); // Returns Route instance with path='/users'
Class/Method/Property Targeting:
Use Attributes::get() with a ReflectionClass, ReflectionMethod, or ReflectionProperty to fetch attributes.
$classAttributes = Attributes::get(new \ReflectionClass(MyClass::class));
$methodAttributes = Attributes::get(new \ReflectionMethod(MyClass::class, 'myMethod'));
Global Attribute Resolution: For Laravel, create a service provider to pre-resolve attributes on boot:
public function boot()
{
$this->app->resolving(MyClass::class, function ($class) {
$attributes = Attributes::get(new \ReflectionClass($class));
// Cache or inject resolved attributes.
});
}
Service Container Binding: Bind resolved attributes to the container for dependency injection:
$this->app->bind(Route::class, function ($app, $parameters) {
$reflection = new \ReflectionMethod(...);
return Attributes::get($reflection)->get(Route::class);
});
Middleware/Filtering:
Use attributes to dynamically apply middleware (e.g., #[Authenticate]):
#[Attribute(Attribute::TARGET_METHOD)]
class Authenticate {}
// In middleware:
if (Attributes::get($reflection)->has(Authenticate::class)) {
return redirect('login');
}
Attribute Aggregation: Combine multiple attributes into a single object for cleaner logic:
$attributes = Attributes::get($reflection);
$meta = new ControllerMeta(
$attributes->get(Route::class),
$attributes->get(Authenticate::class)
);
Fluent Interface: Chain attribute checks for readability:
if (Attributes::get($reflection)
->has(Route::class)
->get(Route::class)->path === '/admin') {
// Admin route logic
}
Reflection Overhead:
static $cachedAttributes = [];
$reflection = new \ReflectionMethod(...);
$cacheKey = $reflection->getName();
return $cachedAttributes[$cacheKey] ?? ($cachedAttributes[$cacheKey] = Attributes::get($reflection));
Attribute Target Mismatch:
TARGET_METHOD for methods). Misconfiguration throws ReflectionException.PHP 8+ Dependency:
Namespace Collisions:
Inspect Attributes:
Use var_dump() or dd() to debug resolved attributes:
dd(Attributes::get($reflection)->all());
Check Reflection: Verify the reflection object is correct:
$method = new \ReflectionMethod(MyClass::class, 'myMethod');
if (!$method->exists()) {
throw new \RuntimeException("Method not found");
}
Attribute Existence:
Use has() before get() to avoid exceptions:
if (Attributes::get($reflection)->has(MyAttribute::class)) {
$attr = Attributes::get($reflection)->get(MyAttribute::class);
}
Custom Attribute Resolvers:
Extend the Attributes class to add custom resolution logic:
class CustomAttributes extends Attributes {
public static function getFromContainer($reflection) {
return self::get($reflection)->filter(fn($attr) => $attr instanceof CustomAttribute);
}
}
Attribute Inheritance: For Laravel, create a trait to auto-resolve parent class attributes:
trait AttributeInheritance {
public function getInheritedAttributes() {
$parent = (new \ReflectionClass($this))->getParentClass();
return $parent ? Attributes::get($parent) : new Attributes();
}
}
Attribute Validation:
Validate attributes at runtime (e.g., ensure Route paths are non-empty):
$route = Attributes::get($reflection)->get(Route::class);
if (empty($route->path)) {
throw new \InvalidArgumentException("Route path cannot be empty");
}
Laravel Service Provider Hooks:
Use register to bind attribute resolvers globally:
public function register() {
$this->app->singleton('attributes', function () {
return new Attributes();
});
}
How can I help you explore Laravel packages today?