Attributes

For quite some time, other programming languages already provide means to embed configuration directives for classes and methods, for instance, directly into the declaration of those units of code. This concept is known as annotations in Java or as attributes in C#, for instance.

PHP 7 only offers an unstructured form of such metadata: doc-comments, a special type of comment that begins with /**, ends with */, and which must be placed immediately before the unit of code it seeks to augment. These doc-comments are, of course, just comments. PHP’s compiler does not – and cannot – reason about them. Over the years, frameworks and libraries such as Doctrine, PHPUnit, or Symfony came up with @-based pseudo-languages to structure the information inside a doc-comment.

With the introduction of attributes, PHP 8 provides a way for adding structured, syntactic metadata to the declarations of classes, interfaces, traits, properties, functions, methods, parameters, and constants. This syntactic metadata is processed by PHP’s compiler which allows certain rules to be enforced. Here is a simple example:

namespace example;

use \Attribute;
use \ReflectionClass;

#[Attribute]
final class MyAttribute
{
    private string $value;

    public function __construct(string $value)
    {
        $this->value = $value;
    }

    public function asString(): string
    {
        return $this->value;
    }
}

#[MyAttribute('foo')]
final class MyClass
{
}

$class     = new ReflectionClass(MyClass::class);
$attribute = $class->getAttributes()[0];

var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump(get_class($attribute->newInstance()));
var_dump($attribute->newInstance()->asString());

We first declare an attribute by declaring a class named MyAttribute. The special #[Attribute] attribute on that class tells PHP that we intend to use this class as an attribute.

Next, we declare a class named MyClass and give it the attribute we declared in the previous step. You can think of MyAttribute('foo') as creating an object of the MyAttribute class with foo being passed to its constructor.

The remainder of the example shows how to query information about attributes using the Reflection API. Executing the code shown above with PHP 8 will print the output shown below:

string(19) "example\MyAttribute"
array(1) {
  [0]=>
  string(3) "foo"
}
string(19) "example\MyAttribute"
string(3) "foo"