PHP

Для чего нужны атрибуты в PHP

26 Июня (ред)

Атрибуты вида #[CustomAttribute] добавлены в PHP 8.0 (RFC, Документация)

Атрибуты предоставляют возможность добавлять различную конфигурацию к конкретным классам, методам, константам класса и тд. При этом, пока вы не начнёте обращаться к этой конфигурации, выполнение PHP никак её не воспринимает, как и обычные комментарии. Через рефлексию можно запросить атрибут конкретного класса/метода и убедиться, что такой атрибут ему назначен и также в атрибуте есть необходимые настройки, уникальные для данного класса/метода.

Атрибут может быть назначен не только классу или методу, но и другим структурным сущностям. Это могут быть функции, константы и поля класса, параметры метода. Также можно разрешить дублирование атрибутов.

Например:

<?php
class PostsController
{
    #[\Route(route:"/api/posts/{id}", methods: ["GET"])]
    public function get($id) { /* ... */ }
}

Это пример из документации и он не абстрактный, а прямо указывает, что можно реализовать маршрутизацию приложения на конфигурации. Такой вариант уже давно реализован в Symfony. Что происходит, когда скрипт выполняет этот код? Ничего. Если вы укажете в атрибуте несуществующий класс, ошибки на этом этапе не будет. Однако в маршрутизаторе, при обработке запроса, учитываются эти данные. Так как код разбора запроса может быть различным (по усмотрению программиста), не буду вдаваться в подробности. В целом же - разработчик сам должен создать класс Route в проекте и через рефлексию запросить его экземляр через название класса и метода, к которым прикреплён атрибут (или не прикреплен, это тоже предстоит проверить в коде). Только тогда будет создан уникальный экземпляр класса Route и можно будет проверить, подходит ли этот метод под заданные параметры экземпляра. По сути это обычный комментарий к классу или методу(и не только), но который можно получить не в виде текста, а некоего класса с параметрами.

Для вышеобозначенного кода класс Route может выглядеть так:

<?php
#[Attribute]
readonly class Route {
   public function __construct(
      public string $route;
      public array $methods;
     ){ }
}

Специальный атрибут в классе указывает, что класс является шаблоном атрибута. Его инициализированный экземпляр и будет получен при запросе атрибутов метода get() у класса PostsController. Остаётся сравнить значения в полях $route и $methods с текущим запросом и произвести другие сопутствующие действия.

Насчет удобства маршрутизации через атрибуты... По мне, так удобнее, чтобы вся карта маршрутов хранилась в одном месте, чем была размазана по контроллерам. Но это дело вкуса.

В целом актуальность атрибутов сильно преувеличена. Если бы решаемая проблема была глобальнее, то мы увидели бы её в официальных примерах к атрибутам. Но атрибуты решают узкоспециализированные задачи, вроде маршрутизации, не внося особо важных архитектурных новшеств для программирования на PHP. Поэтому добавление атрибутов не вынужденная мера для развития языка, а внесение в него альтернативных решений частных задач. Например, аналогичный функционал существовал и ранее в Symfony, только выглядел по-другому:

<?php
class PostsController
{
    /**
     * @Route("/api/posts/{id}", methods={"GET"})
     */
    public function get($id) { /* ... */ }
}

Принцип его обработки в целом точно такой-же, логическая интерпретация определялась в коде фреймворка, только разбор был применён для блока phpDoc. Кроме этого, трудно представить, зачем рядовому разработчику создавать новые атрибуты в проекте, если он уже использует фреймворк с маршрутизацией и основными решениями. Создание дополнительной логики в комментариях сделает обычный код не таким наглядным.

Атрибуты PHP поддерживаются многими IDE и анализаторами кода для решения собственных задач, подробнее в статье.

В PHP 8.3 планируется добавить атрибут #[Override], с помощью которого можно будет явно помечать методы, которые переопределяют методы из родительского класса.

1 Ответ

  1. Evg Evg 26 Июня

    Интересно, спасибо.



Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.