Жизненный цикл запроса

Введение

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

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

Жизненный цикл запроса

При помощи .htaccess Апача или правил Nginx или другого веб-сервера, все запросы передаются файлу public/index.php. Отсюда Laravel начинает процесс обработки запроса и здесь же он возвращает ответ пользователю.

Безусловно, наиболее важным понятием при изучении процесса начальной загрузки Laravel является Service Provider (дословно - "поставщик услуг", далее - "сервис-провайдер"). Вы можете найти список сервис-провайдеров в файле config/app.php, в массиве providers. Эти провайдеры - основной механизм настройки (bootstraping) функционала Laravel. Но прежде чем подробно разбираться в их работе, давайте вернемся к public/index.php. После его вызова загружается файл bootstrap/start.php, в котором создается объект Application, который также служит в качестве IoC-контейнера.

После создания объекта Application устанавливаются пути до некоторых важных папок фреймворка и устанавливаются критерии настроек среды. Затем вызывается скрипт настройки фреймворка, который помимо установки таймзоны, уровня error_reporting и т.п. делает очень важную вещь - регистрацию сервис-провайдеров, объявленных в config/app.php.

Простые сервис-провайдеры имеют только один метод: register(). Этот метод вызывается, когда сервис-провайдер регистрируется в объекте Application. В рамка этого метода сервис-провайдеры регистрируют некоторые свои вещи с IoC-контейнером. По сути, каждый сервис-провайдер как поставщик услуг добавляет одну или несколько функций-замыканий в контейнер, который позволит вам получить доступ к этим "услугам" в вашем приложении. Например, QueueServiceProvider регистрирует функции-замыкания, которые ресолвят различные классы, связанные с очередями. Конечно, сервис-провайдеры могут быть использованы для любых действий по настройке фреймворка, не только для регистрации вещей с IoC-контейнером. Сервис-провайдер может регистрировать слушателей событий (event-listeners), составителей вида (view composers), Artisan-команд и т.п.

После того как все сервис-провайдеры зарегистрированы, загружаются файлы из app/start. Затем загружается app/routes.php, и исходя из того, какой роут выбирается для работы, объект Request отправляется в Application.

Суммируя:

  1. Запрос от клиента приходит на public/index.php.
  2. bootstrap/start.php создает объект Application и определяет среду выполнения.
  3. Внутренний файл vendor/laravel/framework/src/Illuminate/Foundation/start.php читает и применяет конфиги и регистрирует сервис-провайдеры.
  4. Загружаются файлы в app/start.
  5. Загружается app/routes.php.
  6. Объект Request отправляется в Application, возвращается объект Response.
  7. Объект Response отправляется клиенту.

Теперь посмотрим повнимательнее на файлы в app/start.

Старт-файлы

Старт-файлы вашего приложения находятся в папке app/start. По умолчанию их там три: artisan.php, global.php и local.php.

О файле artisan.php вы можете узнать в секции Artisan.

Файл global.php, в частности, содержит регистрацию Logger и подсоединение файла фильтров app/filters.php. Вы можете добавить в него что захотите - этот файл вызывается при каждом запросе, независимо от текущей среды выполнения. Файл local.php, как следует из названия, подключается только тогда, когда приложение работает в среде выполнения local. Больше о средах выполнения и их конфигурирования вы можете узнать в соответствующей секции - Сonfiguration.

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

Что размещать в старт-файлах

Старт-файлы - это место для кода, инициализирующего (bootstraping) ваше приложение. Например, вы можете зарегистрировать там view composers, задать настройки логирования, установить некоторые настройки PHP, которые нужны вашему приложению. Конечно, помещать абсолютно весь инициализирующий код в старт-файлы не стоит, так как в этом случае в этом коде легко запутаться. Если вы понимаете, что в старт-файлах у вас помойка, выделяйте часть инициализирующего кода в сервис-провайдеры.

События приложения

Регистрация обработчиков событий

Вы также можете делать пред- или пост-обработку запроса, регистрируя обработчики событий before, after, close, finish и shutdown:

App::before(function()
{
    //
});

App::after(function($request, $response)
{
    //
});

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

Вы также можете зарегистрировать событие, которое вызовется по совпадению роута (маршрута). Событие запускается перед запуском роута.

Route::matched(function($route, $request)
{
    //
});

Событие finish вызывается после того, как ваше приложение отсылает сформированный ответ клиенту. Событие shutdown вызывается немедленно после всех обработчиков события finish и это последняя возможность сделать какие-то действия перед тем как приложение завершится. Скорее всего у вас не будет необходимости использовать эти события.

Приложение 1. Жизненный цикл запроса в деталях

Оригинал: http://laravel-recipes.com/recipes/52

Стандартный жизненный цикл:

