成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Laravel學(xué)習(xí)筆記之Session源碼解析(中)

longshengwang / 2755人閱讀

摘要:說(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

相關(guān)文章

  • Laravel學(xué)習(xí)筆記Session源碼解析(上)

    摘要:然后中間件使用方法來(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...

    NervosNetwork 評(píng)論0 收藏0
  • Laravel學(xué)習(xí)筆記Session源碼解析(下)

    摘要:實(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...

    Awbeci 評(píng)論0 收藏0
  • Laravel學(xué)習(xí)筆記bootstrap源碼解析

    摘要:總結(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...

    xiaoxiaozi 評(píng)論0 收藏0
  • Laravel學(xué)習(xí)筆記IoC Container實(shí)例化源碼解析

    摘要:說(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 ...

    ningwang 評(píng)論0 收藏0
  • Laravel學(xué)習(xí)筆記Container源碼解析

    摘要:實(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的綁...

    huayeluoliuhen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<