Понимание принципов работы сессий в Laravel
Недавно кто-то попросил помочь отладить, почему значение сессии не устанавливается так, как ожидается.
У них был контроллер, устанавливающий значение сессии, если оно пустое, и затем возвращающий это значение. Но когда они добавили несколько отладочных операторов, то обнаружили, что значение всегда пустое, даже если несколько раз обновить страницу.
Предполагалось, что в первый раз он будет пуст, но затем будет присутствовать некое значение при последующих вызовах.
Вот упрощённая версия того, что они пытались сделать:
// внутри контроллера действие значительно упрощено для отображения в одном блоке
if (session()->has('some-key')) {
dump('key exists');
$value = session('some-key');
} else {
dump('key does not exist');
session(['some-key' => 'some-value']);
$value = session('some-key');
}
dd($value);
При каждом обновлении страницы выводилось значение key does not exist
и some-value
. Исходя из этого, можно было понять, что значение сессии не сохраняется, но почему?
Здесь очень полезно знать, как работают сессии в Laravel. Они не используют базовый механизм сессий PHP, а реализуются через Laravel SessionManager
и middleware StartSession
.
Давайте посмотрим на соответствующий метод в этом middleware (я удалил все комментарии, кроме своего, для упрощения)
protected function handleStatefulRequest(Request $request, $session, Closure $next)
{
$request->setLaravelSession(
$this->startSession($request, $session)
);
$this->collectGarbage($session);
$response = $next($request); // <--- Здесь выполняется действие вашего контроллера
$this->storeCurrentUrl($request, $session);
$this->addCookieToResponse($response, $session);
$this->saveSession($request);
return $response;
}
Обратите внимание, что метод saveSession
вызывается только в ответной части middleware, выполняющейся после действия контроллера.
Поэтому, поместив dd()
в действие нашего контроллера, мы убиваем PHP-запрос до того, как это middleware сможет закончить свою работу. Если бы вместо dd
был использован dump
, то все работало бы так, как и ожидалось.
Загадка разгадана!
P.S. dd
иногда бывает полезен, но Xdebug — ещё лучший инструмент отладки.