Выпуск №2 — PSR-7

Специальный выпуск, посвящённый PSR-7.

Всем привет!

Вы слушаете «Пятиминутку PHP», выпуск номер 2 — еженедельный подкаст о новостях из мира PHP, интересных постах в блогах и современных подходах к разработке.

Это специальный выпуск, посвящённый PSR-7.

Итак, 18 мая принят стандарт PSR-7 — HTTP Message Interface — набор PHP интерфейсов, описывающих HTTP запрос и HTTP ответ.

Напомню историю вопроса. В старые-добрые времена PHP разработчики использовали суперглобальные переменные $_GET, $_POST, $_SERVER, $_FILES и $_COOKIE для получения информации о пришедшем запросе. А для отправки ответа в браузер использовались такие инструкции как echo и print, для http заголовков встроенная функция header(). При этом все мы помним проблему, что нельзя отправить header уже после того, как сделан вывод в основной поток вывода с помощью print или echo.

Позже стали появляться фреймворки, предоставляющие удобные объектно-ориентированные обёртки над этими суперглобальными переменными — так называемые объекты Request и Response. Объект Request икапсулирует в себе все данные пришедшие от клиента (от браузера пользователя), а объект Response предназначен для наполнения данными отправляемыми в браузер. Более того, современные фреймворки обычно имеют некое ядро приложения, которое на вход принимает объект Request и возвращает Response. Эта абстракция, помимо всего прочего, оказалась очень удобной для написания функциональных тестов: можно сгенерировать много разнообразных объектов Request и потом проверить получившиеся в результате Response, не создавая при этом нагрузки на сеть или каких-либо реальных запросов к веб-серверу.

Аналогичный подход с Request/Response обёртками уже давно используется и в других языках программирования, где он зачастую стандартизирован: Rack для Ruby, WSGI для Python, Java Servlet в Java и стандартный HTTP интерфейс в Node.
В PHP, напротив, чуть ли не каждый фреймворк изобретал свои обёртки и интерфейсы. Самым популярным решением являются компоненты из Symfony, которые используются в микрофреймворке Silex, Laravel, Drupal 8, в системе электронной коммерции Ez, в phpBB и в некоторых других проектах. На сайте Symfony есть отдельная страница со списком пользователей компонента HttpKernel.

В некотором смысле, можно сказать, что в PHP изначально существовал такой же стандартный интерфейс для HTTP запроса – это те самые суперглобальные переменные. Но этот якобы стандарт не очень удобен по ряду причин.

Поэтому, группа энтузиастов PHP-FIG (Framework Interop Group), представленная разработчиками самых популярных фреймворков и CMS-ок, после долгой работы (с 2012 года), представила и приняла новый стандарт PSR-7 — HTTP Message Interface!

В феврале на Хабре была хорошая статья «PSR-7 в примерах». На тот момент стандарт ещё не был утверждён и позже в него были внесены незначительные изменения. Тем не менее рекомендую к прочтению.
На следующий день после принятия, Мэтью (это главный по ZendFramework) описал в своём блоге историю работы над PSR-7, эта статья также есть на Хабре, почитайте.

А я пока расскажу немного деталей в сжатом виде, чтобы уложиться в формат «Пятиминутки PHP».

Итак, набор интерфейсов PSR-7 можно скачать через composer (psr/http-message) или непосредственно с GitHub (https://github.com/php-fig/http-message). Там вы найдёте семь PHP интерфейсов в неймспейсе Psr\Http\Message. Но это только интерфейсы, никакой реализации! Реализацию вам в будущем предоставят фреймворки или вы можете написать свою. Главное — использовать эти интерфейсы, и тогда различные фреймворки смогут быть взаимозаменяемы в вопросах обработки HTTP запросов и ответов.

Одной из особенностей являются так называемые value-objects – неизменяемые объекты. Традиционно в ООП мы имеем объекты, у которых есть методы сеттеры. Сеттеры меняют внутреннее состояние объекта, таким образом эти объекты можно назвать изменяемыми. Но при использовании паттерна value-objects, сеттеры не меняют сам объект, а создают и возвращают его клон, в котором изменено указанное поле. Неизменяемые данные, как общий подход в программировании, с одной стороны кажутся расточительными по памяти и не такими быстрыми, с другой стороны, они смогут снять головную боль от случайных изменений в глубинах кода, ведь объекты передаются по ссылке, и помогают при разработке программ с параллельными вычислениями на разных ядрах процессора или даже на разных процессорах (это больше относится к другим языкам). Если говорить о PHP, который, как мы знаем «создан, чтобы умирать», подход с неизменяемыми данными кажется совсем не очевидным. На эту тему было много дискуссий при разработке стандарта, в итоге пришли к value-objects. Лично я поддерживаю это решение.

Второе, о чём хочется упомянуть, это использование потоков (streams). Тело запроса или ответа может быть большим (мегабайты, и даже гигабайты). Если использовать для тела запроса строковую переменную, то PHP может умереть раньше времени. Поэтому, для представления тела запроса и ответа используются потоки. Если вы не слышали или не использовали потоки в PHP – самое время с ними познакомиться!

Это была теория, перейдём к практике.

  • Одним из первых в реализации этих интерфейсов подсуетился всё тот же Мэтью с компонентом zend-diactoros (часть Zend Framework)
  • Команда Symfony также объявила о начале работ над адаптацией PSR-7
  • Guzzle (самый продвинутый http клиент на PHP) планирует использовать PSR-7 и пилит свой вариант
  • Aura Router версии 3.х (из фреймворка Aura) уже поддерживает PSR-7
  • Помимо этого, Paul M. Jones (разработчик Aura) опубликовал в начале мая экспериментальный фреймворк Radar, который тоже использует PSR-7 (https://github.com/radarphp/Radar.Project). Посмотрите, заодно, на сам фреймворк – в нём есть свежие идеи, в частности Action-Domain-Responder паттерн – изысканный вариант MVC для веба, как написано у него на сайте
  • Когда я искал реализации PSR-7 на GitHub, наткнулся на одну эзотерическую библиотеку icicle – библиотека для написания асинхронного кода, используя синхронные технологии PHP. Корутины и промисы, построенные поверх генераторов (ключевое слово yield в PHP 5.5)
  • Ну а для любителей традиционных ценностей и фей, автор фреймворка PHPixie написал статью на Хабре о современном подходе к HTTP с PHPixie и PSR-7

И это далеко не полный список уже готовых или планируемых реализаций.

Как видим, астрологи объявили неделю PSR-7 и популяция фреймворков с его поддержкой удвоилась!

На сегодня всё, надеюсь выпуск был интересен и познавателен.
Если вы ещё не подписаны на подкаст – сделайте это прямо сейчас!
А затем приступайте к собственной реализации PSR-7. Ведь, как известно, каждый PHP разработчик должен хоть раз написать свой PSR-7 совместимый фреймворк! Собственный фреймворк у вас уже наверняка есть, осталось добавить туда поддержку PSR-7.