Стандартный жизненный цикл состоит из следующих пунктов:

  1. HTTP-запрос через Роуты (Routes) поступает в Контроллер (Controller)
  2. Контроллер осуществляет некоторые действия в зависимости от запроса и передает данные во Отображения (Views)
  3. Отображения отображают полученные данные заданным образом, обеспечивая HTTP-ответ.

Есть много отклонений и различных вариантов вышеприведенной схемы, но она дает нам три опорные точки, на которые надо обратить внимание:

  1. Роуты - app/routes.php
  2. Контроллеры - app/controllers/
  3. Отображения - app/views/

"Отклонения" могут быть, например, такими:

  1. Роуты могут возвращать Отображения или сам Ответ (объект Response), без задействования Контроллеров.
  2. До или после Роутов могут срабатывать Фильтры (app/filters.php)
  3. В процесс могут вмешаться Исключения (Exceptions) или ошибки приложения.
  4. Отклики на события.

Копнем глубже

Более глубокое понимание жизненного цикла запроса в Laravel позволит вам понять, где именно можно (и стоит) писать ваш код.

Цикл запроса можно разбить на три части: Загрузка (Loading), Инициализация (Booting) и Выполнение (Running).

Загрузка (Loading)

Цикл запроса Laravel - загрузка

Вот три основные области, где ваше приложение может повлиять на процесс загрузки фреймворка:

  1. Пакеты Workbench. Workbench - это способ организовывать свой код в обособленные пакеты и тестировать их внутри вашего приложения перед тем как сделать их пакетами, распространяемыми через Composer. См. Workbench

  2. Среда выполнения. В зависимости от установки среды, будут загружены те или иные конфиги, те или иные старт-файлы.

  3. Пути. Редактируя bootstrap/paths.php вы можете изменить файловую структуру фреймворка, расположив файлы в удобных для вас местах.

Инициализация (Booting)

Цикл запроса Laravel - инициализация

Есть 10 областей, гда вы можете влиять на процесс инициализации фреймворка.

  1. Конфиги. Конфиги влияют и на процесс инициализации и на процесс работы фреймворка.

  2. Сервис-провайдеры (Service Providers) Любые сервис-провайдеры, которые вы создали или подсоединили к своему приложению в конфиге config/app.php загружаются в начале процесса инициализации. Если сервис-провайдер не отложенный, вызывается его метод register().

  3. Загрузка и применение старт-файлов. Регистрируются старт-файлы, которые надо загрузить, когда будет вызвано событие booted.

  4. Стэк middleware разворачивается вниз Middleware вложены один в другой как матрешки. Верхний middeware обрабатывает запрос и вызывает middleware следующего уровня, и так далее. Последний middleware вызывает приложение. Все middlewares заносятся в стек, и будут вызваны снова в конце части Выполнения (Running).

  5. Инициализация сервис-провайдеров Вызывается метод boot() у всех зарегистрированных не-отложенных сервис-провайдеров.

  6. Коллбэки пре-инициализации Вызываются все функции-замыкания, зарегистрированные в App::booting()

  7. Коллбэки пост-инициализации Вызываются все функции-замыкания, зарегистрированные в App::booted(). Загружаются старт-файлы, зарегистрированные на шаге 3.

  8. Глобальные старт-файлы. Первым делом это app/start/global.php, затем, если исполняется artisan-команда, то app/start/artisan.php.

  9. Старт-файл среды выполнения. Исполняется файл, который имеет то же имя файла, что и название среды выполнения - `app/start/{environment}.php

  10. Роуты Исполняется app/routes.php. Этот файл вы будете редактировать наиболее часто в процессе разработки вашего приложения.

Выполнение (Running)

Цикл запроса Laravel - выполнение

10 областей, где вы можете влиять на процесс выполнения:

  1. Режим обслуживания Если вы зарегистрировали функцию-подписчика режима обслуживания и приложение находится в этом режиме, эта функция выполняется.

  2. Фильтр before уровня приложения Если у вас есть фильтры, зарегистрированные в App::before(), они выполняются.

  3. Фильтры before в роутах. Если у вас есть фильтры before в роутах, они выполняются.

  4. Исполнение запроса. После разбора, к какому роуту относится запрос, вызывается экшн нужного контроллера или коллбэк роута.

  5. Фильтры after в роутах. Если у вас есть фильтры after в роутах, они выполняются.

  6. Фильтр after уровня приложения Если у вас есть фильтры, зарегистрированные в App::after(), они выполняются.

  7. Стек middleware разворачивается вверх Это точка, где объект Response передается вверх по стеку middlewares. Каждый middleware может изменять этот объект.

  8. Middleware shutdown. Если у вас есть middleware, которые реализуют TerminableInterface, вызывается метод shutdown() этих middleware.

  9. Коллбэки finish Если у вас есть функции, зарегистрированные в App::finish(), они выполняются.

  10. Коллбэки shutdown Если у вас есть функции, зарегистрированные в App::shutdown(), они выполняются.