← Back to PHP Course | Chapter 14: Advanced PHP | Lesson 17 of 24

PHP Attributes

Attributes are like sticky labels you attach to a class or function to give extra information about it. Other code can read the labels and act on them.
Syntax
php
#[Attribute]
class AttributeName {
    public function __construct(public type $property) {}
}

#[AttributeName(value)]
class ClassName { }

What are Attributes?

Attributes, introduced in PHP 8.0, let you attach structured metadata directly to classes, methods, and properties in native PHP syntax, replacing what used to require parsing PHPDoc comments as plain text.

Example: What are Attributes?

php
<?php
#[Attribute]
// Define the class `Route`
class Route {
    // Define the constructor `__construct` taking `public string $path`
    public function __construct(public string $path) {}
}

#[Route('/home')]
class HomeController {}

// Print "Attributes attach structured metadata directly in PHP syntax" to the output
echo "Attributes attach structured metadata directly in PHP syntax";
?>

Defining custom Attributes

Defining a custom attribute is just defining a normal class and marking it with the built-in #[Attribute] annotation, which tells PHP this class is meant to be used as metadata rather than instantiated directly in the usual way.

Example: Defining custom Attributes

php
<?php
#[Attribute]
// Define the class `Deprecated`
class Deprecated {
    // Define the constructor `__construct` taking `public string $reason`
    public function __construct(public string $reason = '') {}
}
// Print "Deprecated is now usable as an attribute" to the output
echo "Deprecated is now usable as an attribute";
?>

Applying Attributes

Applying an attribute means writing #[YourAttribute] directly above the class, method, or property it describes -- the syntax is compact and lives right alongside the code it annotates.

Example: Applying Attributes

php
<?php
#[Attribute]
// Define the class `Deprecated`
class Deprecated {
    // Define the constructor `__construct` taking `public string $reason`
    public function __construct(public string $reason = '') {}
}

// Define the class `Report`
class Report {
    #[Deprecated('Use generate() instead')]
    // Define the function `oldGenerate` with no parameters
    function oldGenerate() {}
}
// Print "Attribute applied directly above the method" to the output
echo "Attribute applied directly above the method";
?>

Reading Attributes with Reflection

Attributes are inert until read: the Reflection API's getAttributes() method retrieves them at runtime, which is how frameworks use attributes to drive behavior like route registration or validation rules.

Example: Reading Attributes with Reflection

php
<?php
#[Attribute]
// Define the class `Route`
class Route {
    // Define the constructor `__construct` taking `public string $path`
    public function __construct(public string $path) {}
}

#[Route('/home')]
class HomeController {}

// Create a new `ReflectionClass` instance with `HomeController::class`, stored in `$reflection`
$reflection = new ReflectionClass(HomeController::class);
// Declare `$attributes`, set to `$reflection->getAttributes(Route::class)`
$attributes = $reflection->getAttributes(Route::class);
// Print `$attributes[0]->newInstance()->path` to the output
echo $attributes[0]->newInstance()->path;
?>

Attributes vs. PHPDoc

Because attributes are parsed and validated by the PHP engine itself rather than by a separate documentation-comment parser, they're both faster to read and far less prone to silent typos than PHPDoc annotations.

Example: Attributes vs. PHPDoc

php
<?php
// PHPDoc (parsed as a comment, not validated by PHP):
// /** @route /home */

// Attribute (parsed and validated by the engine itself):
#[Attribute]
class Route {
    public function __construct(public string $path) {}
}
echo "Attributes are engine-native, PHPDoc is just a comment convention";
?>
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Expecting an attribute to do something on its own, when it only stores metadata that code must read with Reflection.
  2. Using attributes on PHP older than 8.0, where #[...] is treated as a comment.
  3. Forgetting the #[Attribute] marker on a custom attribute class, so it cannot be used as an attribute.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.