PSR: стандарты для современного PHP-разработчика
12497

PSR: стандарты для современного PHP-разработчика


До появления PHP Standards Recommendation (PSR) не существовало единых стандартов написания PHP-кода. Например, для стиля кодирования некоторые люди предпочитали стандарт кодирования Zend Framework, некоторые - PEAR Coding Standards, а другие предпочитали создавать свои собственные соглашения об именовании и стиль кодирования.

В 2009 году группа людей, представляющих различные популярные PHP-проекты, собралась вместе и сформировала нечто под названием Framework Interoperability Group (FIG). Цель FIG заключается в том, чтобы представители проектов обсуждали общие черты между своими проектами и находили способы совместной работы.

На данный момент (декабрь 2022 года) принято 14 PSR.

Мы кратко обсудим некоторые из них. Цель этой статьи - познакомить вас с идеями PSR. Для получения более подробной информации о каждом из них, вы всегда можете воспользоваться официальной документацией.

PSR-0 и PSR-4 для автозагрузки, PSR-1 и PSR-12 для стиля написания кода PHP


И PSR-0, и PSR-4 являются стандартами для автозагрузки. Если вы не знакомы с автозагрузкой, то это способ включения классов в PHP без написания беспорядочных операторов include/require.

<?php

use Vendor\Package\ClassName;

$object = new ClassName();

PSR-1 и PSR-12 - это стандарты кодирования PHP. PSR-1 фокусируется на основах, в то время как PSR-12 расширяет PSR-1 и предоставляет более полное руководство по стилю кодирования.

PSR-1 содержит набор простых правил для соглашений об именовании и структуры файлов. Его основная цель - обеспечить высокий уровень технической совместимости между общими PHP-кодами. В проекте, в который включены различные пакеты, может возникнуть неразбериха, если каждый из них использует свой стандарт кодирования, именно для решения этой проблемы и был разработан PRS-1. На данный момент стандарты PSR-0 и PSR-2 имеют статус deprecated.

<?php

namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

PSR-3, PSR-7


После автозагрузки и стандартов кодирования, мы наконец-то можем связать PSR с PHP кодом. Это PSR-3 и PSR-7. PSR-3 содержит интерфейс логирования, а PSR-7 содержит интерфейсы для HTTP сообщений.

PHP отчаянно нуждался в стандарте для интерфейса логгера до появления PSR-3. Логирование - это настолько распространенная задача, что каждый проект создавал свою собственную версию логгера. Без стандарта, единственным способом использовать сторонний логгер было написать обертку вокруг него, чтобы он мог работать с нашими существующими кодовыми базами. Это был не только болезненный процесс, но и неправильный, потому что, в конце концов, все они выполняли одну и ту же работу: ведение логов. Мы должны иметь возможность выбирать нужный логгер по нашему усмотрению.

PSR-3 предоставляет общий интерфейс для библиотек логирования. Пока они реализуют интерфейс PSR-3 logger, они теоретически должны быть взаимозаменяемы с любыми другими библиотеками PSR-3 logger.

HTTP-сообщения необходимы для веб-приложений. Каждое действие пользователя представляет собой комбинацию HTTP-запроса и HTTP-ответа. PSR-7 предоставляет абстракции вокруг HTTP-сообщений и составляющих их элементов. Он окажет огромное влияние на проекты, которые реализуют детали HTTP сообщений, так как HTTP является довольно сложной темой и большинство вендоров имеют свою собственную реализацию, это много рефакторинга для вендоров, чтобы адаптировать PSR-7.

Как пользователь HTTP сообщений, мы теперь можем работать с HTTP сообщениями универсально благодаря PSR-7. Как и PSR-3, PSR-7 значительно облегчает нашу жизнь при создании многократно используемой кодовой базы.

PSR-11: Container interface


Этот документ описывает общий интерфейс для контейнеров инъекции зависимостей (dependency injection).

Целью ContainerInterface является стандартизация того, как фреймворки и библиотеки используют контейнер для получения объектов и параметров (называемых в остальной части этого документа элементами).

Ключевые слова "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" и "OPTIONAL" в этом документе должны интерпретироваться так, как описано в RFC 2119.

Слово "реализатор" в этом документе следует понимать как того, кто имплементирует интерфейс ContainerInterface в библиотеке или фреймворке, связанном с инъекцией зависимостей.

Идентификатор записи - это любая PHP-легальная строка, состоящая как минимум из одного символа, которая однозначно идентифицирует элемент внутри контейнера. Идентификатор записи - это непрозрачная строка, поэтому вызывающие стороны НЕ ДОЛЖНЫ предполагать, что структура строки несет какой-либо семантический смысл.

