PHP 8 Video Tutorial: Attributes


In this video I invite you to discover one of the new features of PHP 8: Attributes.

Annotations but native

The concept of attributes is not new and if you work with doctrine or symfony you have probably already encountered it in another form: annotations.

/ **
* @Route ("/ demo")
** /
function demo () {
    return 'Hello everyone!';
}

The principle is to add metadata to a method, a property, a function or a class. The problem was that until now there was no native way to handle things and we had to use a third party library. PHP 8 therefore introduces a new syntax and new terminology Attribute (not to be confused with annotations).

# (Route ("/ demo"))
function demo () {
    return 'Hello everyone!';
}

The syntax is different but the principle is the same.

Create an attribute

To create an attribute, just create a class which itself will have the attribute Attribute. This attribute can receive as a parameter the type of content that can receive the attribute.

path;
    }

    public function getMethod (): string
    {
        return $ this-> method;
    }


}

You can then use your attribute wherever you want

# (Route ('/ api'))
class HelloController
{

    # (Route ('/ hello / {name}'))
    public function hello (string $ name) {
        return <<< HTML
        Hello {$ name}
        
HTML; } # (Route ('/ goodbye / {name}', method: 'post')) public function goodbye (Response $ response, string $ name) { $ response-> getBody () -> write ("Goodbye, $ name"); return $ response; } }

Finally, you will be able to read the attributes using the PHP reflection API thanks to the method getAttributes ().

$ class = new ReflectionClass (HelloController :: class);
$ routeAttributes = $ class-> getAttributes ( App  Attribute  Route :: class);

You would then get an array of ReflectionAttribute containing the name of your attributes as well as the arguments to pass to it. We will especially note the possibility of recovering an instance of our attribute using the method newInstance ().

$ class = new ReflectionClass (HelloController :: class);
$ routeAttributes = $ class-> getAttributes ( App  Attribute  Route :: class);
if (! empty ($ routeAttributes)) {
    // Here we have our Route instance built with the right arguments
    $ route = $ routeAttributes (0) -> newInstance ();
}

From there it's up to you to imagine the possible uses.

Some avenues of use

Now that we have seen the principle, we can ask ourselves the question of the use cases of such a feature. Also here are some avenues that can be explored.

EventListener

For an event listener, annotations can be used to define which event responds to a specific method

class CommentEventListener {

    # (SubscribeTo (CommentCreatedEvent :: class))
    public function onCreated (CommentCreatedEvent $ event) {

    }

    # (
        SubscribeTo (CommentDeletedEvent :: class),
        SubscribeTo (CommentBlacklisted :: class)
    )
    public function onDelete (CommentCreatedEvent $ event) {

    }

}

A control system

It can be used to automatically record orders

class ServerCommand {

    # (Command ("app: run", arguments: ('port', 'host')))
    public function build (IO $ io, array $ args) {

    }

}

Data validation

class Post {

    # (
        Validation  Unique,
        Validation  Email,
    )
    private string $ email;

    # (
        Validation  NotBlank,
        Validation  Length (min: 5, max: 12),
    )
    private string $ username;

}

Connection with the database

class Post {

    # (ORM  Column (name: 'email', type: 'VARCHAR', length: 255))
    private string $ email;

}