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