Lab 07: PHP Attributes

Time: 40 minutes | Level: Advanced | Docker: docker run -it --rm php:8.3-cli bash

PHP Attributes (also called "annotations" in other languages) provide structured metadata that can be read at runtime via Reflection. They replace DocBlock annotations with a first-class, type-safe syntax.


Step 1: Declaring a Custom Attribute

<?php
// Restrict to class and method targets
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Route {
    public function __construct(
        public readonly string $path,
        public readonly string $method = 'GET'
    ) {}
}

#[Route('/users')]
class UserController {
    #[Route('/users/{id}', 'GET')]
    public function show(int $id): void {}

    #[Route('/users', 'POST')]
    public function create(): void {}

    #[Route('/users/{id}', 'DELETE')]
    public function delete(int $id): void {}
}

// Read via Reflection
$rc = new ReflectionClass(UserController::class);

foreach ($rc->getAttributes(Route::class) as $attr) {
    $r = $attr->newInstance();
    echo "Controller: {$r->method} {$r->path}\n";
}

foreach ($rc->getMethods() as $method) {
    foreach ($method->getAttributes(Route::class) as $attr) {
        $r = $attr->newInstance();
        echo "{$r->method} {$r->path}{$method->getName()}()\n";
    }
}

📸 Verified Output:


Step 2: Attribute Target Flags

📸 Verified Output:


Step 3: Repeatable Attributes

📸 Verified Output:

💡 Add Attribute::IS_REPEATABLE to allow multiple instances of the same attribute on a single target.


Step 4: Built-in PHP Attributes

📸 Verified Output:


Step 5: Validation Attribute Pattern

📸 Verified Output:


Step 6: Event Listener Attribute

📸 Verified Output:


Step 7: Parameter Attributes & Type Checking

📸 Verified Output:


Step 8: Capstone — Mini Router with Attribute-Based Routing

📸 Verified Output:


Summary

Feature
Syntax
PHP Version

Declare attribute

#[Attribute] before class

8.0+

Target restriction

#[Attribute(Attribute::TARGET_CLASS)]

8.0+

Repeatable attribute

Attribute::IS_REPEATABLE flag

8.0+

Read attributes

$rc->getAttributes(MyAttr::class)

8.0+

Instantiate attribute

$attr->newInstance()

8.0+

Built-in: Override

#[\Override] on method

8.3+

Built-in: Deprecated

#[\Deprecated('msg')]

8.4+

Built-in: SensitiveParam

#[\SensitiveParameter]

8.2+

All targets

CLASS, METHOD, PROPERTY, PARAMETER, FUNCTION, CONSTANT

8.0+

Last updated