源碼解讀:Laravel php artisan route:cache

學 Laravel 和 Vuejs 你真應該來 codecasts.com !php

Laravel ​route:cache 能夠直接緩存路由文件,這樣其實能夠在必定程度上提升 Laravel 應用的性能,由於緩存路由以後,在訪問應用的時候咱們就不用再次去計算路由的消耗了,能夠直接根據緩存文件來進行匹配處理。laravel

然而,本文的討論重點,仍是 route:cache 背後的源碼,是怎麼作到這一步的。bootstrap

從哪開始看

route:cache 源碼位於 Illuminate\Foundation\Console\RouteCacheCommand緩存

你仍是可使用編輯器搜 RouteCacheCommand,就能夠看到源碼了。
主要的代碼邏輯就在 fire() 方法裏面:app

public function fire()
    {
        $this->call('route:clear');
        //.... other codes
    }

第一步

執行 $this->call('route:clear'),這部分的邏輯是:若是以前有緩存過路由文件,那麼先清除舊的路由緩存,這個部分的代碼位於 Illuminate\Foundation\Console\RouteClearCommand 中,仍是看到 fire() 方法這裏:編輯器

public function fire()
    {
        $this->files->delete($this->laravel->getCachedRoutesPath());

        $this->info('Route cache cleared!');
    }

主要就是執行刪除動做,將以前的緩存路由刪除;這個源碼就在 Illuminate\Foundation\ApplicationgetCachedRoutesPath() 中:性能

public function getCachedRoutesPath()
    {
        return $this->bootstrapPath().'/cache/routes.php';
    }

因此這樣一看,就是刪除了 bootstrap/cache/routes.php 這個文件,那麼這個文件其實就是 Laravel 的路由緩存文件,以後會從新生成這個 routes.php 文件。ui

第二步

獲取全部的路由和其對應關係,在 RouteCacheCommandfire() 方法往下:this

public function fire()
    {
      //... codes
      $routes = $this->getFreshApplicationRoutes();
      //... codes
    }

其中的 getFreshApplicationRoutes() 的代碼是:code

protected function getFreshApplicationRoutes()
    {
        return tap($this->getFreshApplication()['router']->getRoutes(), function ($routes) {
            $routes->refreshNameLookups();
            $routes->refreshActionLookups();
        });
    }

這裏又包含一個新的方法 getFreshApplication() ,這個方法也是位於一樣的文件中:

protected function getFreshApplication()
    {
        return tap(require $this->laravel->bootstrapPath().'/app.php', function ($app) {
            $app->make(ConsoleKernelContract::class)->bootstrap();
        });
    }

這樣一看,總結這兩個方法作的事情就是:

getFreshApplication() 獲取一個 Laravel 的核心實例, 而後上面的 getFreshApplicationRoutes() 中的 $this->getFreshApplication()['router']->getRoutes() 就能夠理解了,也就是至關於 app('router')->getRoutes(),這個 getRoutes() 就是負責獲取全部路由,這部分的源碼位於 Illuminate\Routing\RoutergetRoutes() 中。

第三步

序列化全部路由註冊映射關係,仍是在 RouteCacheCommandfire() 方法中:

public function fire()
{
   foreach ($routes as $route) {
        $route->prepareForSerialization();
    }
}

上面的 prepareForSerialization() 方法位於 Illuminate\Routing\Route 中的 prepareForSerialization() 中。

第四步

序列化完成以後,將內容寫入文件中,這個文件正是一開始刪除的 bootstrap/cache/routes.php,來看代碼 RouteCacheCommandfire() 方法:

$this->files->put(
    $this->laravel->getCachedRoutesPath(), 
    $this->buildRouteCacheFile($routes)
 );

其中的 $this->laravel->getCachedRoutesPath() 在文章一開始就說明了,它是找到了 bootstrap/cache/routes.php 這個文件,而後寫入的內容就是:

protected function buildRouteCacheFile(RouteCollection $routes)
    {
        $stub = $this->files->get(__DIR__.'/stubs/routes.stub');

        return str_replace('{{routes}}', base64_encode(serialize($routes)), $stub);
    }

在這個方法中,看到 base64_encode(serialize($routes)) 這行代碼,因此你會在緩存的 routes.php 中看到相似下面的代碼:

app('router')->setRoutes(
    unserialize(base64_decode('TzozNDoiSWxsdW1pbm...'))
);

一堆 base64 的字符串,這些字符串 base64_decode() 出來大概是這樣的:

這裏就是完整的註冊路由啦!

而後在下次訪問 Laravel 項目的時候,就是能夠直接從緩存的 routes 文件讀取路由了。因此到這裏,route:cache 的源碼解讀就完成了。

Happy Hacking

相關文章
相關標籤/搜索