Чтение из контейнера Psr\Container\ContainerInterface раскрывает два метода: get и has.

get принимает один обязательный параметр: идентификатор записи, который ДОЛЖЕН быть строкой. get может вернуть что угодно (смешанное значение), или выдать NotFoundExceptionInterface, если идентификатор не известен контейнеру. Два последовательных вызова get с одним и тем же идентификатором ДОЛЖНЫ возвращать одно и то же значение. Однако, в зависимости от дизайна исполнителя и/или конфигурации пользователя, могут быть возвращены разные значения, поэтому пользователь НЕ ДОЛЖЕН полагаться на получение одного и того же значения при двух последовательных вызовах.

has принимает один уникальный параметр: идентификатор записи, который ДОЛЖЕН быть строкой. has ДОЛЖЕН возвращать true, если идентификатор записи известен контейнеру, и false, если нет. Если has($id) возвращает false, get($id) ДОЛЖЕН выбросить NotFoundExceptionInterface.

Пользователи НЕ ДОЛЖНЫ передавать контейнер в объект, чтобы объект мог получить свои собственные зависимости. Это означает, что контейнер используется в качестве локатора сервисов, что обычно не рекомендуется.

PSR-14: Event Dispatcher interface


Диспетчеризация событий - это распространенный и хорошо проверенный механизм, позволяющий разработчикам легко и последовательно внедрять логику в приложение.

Целью данного PSR является создание общего механизма для расширения и взаимодействия на основе событий, чтобы библиотеки и компоненты могли более свободно использоваться в различных приложениях и системах.

Ключевые слова "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" и "OPTIONAL" в этом документе должны интерпретироваться так, как описано в RFC 2119.

Цель

Наличие общих интерфейсов для диспетчеризации и обработки событий позволяет разработчикам создавать библиотеки, которые могут взаимодействовать со многими фреймворками и другими библиотеками в едином ключе.

Некоторые примеры:

  • Система безопасности, которая предотвращает сохранение/доступ к данным, если у пользователя нет разрешения.
  • Общая система кэширования всей страницы.
  • Библиотеки, расширяющие другие библиотеки, независимо от того, в какой фреймворк они интегрированы.
  • Пакет протоколирования для отслеживания всех действий, выполняемых в приложении.

Определения

  • Event (Событие) - это сообщение, созданное эмиттером. Это может быть любой произвольный объект PHP.
  • Listener (Слушатель) - это любой вызываемый объект PHP, который ожидает, что ему будет передано событие. Одно и то же событие может быть передано нулю или нескольким слушателям. Слушатель МОЖЕТ по своему усмотрению вызывать другие асинхронные действия.
  • Emitter (Эмиттер)- это любой произвольный код, который хочет отправить событие. Он также известен как "вызывающий код". Он не представлен какой-либо конкретной структурой данных, но относится к случаю использования.
  • Dispatcher (Диспетчер) - это сервисный объект, которому эмиттер передает объект события. Диспетчер отвечает за то, чтобы событие было передано всем соответствующим слушателям, но ДОЛЖЕН отложить определение ответственных слушателей до поставщика слушателей.
  • Listener Provider (Поставщик слушателей) отвечает за определение того, какие слушатели являются релевантными для данного события, но НЕ ДОЛЖЕН сам вызывать слушателей. Поставщик слушателя может указать ноль или более соответствующих слушателей.

События

События - это объекты, которые выступают в качестве единицы связи между эмиттером и соответствующими слушателями.

Объекты событий МОГУТ быть изменяемыми, если в случае использования требуется, чтобы Слушатели предоставляли информацию обратно к Эмиттеру. Однако если такая двунаправленная коммуникация не требуется, то РЕКОМЕНДУЕТСЯ, чтобы событие было определено как неизменяемое; т.е. определено таким образом, что оно не имеет методов мутатора.

Реализаторы ДОЛЖНЫ предполагать, что один и тот же объект будет передаваться всем Слушателям.

РЕКОМЕНДУЕТСЯ, но НЕ ОБЯЗАТЕЛЬНО, чтобы объекты Event поддерживали сериализацию и десериализацию без потерь; $event == unserialize(serialize($event)) ДОЛЖНО быть верным. Объекты МОГУТ использовать интерфейс Serializable PHP, магические методы __sleep() или __wakeup(), или аналогичную функциональность языка, если это уместно.