深入理解 Laravel 中 config 配置載入原理

李志成發表於2018-10-21

Laravel的配置載入其實就是載入config目錄下所有檔案配置。如何過使用php artisan config:cache則會把載入的配置合併到一個配置檔案中,下次請求就不會再去載入config目錄。

1.載入流程

  1. LoadEnvironmentVariables .env環境配置載入。如果快取配置是不會載入.env
  2. LoadConfiguration 判斷是否快取配置
  3. 是,則直接載入配置,不會載入config目錄所有檔案了
  4. 否,則載入config目錄所有PHP檔案

2.什麼時候載入配置?

核心啟動的時候。載入以下啟動類

\Illuminate\Foundation\Http\Kernel

protected $bootstrappers = [
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,  // 載入 .env
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, // 載入config配置
        ...
    ];

本文重點講解第二個config配置載入。第一個請檢視 深入理解 Laravel 中.env 檔案讀取
.

3. 原始碼分析

LoadConfiguration類中config配置載入的具體邏輯。

其實就是判斷快取是否存在,存在則載入,不存在則遞迴遍歷config目錄所有php檔案。如果執行php artisan config:cache,則會把載入結果儲存在bootstrap/cache目錄中;你可能還會看到services.php檔案,這是一個儲存所有的服務提供者的檔案,具體以後會講。

public function bootstrap(Application $app)
    {
        $items = [];

       // 首先,我們將看看是否有快取配置檔案。 如果是,我們將從該檔案載入配置項,因此它非常快。 
       // 否則,我們需要遍歷每個配置檔案並載入它們。
        if (file_exists($cached = $app->getCachedConfigPath())) {
            // 載入快取的配置檔案
            $items = require $cached;

            $loadedFromCache = true;
        }

        // 接下來,我們將遍歷配置目錄中的所有配置檔案,並將每個配置檔案載入到Repository中。
        // 這將使開發人員可以使用所有選項,以便在此應用程式的各個部分中使用。
        $app->instance('config', $config = new Repository($items));

        // 如果沒有快取配置才會去載入config目錄
        if (! isset($loadedFromCache)) {
            // 載入config目錄所有PHP檔案
            $this->loadConfigurationFiles($app, $config);
        }

        //最後,我們將根據載入的配置值設定應用程式的環境。 
        // 我們將傳遞一個回撥,該回撥將用於在Web環境中獲取環境,其中不存在“--env”開關。
        $app->detectEnvironment(function () use ($config) {
            return $config->get('app.env', 'production');
        });

        // 設定時區
        date_default_timezone_set($config->get('app.timezone', 'UTC'));

        mb_internal_encoding('UTF-8');
    }

    /**
     * 從所有檔案載入配置項。因此效率很低
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @param  \Illuminate\Contracts\Config\Repository  $repository
     * @return void
     * @throws \Exception
     */
    protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
    {
        // 遍歷出所有PHP檔案
        $files = $this->getConfigurationFiles($app);

        if (! isset($files['app'])) {
            throw new Exception('Unable to load the "app" configuration file.');
        }

        // 一個一個的載入
        foreach ($files as $key => $path) {
            $repository->set($key, require $path);
        }
    }

4.小結與注意點

  1. php artisan config:cache之後不會載入config配置,即便你修改了config目錄中的配置檔案也是不生效的,除非清除快取php artisna config:clear,或者重新快取 php artisan config:cache
  2. 因為配置快取可以提高效率,因此推薦生產環境使用配置快取。
  3. 不能在config目錄內定義配置以外的東西。比如在config目錄內定義類,定義常量,自定義函式。這些都是不推薦的,因為配置快取之後,config目錄任何檔案都不會載入,這些類或者常量不存在,最終導致自動載入失敗。解決方案是使用composer.json的自動載入配置來載入:
"autoload": {
        "classmap": [
            "database/seeds",
            "database/factories"
        ],
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            # 這樣那個會載入helpers.php檔案了。該檔案定義的是輔助函式
            "bootstrap/helpers.php"
        ]
    },
  1. config 中呼叫其他的 config('something.item') 是不會預期的載入的。因為不能保證配置something.item已經載入到了
本作品採用《CC 協議》,轉載必須註明作者和本文連結
有什麼想法歡迎提問或者資訊

相關文章