写这篇文章,是因为前段时间在 Laravel 中使用 Session, 突然出现了很诡异的问题,找了好久才发现问题所在,特此记录一下。
HTTP 协议是无状态的协议,两个请求之间是没有任何关联的,为了让服务器保存用户的状态信息,所以引入了 Session 的概念。
在 Laravel 中使用 Session 有两种方式,通过 Request 实例或者通过全局辅助函数,我一般使用全局辅助函数,像下面这样
// 存储数据到 session
session(['user' => 'mrzhouxiaofei']);
// 从 session 获取数据
$value = session('user');
前段时间,在 Laravel 中使用 Session,类似下面这样
public function setSession() {
session(['user' => 'mrzhouxiaofei']);
dd(session('user'));
}
public function getSession() {
dd(session('user'));
}
首先,访问方法 setSession() 存储数据到 session,同时使用全局辅助函数 dd() 将刚存进 session 的值显示出来,这里是没问题的。之后访问 getSession() 将 session 里的值显示出来,这里有问题,刚存进 session 的值并没有显示出来。
之前在 Laravel 中使用 Session 并没有出现这样的问题,我在网上搜了一圈,没找到结果。翻了 Laravel 的文档,找到了下面的一段话。
Laravel 并没有使用 PHP 内置的 Session 功能,而是自己实现了一套更加灵活更加强大的 Session 机制,核心逻辑请参考 Illuminate\Session\Middleware\StartSession 这个中间件,因此在 Laravel 应用中不要试图通过 $_SESSION 方式去获取应用的 Session 值,这是徒劳的。
内容来自:Laravel 学院
Laravel 中的 Session 是自己实现的,没有使用 PHP 原生的那套机制,可是你即使自己实现,一个会话期间,共享 Session 是肯定的啊,还是没有解决问题。
尝试了几次之后,发现方法 setSession 中的 dd() 函数删掉,Session 就正常了。。。
原来是 dd() 函数搞的鬼。知道原因之后,通过关键字 Laravel Session dd() 一下就搜出来好多结果,随便点一个就找到原因了。
Laravel 5.4 session is not being set if dd method is used
有人回复说:dd() 表示 “dump & die”,die() 函数在 dd() 实现中被调用,它会立即结束框架,并且不允许 Laravel 完成请求并保存 Session。如果想这样用,可以使用 dump() 代替 dd()。
// dd() 实现
function dd(...$vars)
{
foreach ($vars as $v) {
VarDumper::dump($v);
}
die(1); // 调用了 die()
}
// dump() 实现
function dump($var, ...$moreVars)
{
VarDumper::dump($var);
foreach ($moreVars as $v) {
VarDumper::dump($v);
}
if (1 < func_num_args()) {
return func_get_args();
}
return $var;
}
原因找到了,Laravel 会首先收集需要写入 Session 的所有数据,并在用户的代码执行后自动调用 session()->save() 方法写入这些数据。这里调用了 dd() 直接终止了整个框架,值根本没有存进去,其它的方法当然取不到了。
所以开始的问题可以像下面这样解决
// 使用 dump() 代替 dd()
public function setSession() {
session(['user' => 'mrzhouxiaofei']);
dump(session('user'));
}
public function getSession() {
dump(session('user'));
}
// 或者在 dd() 之前显示的调用 session()->save()
public function setSession() {
session(['user' => 'mrzhouxiaofei']);
session()->save();
dd(session('user'));
}
public function getSession() {
dd(session('user'));
}
Laravel 中的 Session 是自己实现的,有这个问题,那原生 PHP 的 Session 有这个问题吗?试了一下
// setSession.php
<?php
session_start();
$_SESSION['user'] = 'mrzhouxiaofei';
die();
// getSession.php
<?php
session_start();
echo $_SESSION['user'];
首先访问文件 setSession.php,然后访问 getSession.php,看到值被输出,看来 PHP 的原生 Session 机制并没有这个问题。