這篇文章的性質偏向個人在研究 config:cache 指令的實作,
其中仍有部份自己不能理解、理解錯誤的部份,如果有前輩發現,還請不吝指教!
與這指令搭配的還有 php artisan config:clear,
兩者搭配用來對 Laravel 專案的設定檔產生快取,增進效能。
下指令時會執行到 \Illuminate\Foundation\Console\ConfigCacheCommand 這個檔案。
那這隻檔案的執行點是 fire() 這個函式,裡面依序做了幾個動作:
var_export() 匯出成一段 PHP 語法$this->files->put 寫入到指定路徑快取檔案產生好之後,具體要研究它如何被 Laravel 載入的話,
需要找到 \Illuminate\Foundation\Bootstrap\LoadConfiguration 這個檔案
在 \Illuminate\Foundation\Bootstrap\LoadConfiguration 檔案中,
定義了一個叫做 bootstrap 的 public 函式,其中便包含我想知道的東西。
底下是該函式的程式碼:
<?php
class LoadConfiguration
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        // 擺放設定的變數
        $items = [];
        // 首先檢查有沒有快取檔案的存在,有則載入;
        // 沒有的話我們就只能一個一個檔案挨著載入了。
        if (file_exists($cached = $app->getCachedConfigPath())) {
            $items = require $cached;
            $loadedFromCache = true;
        }
        // 在 Laravel 核心容器建立一個 "config" 的實例,
        // 它的 class 是一個 \Illuminate\Config\Repository;
        $app->instance('config', $config = new Repository($items));
        // 接著我們需要把所有設定檔案(/config/ 資料夾下的所有檔案) 載入進 Repository,
        // 這樣開發者才能在 Laravel 應用程式中任意調用 config
        if (! isset($loadedFromCache)) {
            $this->loadConfigurationFiles($app, $config);
        }
        // 透過 \Illuminate\Foundation\Application::detectEnvironment
        // 調用 \Illuminate\Foundation\EnvironmentDetector::detect
        // 以決定目前的執行環境為何(預設是 production)
        $app->detectEnvironment(function () use ($config) {
            return $config->get('app.env', 'production');
        });
        // 根據設定檔設定 php 的時區
        date_default_timezone_set($config['app.timezone']);
        // 設定 php multi-byte string 函式的內部編碼
        mb_internal_encoding('UTF-8');
    }
}
設定檔快取的載入流程差不多就是這樣了,
更細部的步驟需要繼續深入 loadConfigurationFiles() 。
<?php
// 透過 foreach 迭代每一筆從 getConfigurationFiles 得到的設定檔
foreach ($this->getConfigurationFiles($app) as $key => $path) {
    // 一個一個 require 出來並放進(set) Repository
    $repository->set($key, require $path);
}
<?php
$files = [];
// 透過 realpath 取得設定檔資料夾(/config)在檔案系統中的絕對路徑
$configPath = realpath($app->configPath());
// 透過 foreach 迭代每一筆(用 Finder)從設定檔資料夾底下找到的所有 .php 檔案
foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
    $nesting = $this->getConfigurationNesting($file, $configPath);
    $files[$nesting.basename($file->getRealPath(), '.php')] = $file->getRealPath();
}
return $files;
<?php
// 取得路徑(不含檔名副檔名)
$directory = dirname($file->getRealPath());
// 先用 str_replace 把路徑中,從根目錄直到 /config/ 的路徑全部拔掉
// 再用 trim($path, '/') 移除路徑頭尾的「/」並得到 $tree
if ($tree = trim(str_replace($configPath, '', $directory), DIRECTORY_SEPARATOR)) {
    // 再把檔案名稱中所有的「/」換成「.」
    $tree = str_replace(DIRECTORY_SEPARATOR, '.', $tree).'.';
}
return $tree;
其實我還是不太懂 getConfigurationNesting() 的用意為何,
而且取出 $tree 之後回頭在 getConfigurationFiles() 之中,
把它與路徑的 basename 串在一起當成 key 的意義在哪?
不過我在猜,
tree 就是我們在使用 config('app.env') 時的「app」(指向 config/app.php)吧?
呀,居然寫到Laravel的章節了,
可是已經有點懶的寫了阿~
