Життєвий цикл запиту
Життєвий цикл запиту
Що відбувається від моменту, коли браузер постукав на сайт, до моменту, коли віддається HTML.
Крок за кроком
- Вебсервер.
nginxстоїть спереду і віддає статику (css/js/img) напряму. PHP-запити проксуються в Apache/PHP-FPM, який за.htaccessспрямовує все наindex.php(фронт) абоadmin.php(адмінка).
- Точка входу.
index.phpперевіряє наявністьinstall.lock(інакше — редирект на встановлення) і підключаєcore/bootstrap.php.
- Bootstrap + Kernel.
core/bootstrap.phpстворюєKernel, який:- підключає
Autoloader(PSR-4); - будує DI-
Container; - читає
Configз.envіconfig/*.php; - реєструє сервіси:
Connection(БД, лінивий),Engine(шаблони),Router,Logger,Locale,Translator,Auth,Optionsта інші; - запускає сесію (якщо не CLI).
- підключає
- Локаль. Визначається активна мова (
Locale::detect():?lang→ cookie →Accept-Language→ дефолт) і встановлюється вTranslator.
- Маршрути.
bootstrap.phpреєструє публічні та адмінські маршрути. Наприкінці підключаються активні плагіни (PluginManager::load()) — їхніplugin.phpдодають власні маршрути, хуки й теги.
- Диспетчеризація.
Kernel::handle($request)викликаєRouter::dispatch(). Роутер зіставляє шлях із шаблонами маршрутів і знаходить обробник.
- Middleware. Якщо в маршруту є middleware (наприклад
AuthMiddlewareдля/admin/*), запит проходить через них.
- Контролер. Роутер дістає контролер із контейнера (з авто-впровадженням залежностей) і викликає метод
(Request $request, array $params). Контролер повертаєResponse.
- Відповідь.
Kernel::send($response)виставляє статус, заголовки і віддає тіло.
Роутер
Маршрут реєструється так:
$router->get('/news/{slug:[^/]+}', NewsController::class . '@publicShow');
$router->post('/api/leads/submit', LeadsController::class . '@submit');
$router->group(['prefix' => '/admin', 'middleware' => [AuthMiddleware::class]], function (Router $r) {
$r->get('/users', UsersController::class . '@index');
});
{slug}— параметр (типово[^/]+), можна задати власний регулярний вираз:{id:\d+}.- Групи додають спільний префікс і middleware.
- Обробник
Class@methodлінивий: клас створюється через контейнер лише за збігу маршруту.
Контейнер і авто-впровадження
Container створює обʼєкти за рефлексією: дивиться типи аргументів конструктора і підставляє потрібні сервіси. Тому контролер просто оголошує залежності:
final class MyController
{
public function __construct(
private readonly Engine $engine,
private readonly Options $options,
) {}
public function show(Request $request, array $params): Response
{
$this->engine->setTheme((string) $this->options->get('theme', 'default'));
return Response::html($this->engine->render('my-template', ['x' => 1]));
}
}
Реєстрації: bind() — новий екземпляр на кожен запит, singleton() — один на застосунок, instance() — заздалегідь готовий обʼєкт.
Response
Обʼєкт відповіді будується фабриками:
Response::html($html); // text/html
Response::json($data); // application/json
Response::redirect('/url'); // 302
Response::notFound(); // 404
Response::text('ok'); // text/plain
Обробка помилок
У production (APP_ENV=production) трасування назовні не віддається — користувач бачить «500 Server Error», а деталі пишуться в storage/logs. У dev-режимі показується повний трейс. Ця поведінка примусова: навіть за випадково залишеного APP_DEBUG=true на проді трейс не витече.