Как устроен жизненный цикл запроса в Symfony
Что проверяют
Понимаете ли вы, что Symfony построен вокруг HttpKernel и событий, а не вокруг цепочки middleware, и можете ли показать, куда встроить свою логику. Следом обычно спрашивают, на каком событии работает безопасность и чем kernel.terminate отличается от kernel.response.
Как отвечать
Проведите запрос по шагам:
- вход: веб-сервер отдаёт запрос в
public/index.php, компонент Runtime создаёт ядро, контейнер берётся из скомпилированного кэша, из суперглобальных переменных собираетсяRequest; kernel.request:RouterListenerнаходит маршрут и кладёт_controllerи параметры в$request->attributes. На этом же событии, чуть позже роутера, работает файрвол Security. Слушатель может сразу вернутьResponse, и контроллер уже не вызовется;kernel.controller: контроллер определён, его можно подменить или прочитать атрибуты метода;kernel.controller_arguments: резолверы подставляют аргументы:Request, сущности, сервисы,#[MapRequestPayload];- вызов контроллера: если он вернул не
Response, срабатываетkernel.view, где результат превращают в ответ; kernel.response: последний шанс поменять ответ, добавить заголовки и куки;kernel.terminate: после$response->send(). Под PHP-FPM клиент уже получил ответ, поэтому сюда выносят медленное, например отправку писем;kernel.exception: на необработанную ошибку, отсюда рендерится страница ошибки.
Реальный порядок слушателей в своём проекте покажет bin/console debug:event-dispatcher kernel.request.
Где спотыкаются
Рассказывают про middleware, как в Laravel. В Symfony эту роль играют подписчики на события ядра, так и надо говорить.
Путают kernel.response и kernel.terminate: во втором ответ изменить уже нельзя, он ушёл клиенту.
Не знают про долгоживущие рантаймы. В воркер-режиме FrankenPHP или под RoadRunner ядро живёт между запросами, и сервис, который копит состояние, протекает в следующий запрос, если не реализует ResetInterface.