Блог


PSR-7, middleware и буриме.

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

И тут вот в чем подвох. В стихах главное не рифма. Есть даже понятие - белые стихи, там вообще рифмы недопустимы. Там главное размер. Бывает дактиль, хорей, амфибрахий, и даже пятистопный ямб. Их довольно много, у всех свои правила. Так вот, если каждый участник будет пытаться внедрить свой размер, толку не получится. Не смотря на рифму.

Научиться кодить может каждый
Кто полон желаний, терпелив и не глуп. // Хорей, первые две строки всегда совместимы
У него если есть к знаниям новым жажда // Дактиль, уже диссонанс, хоть и в рифму.
Хоть и не опытный пока, нуб.
 // Ямб, вообще все разъехалось.

Здесь важно соблюдать правила, заданные первым участником. Некий стандарт. Если привести все к единому стилю, получится вполне сносно:

Научиться кодить может каждый
Кто полон желаний, терпелив и не глуп.
Если есть к новым знаниям жажда,
Не беда, что нет опыта, не беда, что он нуб. // Теперь это хорей. Хоть и кривоват, но звучит куда как лучше.

Так причем тут программирование? А притом, что концепция middlewares очень похожа на буриме. Что такое мидлвары? Middle - средний, промежуточный. Ware - изделие, программное обеспечение. В итоге - промежуточная программа.


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 

// Берем сторонний компонент
    
function calculator($data)
    {
        return 
$data += 2
    }
// Интегрируем в наш фреймворк. Ну или проект, не важно.    
    
function framework()
    {
        
$data calculator(2);
        echo 
$data;
    }
// И все довольны, как слоны.
    
framework();// !!!


 


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

Но заставить всех ходить строем невозможно, особенно в среде программистов, где каждый сам себе гуру. Вот PSR-7, это компромисс между неортогональными программистами. Это не сборник правил, как писать совместимый код. Это иное концептуальное решение. Тут немного подробнее.



Есть  другой подход. Более эфективный. Это как раз вот эти самые мидлвары. Суть их довольно проста: они не принимают отдельные данные, и не возвращают различный результат. Они принимают эстафету, как в буриме, а именно данные, приведенные к единообразию.

Обычно эти данные представлены виде объектов. Получают их из объекта класса Request (запрос), а возвращают объект класса Response (ответ) с результатом внутренних телодвижений мидлвара.


Эти объекты, по своей сути, некие активные хранилища формируемого HTTP сообщения, а не набор разрозненных данных. Они предоставляют публичные методы для получения и сохранения этого сообщения. Его можно в любой момент взять, и отправить куда угодно, хоть следующему мидлвару, хоть в другой обработчик, даже на другой сервер или клиенту. Это открывает возможности многопоточной обработки и асинхронности.

Вот их (Request и Response) и регламентирует PSR-7, устанавливая правила в виде набора интерфейсов для этих и вспомогательных классов. Так же, как устанавливается первоначальный размер стиха в буриме. Тогда, зная размерность и следуя ей, можно совместно писать хорошие стихи.

Сам же мидлвар может делать что угодно и как угодно. Главное он должен уметь получать и возвращать данные по определенным правилам. 

В кодовом представлении это примерно так (очень аскетично, только хранилища, без методов):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php     

// Класс Request, принимает эстафету.  
// Если это не инициатор (как CURL), то очень редко  
// изменяет данные, только получает извне.  
class Request  
{  
  
// Представим себе, что эта двойка получена классом из $_POST     
    
public $data 2;  
}  

// Класс Response (тут будет храниться результат действа  
// мидлвара по формированию ответа браузеру)  
class Response  
{  
    public 
$data;  
}  
      
    
$request  = new Request;   
    
$response = new Response;   
      
// Мидлвар. Принимает аргументами эти два объекта  
// Внутри можно делать что угодно  
    
function calculatorMidllware($request$response)  
    {  
        
$data $request->data;// Получаем данные из Request  
        
$data += 2// Производим наши вычисления  
        
$response->data $data// Складываем результат в Responce  
        
return $response// Возвращаем Responce  
    
}  

    
// Получаем ответ из мидлвара  
    
$response calculatorMidllware($request$response);  
    
// Отправляем в следующий мидлвар (здесь не реализован) 
    
$response someMidllware($request$response);
    
// И так далее
    
    //Отправляем конечный результат в браузер
    
echo $response->data// 4 


 




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

И дело тут как раз в унификации. Нельзя добавлять в классы свои свойства, и нельзя их менять. Если там стоит $data, то уже невозможно получить их из свойства $storage допустим. Потому что его попросту не существует. А если все будут знать, что в Request и Response именно $data, никому и в голову не взбредет поступать как то иначе.


Это довольно интересно и выгодно производителям различных плагинов и компонентов. Сейчас они пишутся под конкретную среду. Под Symfony, 
WordPress, Джумлу наконец. А если все будут юзать один стандарт, то плагины станут универсальными. А значит расширится рынок сбыта.

Это интересно производителям фреймворков, по той же причине, только с другого конца.

Это интересно поставщикам различных услуг для ресурсов. Допустим платежные системы. Сейчас у каждого биллинга свой API. Сейчас его надо настраивать и интегрировать, а с PSR-7 достатчно будет отправить универсальный Request и принять универсальный Rеsponse. Что там происходит за их кадром - никому нет дела.

Еще это удобно при кэшировании, откатах, репликациях и так далее. И много чего еще интересного.


Еще один плюс PSR-7, это то, что он призывает работать напрямую с потоками. Реализация интерфейсов PSR-7 (в частности StreamInterface) предоставляет возможность читать поток и писать в него, без загрузки всего потока в память. Это важно для работы с большими объемами данных, так как в обычной практике для их обработки нужно получить и разобрать весь поток целиком.

Однако есть ложка дегдтя. Этот "стандарт" вряд ли быстро станет популярным. Причина тут в сложности реализации. И хотя есть несколько готовых библиотек, и даже целых фреймворков (Slim, Silex, PHPixie к примеру), внедрять стандарт никто не торопится. Производители софта не спешат переходить на него, потому что к их принятию еще не готовы среды. А производители фреймворков, CMS и других глобальных систем не торопятся, потому что накопленный массив плагинов его пока не поддерживает. Получается замкнутый круг.

Разработчикам продакшена и собственных проектов до этого вообще мало дела, потому что они, как правило, работают с одной выбранной средой. А в каждом фреймворке есть собственная HTTP абстракция. В последних веяниях и собственные мидлвары (тот же набирающий популярность Laravel допустим).


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

Источники:

О HTTP, Middleware и PSR-7 или что не так с текущим подходом

PSR-7 By Example

A Case for Higher Level PHP Streams in PSR-7

Теги: PHP

Комментарии (2)

Fighter
26-11-2017
Спасибо за статтю
freelman
06-12-2017
Отлично обьяснили суть middleware. Однозначно в закладки.

 
Наверх