Сегодня мы рассмотрим StackPHP и попытаемся понять, что это за штука. Хотя этот пост будет содержать некоторый код, эта статья будет довольно теоретической, так как мы заинтересованы в том, чтобы узнать, что такое StackPHP на самом деле, откуда он и почему он полезен.
Как говорится на первой странице проекта StackPHP , Stack — это соглашение для создания промежуточного программного обеспечения HttpKernelInterface . Но для того, чтобы действительно понять это определение, нам нужно сначала охватить несколько понятий. В конце мы также проиллюстрируем концепции, которые мы изучили в контексте StackPHP, с примером кода. Это обычно делает вещи намного проще для понимания.
Что такое HttpKernelInterface?
HttpKernelInterface может быть определен как более чем одно. На самом базовом уровне это интерфейс PHP, который находится внутри компонента Symfony HttpKernel . Но это больше, чем это. Это современный шаблон PHP, который позволяет нам обрабатывать HTTP-запросы объектно-ориентированным способом, а не работать с суперглобальными и выходными функциями, такими как echo
или header
.
Но что это на самом деле означает?
Интерфейс предоставляет единственный метод handle()
который принимает $request
и, как ожидается, вернет $response
. Последние в основном являются объектами-обертками вокруг спецификации HTTP. Например, в Symfony компонент HttpFoundation отвечает за их создание и управление ими. Как вы можете себе представить, объект $request
содержит данные о текущем запросе пользователя, а объект $response
отвечает за вывод результата обработки запроса. Но это уже отступление.
Интерфейс на самом деле не заботится о том, что происходит внутри метода handle()
. Это ответственность класса, который его реализует. Например, ядро Symfony использует компонент Event Dispatcher для управления этим. Он отправляет ряд событий, и слушатели этих событий обрабатывают большую часть тяжелой работы. Это держит вещи абстрактными и отделенными.
Но чтобы вернуться к сути, вы можете рассматривать HttpKernelInterface
как очень простой шаблон OO, который помогает организовать обработку входящего запроса с целью превращения его в ответ.
Что такое шаблон декоратора?
Как и многие другие шаблоны программирования, шаблон декоратора является объектно-ориентированным способом решения конкретной проблемы. В этом случае проблема связана с расширением функциональных возможностей внутри класса без фактического изменения или фактического расширения класса. Решение состоит в том, чтобы скорее украсить его дополнительным необходимым функционалом.
Давайте быстро посмотрим на пример кода, так как это самый простой способ понять, для чего предназначен этот шаблон.
Представьте, что у вас есть этот интерфейс и класс Action
:
interface ActionInterface { public function trigger(); } class Action implements ActionInterface { private function performAction() { return 'Action performed'; } public function trigger() { return $this->performAction(); } }
И вы хотите иметь возможность предоставлять несколько разных версий этого класса, которые содержат дополнительные функции внутри метода trigger()
. Вы можете расширить класс, и в некоторых случаях это правильный подход. Однако это также может создать различные проблемы в будущем, если вам в конечном итоге понадобится что-то вроде множественного наследования (наследование от нескольких классов). PHP 5.4 вводит черты, чтобы помочь с ними.
Что вы также можете сделать, это украсить его другим классом, который реализует тот же интерфейс, добавить к нему свою функциональность и затем делегировать обратно исходному. Вот очень простой пример:
class NotifiedAction implements ActionInterface { private $action; public function __construct(ActionInterface $action) { $this->action = $action; } public function notifyUser() { // Logic for user notification } public function trigger() { $performed = $this->action->trigger(); $this->notifyUser(); return $performed; } }
Как видите, теперь у нас есть класс NotifiedAction
который реализует тот же интерфейс и принимает тот же интерфейс, что и параметр конструктора. Это действует как декоратор вокруг объекта параметра, потому что он оборачивается вокруг него и добавляет к его функциональности извне (в этом случае отправляет уведомление после выполнения действия).
Причина, по которой декоратор должен реализовать тот же интерфейс, состоит в том, чтобы убедиться, что у него тот же открытый API, что и у оформленного. Другими словами, объекты должны быть более или менее взаимозаменяемыми. На самом деле это главный недостаток шаблона декоратора, поскольку обертывание интерфейсов несколькими методами может стать довольно неуклюжим. Но вернемся к нашему примеру.
Теперь у вас есть 2 варианта запуска действий с помощью ActionInterface
:
$action = new Action(); $action->trigger();
И
$action = new NotifiedAction(new Action()); $action->trigger();
И вы можете продолжать создавать декораторы и оборачивать их друг в друга, как русские куклы:
$action = new EmailNotifiedAction(new NotifiedAction(new Action())); $action->trigger();
Это очень простой пример шаблона декоратора. У вас может быть немного более сложная структура, в которой вы делаете некоторые дополнительные абстракции для сокращения стандартного кода. Но этого будет достаточно для наших целей.
Что такое промежуточное ПО StackPHP?
Теперь, когда у нас есть общее представление о том, что такое HttpKernelInterface и шаблон декоратора, пришло время посмотреть, что такое промежуточное ПО StackPHP.
Как я уже упоминал в начале, StackPHP является
соглашение о создании промежуточного программного обеспечения HttpKernelInterface.
Другими словами, StackPHP — это соглашение для создания промежуточного программного обеспечения, которое соблюдает небольшое количество правил, одним из которых является реализация HttpKernelInterface. Но что такое промежуточное ПО в этом контексте?
Промежуточное программное обеспечение можно понимать как часть функциональности, которая добавляется в конвейер, который проходит между пользователем и сервером (между запросом и ответом). Промежуточное программное обеспечение стойки является близким примером определения промежуточного программного обеспечения StackPHP. И поскольку он обеспечивает разумный шаблон для реализации этого конвейера, HttpKernelInterface является отличным выбором для промежуточного программного обеспечения, чтобы обернуть вокруг.
Более конкретно, промежуточное ПО Stack — это простой объект PHP, который следует трем простым правилам:
- Реализует HttpKernelInterface
- Украшает другой объект, который реализует этот интерфейс
- Добавляет функциональность методу
handle()
и делегирует исходный объект
Поэтому важно помнить, что StackPHP не является фреймворком или библиотекой. Он даже не имеет никакого кода как такового (кроме нескольких дополнительных инструментов, которые помогут вам реализовать соглашения).
Скорее, цель проекта StackPHP — продвижение независимого от фреймворка способа создания кода на уровне HTTP. В нем утверждается, что в отличие от кода, специфичного для фреймворка или интегрированного кода, код уровня HTTP может быть встроен в существующие приложения, что также делает его более совместным и универсальным. В настоящее время существует ряд платформ PHP, которые используют компонент Symfony HttpKernel и с которым уже работает стек. Symfony, Silex, Laravel 5 и Drupal 8 — это всего лишь несколько примеров, и есть надежда, что в будущем это число увеличится.
Как выглядит промежуточное ПО стека?
Если мы применим то, что мы узнали в первых двух разделах, мы теперь должны полностью понять, как создать промежуточное программное обеспечение стека. Нам нужно написать класс, который украшает объект HttpKernelInterface и добавить нашу собственную функциональность до или после делегирования украшенному объекту. Итак, давайте создадим мертвое простое промежуточное программное обеспечение Stack, которое оборачивает приложение Symfony и выполняет пользовательское действие, прежде чем фактически вернуть ответ пользователю.
На базовом уровне это фронт-контроллер приложения Symfony:
$kernel = new AppKernel('prod', false); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response);
AppKernel
реализует HTTPKernelInterface и поэтому имеет метод handle()
которому мы передаем объект Request
и от которого мы ожидаем объект Response
. Даже не заботясь о том, что этот метод делает внутри, мы можем украсить его собственным промежуточным программным обеспечением и добавить новые функциональные возможности:
class CustomAppKernel implements HttpKernelInterface { /** * @var \Symfony\Component\HttpKernel\HttpKernelInterface */ private $kernel; public function __construct(HttpKernelInterface $kernel) { $this->kernel = $kernel; } /** * {@inheritdoc} */ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = TRUE) { // Perform whatever task we want before handling the request // Delegate to the decorated kernel to handle the request as it normally would $response = $this->kernel->handle($request, $type, $catch); // Perform some more tasks after the response has been created // Return the Response return $response; } }
В CustomAppKernel
вы можете увидеть шаблон декоратора в работе. Мы обертываем объект HttpKernelInterface, выполняем некоторую логику и затем делегируем декорированному объекту. Теперь наш фронт-контроллер приложения Symfony может выглядеть так:
$kernel = new CustomAppKernel(new AppKernel('prod', false)); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send();
Вот и все. Мы создали промежуточное ПО стека. Если вы хотите увидеть еще несколько примеров, посетите страницу промежуточного программного обеспечения на веб-сайте StackPHP.
Одна вещь, которую вы заметите, это отсутствующий вызов метода terminate()
. Если мы хотим сделать это, наше промежуточное ПО должно также реализовать TerminableInterface
. В качестве альтернативы, мы можем использовать StackBuilder, чтобы помочь нам объединять или устанавливать промежуточное программное обеспечение вместе, и это также обеспечивает поддержку ядер, которые реализуют этот интерфейс.
StackBuilder
StackBuilder — это небольшая библиотека, которая помогает вам построить дерево промежуточного программного обеспечения. По сути, это избавляет от необходимости вручную создавать экземпляры и украшать промежуточное программное обеспечение, предоставляя вместо этого простой мастер API. Итак, как это работает?
Давайте вернемся к нашему примеру выше:
$kernel = new CustomAppKernel(new AppKernel('prod', false)); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send();
С StackBuilder мы можем сделать что-то вроде этого:
$kernel = new AppKernel('prod', false); $stack = (new Stack\Builder()) ->push('CustomAppKernel'); $kernel = $stack->resolve($kernel);
Используя метод push()
объекта StackBuilder
мы можем добавить промежуточное программное обеспечение в стек. В этом примере мы обертываем наш CustomAppKernel
промежуточным программным обеспечением CustomAppKernel
. Это действительно становится полезным, когда у вас есть несколько промежуточных программ, которые вы хотите объединить. Все, что вам нужно сделать, это продолжить цепочку в методе push()
:
$stack = (new Stack\Builder()) ->push('CustomAppKernel') ->push('AnotherAppKernel') ->push('YetAotherAppKernel);
Все они будут оборачивать один за другим оригинальный объект HttpKernelInterface. И метод resolve()
обрабатывает фактическую укладку. Так что теперь, когда вы вызываете метод handle()
для CustomAppKernel
ядра, вы в основном вызываете метод handle()
в CustomAppKernel
который оборачивает AnotherAppKernel
который обертывает YetAnotherAppKernel
который оборачивает исходный AppKernel
.
Кроме того, в стеке ядра, возвращаемом TerminableInterface
resolve()
также реализован TerminableInterface
и поэтому доступен метод terminate()
. Поэтому, если мы вызываем его, он делегирует методу terminate()
каждого промежуточного программного обеспечения в стеке, которое реализует этот интерфейс.
Вывод
В этой статье мы рассмотрели StackPHP и попытались понять, в чем суть. Сначала мы говорили о HttpKernelInterface как о ядре того, что пытаются достичь соглашениями о стеке. Мы также объяснили шаблон декоратора, чтобы лучше понять, как эти соглашения могут выполняться на практике. Затем мы создали небольшое промежуточное программное обеспечение, чтобы увидеть все это в действии. Наконец, мы взглянули на StackBuilder, утилиту, созданную Stack, которая делает процесс объединения промежуточного программного обеспечения быстрым.
Вы создали свое собственное промежуточное ПО StackPHP? Дайте нам знать об этом в комментариях.