Что такое PSR
11-09-2019Время чтения ~ 7 мин.PHP 12832
PHP Standards Recommendations — это набор рекомендаций для разработчиков на PHP. Отношение к PSR разное: от полного неприятия, то фанатичной преданности. Сам по себе PSR появился как копирование Java Community Process (ага, опять Java!). Основное назначение PSR в том, чтобы предоставить PHP-разработчикам некие общие концепции, которые уже были проверены и отработаны.
На сегодняшний день существует 20 рекомендаций PSR. Часть из них находится в активном статусе, другие в виде черновиков. Есть «заброшенные» и отмененные рекомендации. В общем «движуха» достаточно активная. Попробуем во всём этом разобраться.
Стандарт или рекомендация?
В названии PHP Standards Recommendations неудачная игра слов — «стандарт» и «рекомендация» (стандартные рекомендации). Под стандартом обычно понимают то, чему следует строго и обязательно следовать. Рекомендация же, наоборот, лишь предлагает, но не обязывает. По своей сути PSR однозначно рекомендация, которая не требует исполнения.
Цель
Группа PHP Framework Interop Group предлагает рекомендации в качестве помощи PHP-разработчикам. То есть смысл в том, чтобы прийти к унификации при решении некоторых задач. Здесь есть некая тонкая грань, когда PSR начинает описывать не просто абстрактную теорию как нужно делать, а предлагает уже конкретный php-код, что во многих случаях может вызывать непонимание или даже неприятие. Но в любом случае PSR однозначно не отвечает за архитектуру приложения, а значит следовать рекомендациям или нет полностью ложится на решение разработчика.
Фундаментальные рекомендации, по сути стандарты
Самое важное, чего добилась группа PHP-FIG — это всё-таки заставила php-программистов следовать единому стилю написание кода. За это отвечают два стандарта:
- PSR-1: Basic Coding Standard
- PSR-12: Extended Coding Style
На самом деле это лишь второстепенный фактор: качество кода никак не связано с его форматированием. Но, когда код предполагается для обозрения, то общепринятый формат упрощает его чтение. По факту же эти рекомендации больше всего востребованы в программах редакторах. Например я привык к стилю форматирования CodeIgniter. Но мне не сложно нажать автоформат в Visual Studio Code и получить полное соответствие PSR-1/12. Более того, если я встречаю чужую библиотеку, которая неряшливо оформлена, то опять же привести код в понятный — это один клик мышью.
Другим фундаментальным стандартном стал PSR-4: Autoloader (старый и отмененный PSR-0). В нём описан алгоритм подключения файлов классов для spl_autoload_register()
. Это очень важная рекомендация, которая не только упростила подход к именованию файлов, но и решила вопрос со структурой каталогов. В конечном итоге это даже сыграло положительную роль и с разделением пространства имён (namespace).
ООП интерфейсы
Остальные рекомендации представляют собой обычные интерфейсы для создания своих классов. Читать такие PSR лучше с конца — исходного кода. Тогда будет понятно реальное назначение. По какой-то причине описание PSR начинается с многословного бла-бла-бла и многие разработчики воспринимают именно эту часть текста как безусловный «стандарт». Происходит подмена понятий, дескать, если не следовать этой рекомендации, то код становится устаревшим и плохим.
На самом же деле, каждая рекомендация направлена на решение определенной задачи. Если фреймворк или CMS решает её своим способом, то это не значит, что он плохой, а означает только то, что ему эта рекомендация просто не нужна.
PSR-3: Logger Interface
Назначение — ведение журнала протоколирования. То есть не просто лог в файл или на экран, а некая система, которая работает не только с текстом сообщения, но и его кодом важности. Этот код описан в документе RFC 5424:
- Emergency: system is unusable
- Alert: action must be taken immediately
- Critical: critical conditions
- Error: error conditions
- Warning: warning conditions
- Notice: normal but significant condition
- Informational: informational messages
- Debug: debug-level messages
То есть когда отправляется какое-то сообщение, то присваивается его код важности (это в самом простом понимании). Что предлагает PSR-3? Элементарную вещь — готовый интерфейс Psr\Log\LoggerInterface с методами:
- alert()
- emergency()
- critical()
- и т.д.
Поскольку интерфейс это тип данных, то все наследники будут совместимы между собой. А это, в свою очередь, позволяет организовать такую структуру классов, чтобы использовать разные реализации логов. Например в одном приложении это будет запись в файл, в другом в базу данных, в третьем сразу на экран. Поскольку интерфейс один, то получается что можно использовать разные классы для реализации разных возможностей. В общем как это я рассказываю в ООП паттернах.
Дальше. Если предположить, что несколько разработчиков логов сделают разные реализации, то они могу быть совместимы между собой, поскольку все реализуют интерфейс Psr\Log\LoggerInterface
. Получается вроде как унификация.
И здесь важный момент. Если в приложении нужен лог (а это очень частая задача), то не значит, что нужно обязательно делать его со всеми методами PSR-3. То есть всегда следует идти от реальной задачи и не создавать лишние связи/классы/файлы там, где этого не требуется.
PSR-6: Caching Interface
PSR-16: Common Interface for Caching Libraries
Интерфейс, который призван привести работу с разными видами кэширование к единым методам. То есть не важно как именно будет реализовано кэширование проекта, например через Memcached или обычные файлы, на «публику» следует отдать единые методы. PSR-6 предлагает их с избытком, видимо рассчитывая на особенности кэширующих библиотек.PSR-7: HTTP message interfaces
Назначение этого стандарта уже вызывает массу вопросов. Цель, вроде как понятна — обеспечить работу с http-протоколом. Ради этого был придуман интерфейс с множеством методов. При этом реализуется еще RequestInterface
и ResponseInterface
. Мне кажется здесь прослеживается очередное желание подражать Java, поскольку PSR-7 предполагает использовать ООП для работы с http. Всё это хорошо, только в PHP с испокон веков принято работать с помощью $_POST, $_GET, $_SERVER и т.п. Это не просто глобальные переменные, а суперглобальные: имеющие не только особую важность, но и значительно упрощающие работу с http (или даже так). PSR-7 предлагает вместо простых строчек кода использовать сложное нагромождение классов.
PSR-11: Container interface
Описывает два метода для контейнера зависимостей. Это ООП-паттерн «Dependency injection» (я его ещё не публиковал). В DI предполагается, что есть некий контейнер, который хранит все зависимости. Скажем есть несколько классов, которые вначале добавляются/регистрируются в этом контейнере, а уже после «вытягиваются» из него по мере необходимости. PSR-11 предлагает, что получение это метод get()
и has()
для проверки существования зависимости.
PSR-11 направлен на разработчиков «модульных» фреймворков, где есть необходимость подключения сторонних (или своих) модулей/библиотек. Вместо обычного инстанцирования класса через new
используется метод контейнера, например add()
, а получение с помощью get()
. Вот пример одной из библиотек.
Тут всё сильно завязано на внутреннюю архитектуру используемого фреймворка — если он сложный, то скорее всего использует свою реализацию, которой следует придерживаться. Для простых же вещей обычного ООП-подхода более чем достаточно.
PSR-13: Link definition interfaces
Смысл этой рекомендации в том, чтобы унифицировать методы работы с ссылками. Предлагается сразу несколько интерфейсов, методы которых должны возвращать разные атрибуты. Я не знаю где это вообще нужно, поскольку небольшой обёртки над стандартной parse_url()
обычно хватает более чем.
PSR-14: Event Dispatcher
По сути это попытка создать ООП-паттерн Observer (Наблюдатель). Я его уже как-то описывал для Java. (Нужно будет, конечно, довыкладывать все остальные php-паттерны...) Назначение PSR-14 в реализации событийной модели в приложении. Я никогда не сталкивался с подобной схемой, возможно это также завязка на какой-то фреймворк, но нюанс в том, что в PHP уже есть стандартные (без кавычек) интерфейсы для реализации полноценного паттерна Observer (SplSubject, SplObjectStorage и SplObserver).
PSR-15: HTTP Server Request Handlers
PSR-17: HTTP Factories
PSR-18: HTTP Client
Эти рекомендации развивают PSR-7. То есть опять же, если приложению как-то активно и своеобразно использует http-методы, то наверное есть смысл воспользоваться этими PSR.
Итоги
Нужны ли рекомендации PSR? На мой взгляд да, нужны. Самые главные стандарты — это стиль кодирования и автозагрузка — это то, что реально востребовано. Остальные рекомендации рассчитаны на специфичные задачи. Наверное правильней и честней было бы прямо указать, дескать это реализовано в таком-то фреймворке, давайте использовать аналогично. Поскольку этого нет, то и нет понимания того, где именно нужно использовать рекомендацию вне конкретного фреймворка.
Тут ещё следует отметить, что PHP-FIG формируют люди, которые имеют свои проекты. В каждом из них свои «велосипеды» и большинство несовместимы между собой. Каждый разработчик считает что его подход лучший, но это не значит, что все должны ему следовать. PHP очень гибкий язык, поэтому может быть множество реализаций одной задачи. Рекомендации PSR это взгляд с какой-то одной стороны и не всегда лучший. Скажем Symfony покинула группу PHP-FIG, а влияние Symfony очень велико: выкиньте из Laravel все Symfony-зависимости и что там останется? А если и все остальные сторонние модули?.. Так что в PHP-FIG всё не так гладко.
Хотя, возможно, настанет момент, когда крупные разработчики смогут предложить свою альтернативу, более конкретную и понятную, чем текущие рекомендации PSR. Ну а пока следовать им или нет, каждый решает сам. :-)