How PHP 8 Attributes and Annotations Work
PHP 8 introduced attributes as a native, structured alternative to PHPDoc annotations. This article explains the core concepts of PHP 8 attributes, compares them with legacy docblock annotations, demonstrates how to define and apply them to your code, and shows how to retrieve their metadata using PHP’s native Reflection API.
What Are PHP 8 Attributes?
Attributes, often referred to as annotations in other programming
languages, are a form of structured metadata that you can add to
classes, methods, functions, properties, constants, and parameters.
Before PHP 8, developers relied on unstructured PHPDoc comments (such as
/** @Route("/api", methods={"GET"}) */) parsed at runtime
by external libraries. PHP 8 replaces this workaround with a native,
compiler-verified syntax.
The Syntax of PHP 8 Attributes
The syntax for attributes in PHP 8 uses the #[ and
] delimiters. You place the attribute directly above the
declaration of the code block it describes.
#[MyAttribute]
class MyClass
{
#[MyAttribute('some_value')]
public string $myProperty;
}Attributes can accept arguments, including scalar values, arrays, class constants, and even nested attributes.
How to Create a Custom Attribute
To create an attribute, you define a standard PHP class and apply the
native #[Attribute] attribute to it. This tells the PHP
engine that the class can be used as metadata.
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class RoleRequired
{
public function __construct(public string $role) {}
}In the example above, the
Attribute::TARGET_CLASS | Attribute::TARGET_METHOD flags
restrict where this attribute can be applied. You can limit attributes
to classes, methods, properties, parameters, or allow them globally.
How to Apply the Attribute
Once defined, you can apply your custom attribute to any compatible code element.
#[RoleRequired('admin')]
class AdminDashboardController
{
#[RoleRequired('super_admin')]
public function deleteUser()
{
// Controller logic
}
}How to Read Attributes Using Reflection
Because attributes are native to PHP, they do not require complex comment-parsing libraries. Instead, you read them at runtime using the PHP Reflection API.
The getAttributes() method is available on reflection
objects, such as ReflectionClass,
ReflectionMethod, and ReflectionProperty.
// Reflect the class
$reflection = new ReflectionClass(AdminDashboardController::class);
// Retrieve all 'RoleRequired' attributes on the class
$attributes = $reflection->getAttributes(RoleRequired::class);
foreach ($attributes as $attribute) {
// Instantiate the attribute class to access its properties
$roleRequiredInstance = $attribute->newInstance();
echo $roleRequiredInstance->role; // Outputs: admin
}Calling $attribute->newInstance() triggers the
constructor of your custom attribute class, transforming the raw
metadata into a fully typed PHP object.
Key Benefits of Native Attributes
- Performance: Native attributes are parsed by the PHP engine during compilation, which is significantly faster than parsing docblock strings at runtime.
- Type Safety: Since attributes are standard PHP classes, you benefit from type safety, autocomplete in IDEs, and static analysis validation.
- No Syntax Clutter: Code remains cleaner by separating documentation comments from functional architectural metadata.