這篇文章的性質偏向個人在研究 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的章節了,
可是已經有點懶的寫了阿~