Metadata Attributes and Their Impact on Modern Development with PHP

Doğan Uçar
4 min readMay 22, 2023

--

PHP introduced attributes with version 8.0. Prior PHP8, it was possible to use annotations to use the benefits of attributes.
Attributes are a type of metadata that can be added to classes, methods, properties, and even function parameters. This metadata doesn’t directly affect the behavior of your code, but it can be retrieved at runtime using PHP’s reflection APIs, and then used for any purpose you can think of.

Attributes do not affect source code or source code logic in first place. Instead, frameworks and libraries can make use of it to enhance configuration or work flow.

The Motivation: Why attributes were needed

As stated in the introductory phrase, attributes in PHP are similar to the purpose of annotations which are widely used already. Other languages like Java or C# have these constructs for a long time and go with attributes very well. The primary purpose of attributes is about adding metadata to the code in a structured and type-safe way and make it later confirmable by the code interpreter.

Prior to PHP 8.0, developers commonly used Doc-Blocks (a.k.a. PHPDoc comments) to add metadata. However, from a technical point of view, Doc-Blocks are just comments, so they were used a bit out of their original scope and parsing them can be slow and error-prone.

Attributes are a dedicated and exclusive way for metadata getting used. They add context or simply can be a nice way to describe the code. For example, attributes used to tag test methods in a test class, provide ORM mapping details, define routing rules, specify dependency injection details, etc.

Usage

Declaring an attribute is as easy as:

#[Attribute]
class Color
{
public function __construct(public string $value) {}
}

This declares an attribute class named Color. The #[Attribute] before the class definition tells PHP that this class is meant to be used as an attribute. Notice that attributes start with an hash sign followed with the attribute in square brackets.

Attributes can then be used to annotate classes, methods, properties, or parameters, like so:

#[Color('red')]
class Car {}

The code above adds the color attribute to the Car class. Attribute retrieval can be done by using PHP’s reflection API:

$reflectionClass = new ReflectionClass(Car::class);
$attributes = $reflectionClass->getAttributes();
$myAttribute = $attributes[0]->newInstance();
echo $myAttribute->value; // Outputs: 'red'

Where are Attributes used?

There are several use cases where attributes are reasonable and can be used. Many of the frameworks like Symfony or Laravel have used annotations to structure their code or give developers the ability to control class behaviour. These annotations can get replaced by attributes. Testing frameworks like PHPUnit can start using attributes to mark tests as skipped or as an actual test.

A famous place to use attributes (annotations) are ORMs (like Doctrine or Eloquent) to map classes to database tables and properties to columns or define behaviour. Another prominent example — at least for languages like Java — is dependency injection: just defining a dependency attribute lets the framework now that the actual class depends on another.

Where and How often to use Attributes?

Attributes are a powerful tool to add metadata information to the code not only for humans, but also for the underlying code interpreter. It is already long overdue to have them on board and getting the “old” way using annotations replaced.

However, I think we have to be very careful with them and do not use too much. We must be clear that this is not source code, therefore not part of the logic and should stay as this. For instance, let’s take ORM as an example: ORMs are very complicated and you must have a good understanding of what you do. There are way too much examples of loading the whole table into memory because there was something tiny missing.

Imagine now table or schema interaction depends on metadata. Imagine the maximum amount of data retrieved by a query is defined in an attribute and this is misconfigured — because a junior developer did not know the attribute, a typo or another mistake.

Sure, this could happen with configuration files or similar as well. But this would be a change in source code logic which usually gets more attention than something which is outside of the class or method.

So my rule of thumb: use it as far as it is not part of the logic or code flow.

This blog post was first published on my personal blog. If you like my content then please consider to follow me on Medium :)

--

--

Doğan Uçar

Software Engineer, PHP/Laminas (Zend), Backend, Cloud, Freelancer & CEO, Open Source Contributor