With the introduction of attributes in PHP 8.0, developers gained a powerful way to add metadata to classes, methods, properties, and functions. Attributes replace docblock annotations with structured, native PHP syntax that can be accessed via reflection.

While you can define your own attributes, PHP itself comes with several predefined attributes that are commonly used to improve code quality, handle backward compatibility, or provide hints to the engine.


The Attribute Attribute

The Attribute attribute is the foundation of PHP's attribute system. It is used to declare a class as an attribute class. Without this attribute, your class cannot be used as an attribute.

It also allows specifying where the attribute can be applied using flags:

  • Attribute::TARGET_CLASS
  • Attribute::TARGET_METHOD
  • Attribute::TARGET_PROPERTY
  • Attribute::TARGET_FUNCTION
  • Attribute::TARGET_PARAMETER
  • Attribute::TARGET_ALL
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class Loggable
{
    public function __construct(
        public string $level = 'info'
    ) {}
}

class User
{
    #[Loggable('debug')]
    public function save()
    {
        echo "User saved!";
    }
}

// Reflection to read attributes
$reflection = new ReflectionMethod(User::class, 'save');
$attributes = $reflection->getAttributes();

foreach ($attributes as $attr) {
    $instance = $attr->newInstance();

    echo "Log level: " . $instance->level; // Log level: debug
}

Here, Loggable is declared as a valid attribute that can be attached to methods and functions.


The AllowDynamicProperties Attribute

In PHP 8.2, creating dynamic properties (adding undeclared properties at runtime) was deprecated. However, some legacy code still relies on this behavior.

The AllowDynamicProperties attribute lets you opt-in to dynamic properties on a specific class.

#[AllowDynamicProperties]
class LegacyModel {
    // No properties defined
}

$model = new LegacyModel();
$model->newProperty = "Allowed in PHP 8.2+";
echo $model->newProperty;
// Allowed in PHP 8.2+

Without #[AllowDynamicProperties], the above code would throw a deprecation notice in PHP 8.2.


The Deprecated Attribute

Introduced in PHP 8.2, the Deprecated attribute marks classes, methods, functions, or constants as deprecated. This allows IDEs, static analyzers, and runtime tools to give warnings.

It can also include a custom message and a version since when it was deprecated.

class Math
{
    #[Deprecated("Use add() instead", "8.2")]
    public function sum($a, $b)
    {
        return $a + $b;
    }

    public function add($a, $b)
    {
        return $a + $b;
    }
}

$math = new Math();
echo $math->sum(2, 3);
// Works, but marked as deprecated

When using sum(), tools like PHPStan or IDEs can show a deprecation warning.


The Override Attribute

The Override attribute (added in PHP 8.3) is used when a method must override a parent method. If the method does not actually override anything, PHP will throw an error.

This prevents mistakes such as typos in method names.

class Base
{
    public function greet()
    {
        echo "Hello from Base";
    }
}

class Child extends Base
{
    #[Override]
    public function greet()
    {
        // Correctly overrides parent method
        echo "Hello from Child";
    }

    // #[Override]
    // public function grete() {}
    // ERROR: No method "grete" in parent
}

$child = new Child();
$child->greet();
// Hello from Child

This is very useful in large projects where accidental typos could silently cause bugs.


The ReturnTypeWillChange Attribute

Sometimes, when extending internal PHP classes (like ArrayObject or Iterator), your overridden methods may lack return types that are required in newer PHP versions.

Instead of breaking backward compatibility, you can use #[ReturnTypeWillChange] to suppress warnings.

class MyArray extends ArrayObject
{
    #[ReturnTypeWillChange]
    public function offsetGet($key)
    {
        return parent::offsetGet($key);
    }
}

$myArr = new MyArray(['name' => 'Orkhan']);
echo $myArr['name']; // Orkhan

Without this attribute, PHP would trigger a deprecation warning about missing return types.


The SensitiveParameter Attribute

The SensitiveParameter attribute (PHP 8.2) is used to hide sensitive data (like passwords, tokens, API keys) from stack traces and error messages.

This prevents accidental leakage of secrets in logs.

function login(
    string $username,
    #[SensitiveParameter] string $password
) {
    throw new Exception("Login failed!");
}

try {
    login("admin", "secret123");
} catch (Throwable $e) {
    echo $e;
}

Output (simplified):

Exception: Login failed! in example.php:8
Stack trace:
#0 example.php(12): login('admin', Object(SensitiveParameterValue))

Notice that the actual password is replaced with SensitiveParameterValue.


Source: Orkhan Alishov's notes