博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Laravel学习笔记之Session源码解析(中)
阅读量:6240 次
发布时间:2019-06-22

本文共 6270 字,大约阅读时间需要 20 分钟。

说明:在上篇中学习了session的启动过程,主要分为两步,一是session的实例化,即\Illuminate\Session\Store的实例化;二是从session存储介质redis中读取id = laravel_session*的数据。Laravel5.3把session垃圾回收放在了启动过程中,尽管Laravel5.1是放在session关闭过程的,本篇聊下垃圾回收,这也是session第一步启动session的过程。session第二步就是操作session,包括对session数据的CRUD增删改查操作,本文也主要聊下相关操作源码。

开发环境:Laravel5.3 + PHP7

Session垃圾回收

首先看下session中间件的源码\Illuminate\Session\Middleware\StartSession::class

public function handle($request, Closure $next) { $this->sessionHandled = true; if ($this->sessionConfigured()) { $session = $this->startSession($request); // 把session对象存储到Request中 // 所以可以在控制器Controller中使用Request实例获取session对象:$request->session() $request->setSession($session); $this->collectGarbage($session); } ... } protected function collectGarbage(SessionInterface $session) { // 读取config/session.php中的配置 $config = $this->manager->getSessionConfig(); if ($this->configHitsLottery($config)) { // CacheBasedSessionHandler::gc(60) 60 minutes $session->getHandler()->gc($this->getSessionLifetimeInSeconds()); } } protected function configHitsLottery(array $config) { // session.php中'lottery'默认配置是[2, 100],这里就是取概率2/100 = 2% // 也就是100次请求有2次会触发过期session的垃圾回收 return random_int(1, $config['lottery'][1]) <= $config['lottery'][0]; }

这里假设session的存储介质是常用的redis,则$session->getHandler()返回的就是\Illuminate\Session\CacheBasedSessionHandler实例,该handler就是负责从redis这个存储介质中CRUD数据,OK,看下该handler的gc()源码:

public function gc($lifetime) { return true; }

其实什么都没做。这是当然的,redis对于过期的key会自动清除,所以这里就让redis来负责垃圾回收过期数据。当然,对于database这种handler,可以看下它的垃圾回收\Illuminate\Session\DatabaseSessionHandler:

public function gc($lifetime)    {        $this->getQuery()->where('last_activity', '<=', time() - $lifetime)->delete(); }

以数据库作为存储session的介质,垃圾回收就是从sessions表里删除掉对应字段。

操作Session

操作Session就是对从存储介质如redis中取出的数据进行CRUD增删改查操作,包括:数据读取;数据存储;数据删除;数据暂存。当然,在对session进行CRUD操作前,首先得获取session对象即\Illuminate\Session\Store实例,有三种方法:通过Request实例;通过Session Facade方法;通过helper函数session(),代码如下:

// 因为在中间件StartSesstion前置操作中有把session实例存入到$request中,$request->setSession($session);    $session = $request->session();     // 通过Session Facade直接获取到$session对象,并进行CRUD操作    Session::put('session', 'Store'); // 通过helper函数来获取session实例,实际上是通过app('session')从Container中解析出名为'session'的服务即Store实例 $session = session()->driver(); function session($key = null, $default = null) { if (is_null($key)) { return app('session'); } if (is_array($key)) { return app('session')->put($key); } return app('session')->get($key, $default); }

session数据读取

session数据读取方法包括:

// 'Store'是默认数据,读取key为'session:store'的数据    $value = Session::get('session.store', 'Store');     // Illuminate\Session\Store public function get($name, $default = null) { return Arr::get($this->attributes, $name, $default); } // 'Store'是默认数据,读取key为'session:store'的数据,并删除key为'session'的数据 $value = Session::pull('session', 'Store'); // Illuminate\Session\Store public function pull($key, $default = null) { return Arr::pull($this->attributes, $key, $default); } // 返回所有数据 $value = Session:all(); public function all() { return $this->attributes; }

在Session启动过程中,就包含了把session数据从存储介质如redis中取出来,并存放在Store的$attributes属性中,可看Store::loadSession()源代码:

protected function loadSession() { $this->attributes = array_merge($this->attributes, $this->readFromHandler()); foreach (array_merge($this->bags, [$this->metaBag]) as $bag) { $this->initializeLocalBag($bag); $bag->initialize($this->bagData[$bag->getStorageKey()]); } }

所以,使用Arr类的一些数组操作函数从Store的$attributes属性中读取session数据。Laravel提供了\Illuminate\Support\Arr辅助类来操作数组,支持.语法来操作数组,同时还提供了\Illuminate\Support\Str辅助类来操作字符串。

总之,Laravel提供了三种方法来读取session数据:

Session::get();Session::pull();Session::all();

session数据存储

session数据存储方法包括:

// '更新式存储',即如果redis中有'session.store'数据,就使用'Store'来update旧数据    Session::put('session.store', 'Store');    public function put($key, $value = null) { if (! is_array($key)) { $key = [$key => $value]; } foreach ($key as $arrayKey => $arrayValue) { $this->set($arrayKey, $arrayValue); } } // '压入式存储',即如果redis中有'session.store'数据,就使用'Store'和旧数据如'StoreOld'作为新数组数据 // 这时'session.store'新数据是['StoreOld', 'Store']; Session::push('session.store', 'Store'); public function push($key, $value) { $array = $this->get($key, []); $array[] = $value; $this->put($key, $array); }

总之,Laravel提供了两种方法来存储数据:

Session::put('session.store', 'Store');Session::push('session.store', 'StoreNew');

session数据删除

session数据删除方法包括:

// 删除key为'session.store'的数据    Session::forget('session.store');    public function forget($keys) { Arr::forget($this->attributes, $keys); } // 清空所有数据,$attributes为空 Session::flush(); public function flush() { $this->clear(); } public function clear() { $this->attributes = []; foreach ($this->bags as $bag) { $bag->clear(); } }

总之,Laravel提供了两种方法来删除数据:

Session::forget('session.store');Session::flush();

session数据暂存

数据暂存是把session中的数据保留到下一次请求中,下一次请求结束后则删除数据,数据暂存方法包括:

// 把'session.store'数据刷到'_flash.new',等待下一次请求使用,然后再删除    Session::flash('session.store', 'Store');    public function flash($key, $value) { // 更新式存储'session.store' => 'Store' $this->put($key, $value); // 压入式存储'_flash.new' => ['session.store', XXX] $this->push('_flash.new', $key); // 删除'session.store'这个value值 $this->removeFromOldFlashData([$key]); } protected function removeFromOldFlashData(array $keys) { // 把'_flash.old'数组中不包含'session.store'的结果存储到'_flash.old'中 // 即删除'session.store'这个value值 $this->put('_flash.old', array_diff($this->get('_flash.old', []), $keys)); } // 把所有本次需要删除的数据全部刷到'_flash.new'中,等待下一次请求使用,然后再删除 Session::reflash(); public function reflash() { $this->mergeNewFlashes($this->get('_flash.old', [])); $this->put('_flash.old', []); } protected function mergeNewFlashes(array $keys) { // 把'_flash.old'中的value值合并到'_flash.new'中 $values = array_unique(array_merge($this->get('_flash.new', []), $keys)); $this->put('_flash.new', $values); } // 把要删除的'session.store'重新激活,刷到'_flash.new'中,等待下一次使用 Session::keep(['session.store' => 'Store']); public function keep($keys = null) { $keys = is_array($keys) ? $keys : func_get_args(); // 把'session.store'刷到'_flash.new'中 $this->mergeNewFlashes($keys); // 同时,把'session.store'从'_flash.old'中删除 $this->removeFromOldFlashData($keys); }

总之,就是把本次请求要删除的数据放在'_flash.old',留到下一次请求中使用的就把它刷到'_flash.new'中。Laravel提供了三种方法来暂存数据:

Session::flash();Session::reflash();Session::keep();

总结:本文主要学习下Laravel的session的垃圾回收和CRUD增删改查操作。下篇再学习下关闭session,到时见。

转载地址:http://mudia.baihongyu.com/

你可能感兴趣的文章
memcpy内存重叠的解决
查看>>
保存和恢复activity的状态数据[转]
查看>>
JS中call、apply的用法说明
查看>>
C#中对于Enum类型的遍历
查看>>
使用tomcat启动dubbo项目
查看>>
crontab + shell脚本实现文件重命名
查看>>
谈谈-ConstraintLayout完全解析
查看>>
fluent-ffmpeg 常用函数
查看>>
Robot Framework(十五) 扩展RobotFramework框架——远程库接口
查看>>
Eclipse中没有javax.servlet和javax.servlet.http包的处理办法
查看>>
汽车加工厂
查看>>
localStorage 和 sessionStorage 的用法
查看>>
day23-python操作数据库三
查看>>
第二次冲刺——第3天
查看>>
SpringMVC+Hibernate+Junit4+json基本框架近乎0配置
查看>>
Pro Android学习笔记(一三七):Home Screen Widgets(3):配置Activity
查看>>
Hadoop学习笔记(九)HDFS架构分析
查看>>
DB2数据库常用基本操作命令
查看>>
RHEL5.8安装Sybase 15.7_x86_64
查看>>
函数适配器bind2nd 、mem_fun_ref 源码分析、函数适配器应用举例
查看>>