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') {}
}
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";
}
}
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:
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
}
Recommended by LinkedIn
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() {}
}
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
Summary