Reading — step 1 of 4
Learn
~1 min readReflection and Attributes
PHP 8 added native attributes — metadata you can attach to classes, methods, properties, parameters, then read via reflection.
<?php
#[Attribute(Attribute::TARGET_METHOD)]
class Route {
public function __construct(
public readonly string $path,
public readonly string $method = 'GET',
) {}
}
class UserController {
#[Route(path: '/users', method: 'GET')]
public function list() { ... }
#[Route(path: '/users/{id}', method: 'GET')]
public function show(int $id) { ... }
#[Route(path: '/users', method: 'POST')]
public function create() { ... }
}
Reading attributes:
$rc = new ReflectionClass(UserController::class);
foreach ($rc->getMethods() as $method) {
foreach ($method->getAttributes(Route::class) as $attr) {
$route = $attr->newInstance(); // instantiates the Route
echo "{$route->method} {$route->path} -> {$method->getName()}\n";
}
}
Note: attributes are PHP classes annotated with #[Attribute]. They're inert until you explicitly read them via reflection.
Attribute::TARGET_* flags:
TARGET_CLASS,TARGET_METHOD,TARGET_PROPERTY,TARGET_PARAMETER,TARGET_FUNCTION,TARGET_CLASS_CONSTANT,TARGET_ALL- Combine with
|:Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION Attribute::IS_REPEATABLE— allow multiple of the same attribute
Use cases:
- Routing (Symfony, Laravel route attributes)
- Validation (
#[Required],#[Min(0)],#[Email]) - ORM mapping (
#[Column(type: 'string')],#[Index]) - Authorization (
#[RequiresRole('admin')]) - Test discovery (
#[Test]for PHPUnit-like frameworks)
Before PHP 8, frameworks used doc-comments (/** @Route("/users") */) parsed via libraries like Doctrine Annotations. Native attributes are a big upgrade — language-level support, IDE-autocomplete, type-checked.
Modern PHP framework code (Symfony 6+, Laravel 9+) leans heavily on attributes for declarative APIs.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…