Flash数据是一种特别的session数据,它一旦在某个请求中设置后, 只会在下次请求中有效,然后该数据就会自动被删除。 常用于实现只需显示给终端用户一次的信息, 如用户提交一个表单后显示确认信息。
在实际应用中,通过
$session = Yii::$app->session;
$session->setFlash("pwd","123456");
来创建一个flash数据。
$session->getFlash("pwd")
当我们获取其值以后,发现,仅仅第一次获取能获取到,第二次获取就变为空了。
那么其原理是什么呢?我们一起来分析一下:
如果直接点开,getFlash()方法:
public function getFlash($key, $defaultValue = null, $delete = false)
{
$counters = $this->get($this->flashParam, []);
if (isset($counters[$key])) {
$value = $this->get($key, $defaultValue);
if ($delete) {
$this->removeFlash($key);
} elseif ($counters[$key] < 0) {
// mark for deletion in the next request
$counters[$key] = 1;
$_SESSION[$this->flashParam] = $counters;
}
return $value;
} else {
return $defaultValue;
}
}
我们会发现,有个默认的$delete参数,但是他是false啊,在if($delete)为假,不会执行removerFlash()啊,可是 为何第二次访问,值就没有了呢,那咱们还得从根源看起。
public function setFlash($key, $value = true, $removeAfterAccess = true)
{
$counters = $this->get($this->flashParam, []);
$counters[$key] = $removeAfterAccess ? -1 : 0;
$_SESSION[$key] = $value;
$_SESSION[$this->flashParam] = $counters;
}
$counters首先执行get方法获取$this->flashParam的值(flashParam在上文有定义)至于为什么要获取他,咱们 下文再说public $flashParam = '__flash';
很明显,$removeAfterAccess默认值为真,所以$counters[$key]的值就为-1,然后将value存入session, 然后将"__flash"存入session,其值为-1,即$counters的值。
然后我们再执行getFlash()方法的时候
public function getFlash($key, $defaultValue = null, $delete = false)
{
$counters = $this->get($this->flashParam, []);//从session中获取$counters的值
if (isset($counters[$key])) {//是否存在
$value = $this->get($key, $defaultValue);//去除session中对应的值
if ($delete) {
$this->removeFlash($key);
} elseif ($counters[$key] < 0) {
// mark for deletion in the next request
$counters[$key] = 1;
$_SESSION[$this->flashParam] = $counters;
}
return $value;
} else {
return $defaultValue;
}
}
发现,还是没有执行removeFlash($key),然后思考,这个$counters[$key]是干啥的呢,为什么一直贯穿,为什么
,小于0的时候要改1呢,在我们使用setFlash()方法的时候,记得,他的值被赋值成了-1,于是我们点开$this->get()方法。
public function get($key, $defaultValue = null)
{
$this->open();
return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
}
发现其执行了一个open方法。
public function open()
{
if ($this->getIsActive()) {
return;
}
$this->registerSessionHandler();
$this->setCookieParamsInternal();
@session_start();
if ($this->getIsActive()) {
Yii::info('Session started', __METHOD__);
$this->updateFlashCounters();//更新flash计数
} else {
$error = error_get_last();
$message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
Yii::error($message, __METHOD__);
}
}
open方法中,有一个updateFlashCounters(),找到其源码
protected function updateFlashCounters()
{
$counters = $this->get($this->flashParam, []);
if (is_array($counters)) {//如果$counters是一个数组
foreach ($counters as $key => $count) {
if ($count > 0) {//经行过getFlash()以后,其值变成了1
unset($counters[$key], $_SESSION[$key]);
} elseif ($count == 0) {
$counters[$key]++;
}
}
$_SESSION[$this->flashParam] = $counters;
} else {
// fix the unexpected problem that flashParam doesn't return an array
unset($_SESSION[$this->flashParam]);
}
}
哎,我们发现,在if($count>0)中,删除了$counters[$kye]和$_SESSION[$key]的值
于是恍然大悟,在第二次getFlash()的之后,由于没有了$counters[$key],所以直接返回了$defaultValue的值,默认为空。
public function getFlash($key, $defaultValue = null, $delete = false)
{
$counters = $this->get($this->flashParam, []);//从session中获取$counters的值
if (isset($counters[$key])) {//是否存在
$value = $this->get($key, $defaultValue);//去除session中对应的值
if ($delete) {
$this->removeFlash($key);
} elseif ($counters[$key] < 0) {
// mark for deletion in the next request
$counters[$key] = 1;
$_SESSION[$this->flashParam] = $counters;
}
return $value;
} else {
return $defaultValue;
}
}