摘要:說明在上篇中學習了的啟動過程,主要分為兩步,一是的實例化,即的實例化二是從存儲介質中讀取的數據。第二步就是操作,包括對數據的增刪改查操作,本文也主要聊下相關操作源碼。下篇再學習下關閉,到時見。
說明:在上篇中學習了session的啟動過程,主要分為兩步,一是session的實例化,即IlluminateSessionStore的實例化;二是從session存儲介質redis中讀取id = laravel_session*的數據。Laravel5.3把session垃圾回收放在了啟動過程中,盡管Laravel5.1是放在session關閉過程的,本篇聊下垃圾回收,這也是session第一步啟動session的過程。session第二步就是操作session,包括對session數據的CRUD增刪改查操作,本文也主要聊下相關操作源碼。
開發環境:Laravel5.3 + PHP7
Session垃圾回收首先看下session中間件的源碼IlluminateSessionMiddlewareStartSession::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()返回的就是IlluminateSessionCacheBasedSessionHandler實例,該handler就是負責從redis這個存儲介質中CRUD數據,OK,看下該handler的gc()源碼:
public function gc($lifetime) { return true; }
其實什么都沒做。這是當然的,redis對于過期的key會自動清除,所以這里就讓redis來負責垃圾回收過期數據。當然,對于database這種handler,可以看下它的垃圾回收IlluminateSessionDatabaseSessionHandler:
public function gc($lifetime) { $this->getQuery()->where("last_activity", "<=", time() - $lifetime)->delete(); }
以數據庫作為存儲session的介質,垃圾回收就是從sessions表里刪除掉對應字段。
操作Session操作Session就是對從存儲介質如redis中取出的數據進行CRUD增刪改查操作,包括:數據讀取;數據存儲;數據刪除;數據暫存。當然,在對session進行CRUD操作前,首先得獲取session對象即IlluminateSessionStore實例,有三種方法:通過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"); // IlluminateSessionStore public function get($name, $default = null) { return Arr::get($this->attributes, $name, $default); } // "Store"是默認數據,讀取key為"session:store"的數據,并刪除key為"session"的數據 $value = Session::pull("session", "Store"); // IlluminateSessionStore 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提供了IlluminateSupportArr輔助類來操作數組,支持.語法來操作數組,同時還提供了IlluminateSupportStr輔助類來操作字符串。
總之,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,到時見。
歡迎關注Laravel-China。
RightCapital招聘Laravel DevOps
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/21942.html
摘要:然后中間件使用方法來啟動獲取實例,使用類來管理主要分為兩步獲取實例,主要步驟是通過該實例從存儲介質中讀取該次請求所需要的數據,主要步驟是。 說明:本文主要通過學習Laravel的session源碼學習Laravel是如何設計session的,將自己的學習心得分享出來,希望對別人有所幫助。Laravel在web middleware中定義了session中間件IlluminateSess...
摘要:實際上,在中關閉主要包括兩個過程保存當前到介質中在中存入。,學習下關閉的源碼吧先。總之,關閉的第二件事就是給添加。通過對的源碼分析可看出共分為三大步啟動操作關閉。總結本小系列主要學習了的源碼,學習了的三大步。 說明:在中篇中學習了session的CRUD增刪改查操作,本篇主要學習關閉session的相關源碼。實際上,在Laravel5.3中關閉session主要包括兩個過程:保存當前U...
摘要:總結本文主要學習了啟動時做的七步準備工作環境檢測配置加載日志配置異常處理注冊注冊啟動。 說明:Laravel在把Request通過管道Pipeline送入中間件Middleware和路由Router之前,還做了程序的啟動Bootstrap工作,本文主要學習相關源碼,看看Laravel啟動程序做了哪些具體工作,并將個人的研究心得分享出來,希望對別人有所幫助。Laravel在入口index...
摘要:說明本文主要學習容器的實例化過程,主要包括等四個過程。看下的源碼如果是數組,抽取別名并且注冊到中,上文已經討論實際上就是的。 說明:本文主要學習Laravel容器的實例化過程,主要包括Register Base Bindings, Register Base Service Providers , Register Core Container Aliases and Set the ...
摘要:實際上的綁定主要有三種方式且只是一種的,這些已經在學習筆記之實例化源碼解析聊過,其實現方法并不復雜。從以上源碼發現的反射是個很好用的技術,這里給出個,看下能干些啥打印結果太長了,就不粘貼了。 說明:本文主要學習Laravel中Container的源碼,主要學習Container的綁定和解析過程,和解析過程中的依賴解決。分享自己的研究心得,希望對別人有所幫助。實際上Container的綁...
閱讀 2562·2021-11-22 09:34
閱讀 3539·2021-11-15 11:37
閱讀 2341·2021-09-13 10:37
閱讀 2105·2021-09-04 16:40
閱讀 1564·2021-09-02 15:40
閱讀 2456·2019-08-30 13:14
閱讀 3326·2019-08-29 13:42
閱讀 1903·2019-08-29 13:02