摘要:說明在上篇中學(xué)習(xí)了的啟動過程,主要分為兩步,一是的實例化,即的實例化二是從存儲介質(zhì)中讀取的數(shù)據(jù)。第二步就是操作,包括對數(shù)據(jù)的增刪改查操作,本文也主要聊下相關(guān)操作源碼。下篇再學(xué)習(xí)下關(guān)閉,到時見。
說明:在上篇中學(xué)習(xí)了session的啟動過程,主要分為兩步,一是session的實例化,即IlluminateSessionStore的實例化;二是從session存儲介質(zhì)redis中讀取id = laravel_session*的數(shù)據(jù)。Laravel5.3把session垃圾回收放在了啟動過程中,盡管Laravel5.1是放在session關(guān)閉過程的,本篇聊下垃圾回收,這也是session第一步啟動session的過程。session第二步就是操作session,包括對session數(shù)據(jù)的CRUD增刪改查操作,本文也主要聊下相關(guān)操作源碼。
開發(fā)環(huán)境: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次會觸發(fā)過期session的垃圾回收 return random_int(1, $config["lottery"][1]) <= $config["lottery"][0]; }
這里假設(shè)session的存儲介質(zhì)是常用的redis,則$session->getHandler()返回的就是IlluminateSessionCacheBasedSessionHandler實例,該handler就是負責(zé)從redis這個存儲介質(zhì)中CRUD數(shù)據(jù),OK,看下該handler的gc()源碼:
public function gc($lifetime) { return true; }
其實什么都沒做。這是當(dāng)然的,redis對于過期的key會自動清除,所以這里就讓redis來負責(zé)垃圾回收過期數(shù)據(jù)。當(dāng)然,對于database這種handler,可以看下它的垃圾回收IlluminateSessionDatabaseSessionHandler:
public function gc($lifetime) { $this->getQuery()->where("last_activity", "<=", time() - $lifetime)->delete(); }
以數(shù)據(jù)庫作為存儲session的介質(zhì),垃圾回收就是從sessions表里刪除掉對應(yīng)字段。
操作Session操作Session就是對從存儲介質(zhì)如redis中取出的數(shù)據(jù)進行CRUD增刪改查操作,包括:數(shù)據(jù)讀取;數(shù)據(jù)存儲;數(shù)據(jù)刪除;數(shù)據(jù)暫存。當(dāng)然,在對session進行CRUD操作前,首先得獲取session對象即IlluminateSessionStore實例,有三種方法:通過Request實例;通過Session Facade方法;通過helper函數(shù)session(),代碼如下:
// 因為在中間件StartSesstion前置操作中有把session實例存入到$request中,$request->setSession($session); $session = $request->session(); // 通過Session Facade直接獲取到$session對象,并進行CRUD操作 Session::put("session", "Store"); // 通過helper函數(shù)來獲取session實例,實際上是通過app("session")從Container中解析出名為"session"的服務(wù)即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數(shù)據(jù)讀取
session數(shù)據(jù)讀取方法包括:
// "Store"是默認數(shù)據(jù),讀取key為"session:store"的數(shù)據(jù) $value = Session::get("session.store", "Store"); // IlluminateSessionStore public function get($name, $default = null) { return Arr::get($this->attributes, $name, $default); } // "Store"是默認數(shù)據(jù),讀取key為"session:store"的數(shù)據(jù),并刪除key為"session"的數(shù)據(jù) $value = Session::pull("session", "Store"); // IlluminateSessionStore public function pull($key, $default = null) { return Arr::pull($this->attributes, $key, $default); } // 返回所有數(shù)據(jù) $value = Session:all(); public function all() { return $this->attributes; }
在Session啟動過程中,就包含了把session數(shù)據(jù)從存儲介質(zhì)如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類的一些數(shù)組操作函數(shù)從Store的$attributes屬性中讀取session數(shù)據(jù)。Laravel提供了IlluminateSupportArr輔助類來操作數(shù)組,支持.語法來操作數(shù)組,同時還提供了IlluminateSupportStr輔助類來操作字符串。
總之,Laravel提供了三種方法來讀取session數(shù)據(jù):
Session::get(); Session::pull(); Session::all();session數(shù)據(jù)存儲
session數(shù)據(jù)存儲方法包括:
// "更新式存儲",即如果redis中有"session.store"數(shù)據(jù),就使用"Store"來update舊數(shù)據(jù) 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"數(shù)據(jù),就使用"Store"和舊數(shù)據(jù)如"StoreOld"作為新數(shù)組數(shù)據(jù) // 這時"session.store"新數(shù)據(jù)是["StoreOld", "Store"]; Session::push("session.store", "Store"); public function push($key, $value) { $array = $this->get($key, []); $array[] = $value; $this->put($key, $array); }
總之,Laravel提供了兩種方法來存儲數(shù)據(jù):
Session::put("session.store", "Store"); Session::push("session.store", "StoreNew");session數(shù)據(jù)刪除
session數(shù)據(jù)刪除方法包括:
// 刪除key為"session.store"的數(shù)據(jù) Session::forget("session.store"); public function forget($keys) { Arr::forget($this->attributes, $keys); } // 清空所有數(shù)據(jù),$attributes為空 Session::flush(); public function flush() { $this->clear(); } public function clear() { $this->attributes = []; foreach ($this->bags as $bag) { $bag->clear(); } }
總之,Laravel提供了兩種方法來刪除數(shù)據(jù):
Session::forget("session.store"); Session::flush();session數(shù)據(jù)暫存
數(shù)據(jù)暫存是把session中的數(shù)據(jù)保留到下一次請求中,下一次請求結(jié)束后則刪除數(shù)據(jù),數(shù)據(jù)暫存方法包括:
// 把"session.store"數(shù)據(jù)刷到"_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"數(shù)組中不包含"session.store"的結(jié)果存儲到"_flash.old"中 // 即刪除"session.store"這個value值 $this->put("_flash.old", array_diff($this->get("_flash.old", []), $keys)); } // 把所有本次需要刪除的數(shù)據(jù)全部刷到"_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); }
總之,就是把本次請求要刪除的數(shù)據(jù)放在"_flash.old",留到下一次請求中使用的就把它刷到"_flash.new"中。Laravel提供了三種方法來暫存數(shù)據(jù):
Session::flash(); Session::reflash(); Session::keep();
總結(jié):本文主要學(xué)習(xí)下Laravel的session的垃圾回收和CRUD增刪改查操作。下篇再學(xué)習(xí)下關(guān)閉session,到時見。
歡迎關(guān)注Laravel-China。
RightCapital招聘Laravel DevOps
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/21942.html
摘要:然后中間件使用方法來啟動獲取實例,使用類來管理主要分為兩步獲取實例,主要步驟是通過該實例從存儲介質(zhì)中讀取該次請求所需要的數(shù)據(jù),主要步驟是。 說明:本文主要通過學(xué)習(xí)Laravel的session源碼學(xué)習(xí)Laravel是如何設(shè)計session的,將自己的學(xué)習(xí)心得分享出來,希望對別人有所幫助。Laravel在web middleware中定義了session中間件IlluminateSess...
摘要:實際上,在中關(guān)閉主要包括兩個過程保存當(dāng)前到介質(zhì)中在中存入。,學(xué)習(xí)下關(guān)閉的源碼吧先??傊?,關(guān)閉的第二件事就是給添加。通過對的源碼分析可看出共分為三大步啟動操作關(guān)閉。總結(jié)本小系列主要學(xué)習(xí)了的源碼,學(xué)習(xí)了的三大步。 說明:在中篇中學(xué)習(xí)了session的CRUD增刪改查操作,本篇主要學(xué)習(xí)關(guān)閉session的相關(guān)源碼。實際上,在Laravel5.3中關(guān)閉session主要包括兩個過程:保存當(dāng)前U...
摘要:總結(jié)本文主要學(xué)習(xí)了啟動時做的七步準備工作環(huán)境檢測配置加載日志配置異常處理注冊注冊啟動。 說明:Laravel在把Request通過管道Pipeline送入中間件Middleware和路由Router之前,還做了程序的啟動Bootstrap工作,本文主要學(xué)習(xí)相關(guān)源碼,看看Laravel啟動程序做了哪些具體工作,并將個人的研究心得分享出來,希望對別人有所幫助。Laravel在入口index...
摘要:說明本文主要學(xué)習(xí)容器的實例化過程,主要包括等四個過程。看下的源碼如果是數(shù)組,抽取別名并且注冊到中,上文已經(jīng)討論實際上就是的。 說明:本文主要學(xué)習(xí)Laravel容器的實例化過程,主要包括Register Base Bindings, Register Base Service Providers , Register Core Container Aliases and Set the ...
摘要:實際上的綁定主要有三種方式且只是一種的,這些已經(jīng)在學(xué)習(xí)筆記之實例化源碼解析聊過,其實現(xiàn)方法并不復(fù)雜。從以上源碼發(fā)現(xiàn)的反射是個很好用的技術(shù),這里給出個,看下能干些啥打印結(jié)果太長了,就不粘貼了。 說明:本文主要學(xué)習(xí)Laravel中Container的源碼,主要學(xué)習(xí)Container的綁定和解析過程,和解析過程中的依賴解決。分享自己的研究心得,希望對別人有所幫助。實際上Container的綁...
閱讀 2626·2021-11-22 09:34
閱讀 3603·2021-11-15 11:37
閱讀 2424·2021-09-13 10:37
閱讀 2181·2021-09-04 16:40
閱讀 1789·2021-09-02 15:40
閱讀 2517·2019-08-30 13:14
閱讀 3393·2019-08-29 13:42
閱讀 2006·2019-08-29 13:02