PHP Attributes Tutorial
Image created by Grok, an AI developed by xAI.

PHP Attributes Tutorial

PHP attributes (introduced in PHP 8.0) provide a way to add metadata or annotations to classes, methods, properties, and parameters. They use a structured syntax (#[Attribute]) and are simpler than docblocks for certain use cases. This tutorial covers the essentials with minimal details.

1. What Are Attributes?

Attributes are annotations that attach metadata to code elements. They’re defined as classes and applied using #[AttributeName]. They’re useful for frameworks, validation, or custom logic.


2. Defining an Attribute

An attribute is a PHP class marked with the #[Attribute] meta-attribute. It can have constructor parameters for configuration.

#[Attribute]
class Route {
    public function __construct(public string $path, public string $method = 'GET') {}
}
        

  • #[Attribute] marks the class as an attribute.
  • The class can have properties and a constructor to store data.


3. Applying Attributes

Attributes are applied to classes, methods, properties, or parameters using #[AttributeName].

#[Route('/home', 'GET')]
class HomeController {
    #[Route('/user/{id}', 'GET')]
    public function showUser(int $id) {
        return "User $id";
    }
}
        

  • Place #[AttributeName(args)] above the target (class, method, etc.).
  • Multiple attributes can be applied to the same element.


4. Restricting Attribute Targets

You can limit where an attribute can be used with flags in the #[Attribute] declaration.

#[Attribute(Attribute::TARGET_METHOD)]
class MethodOnly {
    public function __construct(public string $value) {}
}
        

Common flags:

  • Attribute::TARGET_CLASS
  • Attribute::TARGET_METHOD
  • Attribute::TARGET_PROPERTY
  • Attribute::TARGET_PARAMETER
  • Combine flags with | (e.g., Attribute::TARGET_CLASS | Attribute::TARGET_METHOD).


5. Reading Attributes with Reflection

Use PHP’s Reflection API to read attributes at runtime.

$reflection = new ReflectionClass(HomeController::class);
$attributes = $reflection->getAttributes(Route::class);

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->path; // Outputs: /home
    echo $instance->method; // Outputs: GET
}
        

  • getAttributes() returns an array of attribute instances.
  • newInstance() creates an instance of the attribute with its constructor arguments.


6. Allowing Multiple Instances

By default, an attribute can only be applied once. To allow multiple instances, use Attribute::IS_REPEATABLE.

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Tag {
    public function __construct(public string $name) {}
}

class BlogController {
    #[Tag('public'), Tag('api')]
    public function index() {}
}
        

  • IS_REPEATABLE lets you apply the same attribute multiple times.


7. Attribute Inheritance

Attributes on parent classes or interfaces are not inherited by default. You can check parent attributes manually with Reflection.

$reflection = new ReflectionClass(ChildClass::class);
while ($reflection) {
    $attributes = $reflection->getAttributes();
    // Process attributes
    $reflection = $reflection->getParentClass();
}
        


8. Practical Example

A simple validation attribute to ensure a property is not empty.

#[Attribute(Attribute::TARGET_PROPERTY)]
class NotEmpty {
    public function validate($value) {
        return !empty($value);
    }
}

class User {
    #[NotEmpty]
    public string $name = '';
}

function validateObject($object) {
    $reflection = new ReflectionClass($object);
    foreach ($reflection->getProperties() as $property) {
        $attributes = $property->getAttributes(NotEmpty::class);
        foreach ($attributes as $attribute) {
            $instance = $attribute->newInstance();
            $value = $property->getValue($object);
            if (!$instance->validate($value)) {
                throw new Exception("Property {$property->getName()} cannot be empty");
            }
        }
    }
}

$user = new User();
validateObject($user); // Throws: Property name cannot be empty
        


9. Built-in PHP Attributes

PHP includes some built-in attributes, like #[Deprecated] or #[SensitiveParameter].

#[Deprecated("Use newMethod() instead")]
function oldMethod() {}
        


10. Best Practices

  • Use attributes for structured metadata, not logic-heavy tasks.
  • Keep attribute classes simple and focused.
  • Use Reflection sparingly for performance.
  • Combine with docblocks for documentation if needed.


Summary

  • Define attributes with #[Attribute] and apply with #[AttributeName].
  • Restrict targets with flags like Attribute::TARGET_METHOD.
  • Read attributes using Reflection.
  • Allow multiple instances with Attribute::IS_REPEATABLE.
  • Use for validation, routing, or metadata in frameworks.

To view or add a comment, sign in

Insights from the community

Others also viewed

Explore topics