成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

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

longshengwang / 2770人閱讀

摘要:說明在上篇中學(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

相關(guān)文章

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

    摘要:然后中間件使用方法來啟動獲取實例,使用類來管理主要分為兩步獲取實例,主要步驟是通過該實例從存儲介質(zhì)中讀取該次請求所需要的數(shù)據(jù),主要步驟是。 說明:本文主要通過學(xué)習(xí)Laravel的session源碼學(xué)習(xí)Laravel是如何設(shè)計session的,將自己的學(xué)習(xí)心得分享出來,希望對別人有所幫助。Laravel在web middleware中定義了session中間件IlluminateSess...

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

    摘要:實際上,在中關(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...

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

    摘要:總結(jié)本文主要學(xué)習(xí)了啟動時做的七步準備工作環(huán)境檢測配置加載日志配置異常處理注冊注冊啟動。 說明:Laravel在把Request通過管道Pipeline送入中間件Middleware和路由Router之前,還做了程序的啟動Bootstrap工作,本文主要學(xué)習(xí)相關(guān)源碼,看看Laravel啟動程序做了哪些具體工作,并將個人的研究心得分享出來,希望對別人有所幫助。Laravel在入口index...

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

    摘要:說明本文主要學(xué)習(xí)容器的實例化過程,主要包括等四個過程。看下的源碼如果是數(shù)組,抽取別名并且注冊到中,上文已經(jīng)討論實際上就是的。 說明:本文主要學(xué)習(xí)Laravel容器的實例化過程,主要包括Register Base Bindings, Register Base Service Providers , Register Core Container Aliases and Set the ...

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

    摘要:實際上的綁定主要有三種方式且只是一種的,這些已經(jīng)在學(xué)習(xí)筆記之實例化源碼解析聊過,其實現(xiàn)方法并不復(fù)雜。從以上源碼發(fā)現(xiàn)的反射是個很好用的技術(shù),這里給出個,看下能干些啥打印結(jié)果太長了,就不粘貼了。 說明:本文主要學(xué)習(xí)Laravel中Container的源碼,主要學(xué)習(xí)Container的綁定和解析過程,和解析過程中的依賴解決。分享自己的研究心得,希望對別人有所幫助。實際上Container的綁...

    huayeluoliuhen 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<