Laravel學習筆記之Session源碼解析(中)

說明:在上篇中學習了session的啓動過程,主要分爲兩步,一是session的實例化,即\Illuminate\Session\Store的實例化;二是從session存儲介質redis中讀取id = laravel_session*的數據。Laravel5.3把session垃圾回收放在了啓動過程當中,儘管Laravel5.1是放在session關閉過程的,本篇聊下垃圾回收,這也是session第一步啓動session的過程。session第二步就是操做session,包括對session數據的CRUD增刪改查操做,本文也主要聊下相關操做源碼。php

開發環境:Laravel5.3 + PHP7laravel

Session垃圾回收

首先看下session中間件的源碼\Illuminate\Session\Middleware\StartSession::classredis

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

操做Session就是對從存儲介質如redis中取出的數據進行CRUD增刪改查操做,包括:數據讀取;數據存儲;數據刪除;數據暫存。固然,在對session進行CRUD操做前,首先得獲取session對象即\Illuminate\Session\Store實例,有三種方法:經過Request實例;經過Session Facade方法;經過helper函數session(),代碼以下:app

// 由於在中間件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數據讀取方法包括:dom

// '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,到時見。

相關文章
相關標籤/搜索