分析 Config
看完了 Container 後,接著看所有元件裡,最簡單的--Config,它的功能非常單純,是一個存放設定的空間,因此很容易理解原理。
類別圖
如同第一天所說,它依賴了 Contracts,另外還有依賴 Support。
先來看一下 UML 圖:
PlantUML 原始碼如下:
@startuml |
註:上圖主要表示行為(Contract)與關係(Implement / Static Call),其他細節則忽略。
從這張圖可以知道,Config\Repository
提供了數個基本方法如 has()
get()
all()
set()
,來存取裡面的資訊,同時也提供 ArrayAccess 功能。
prepend()
和 push()
則是類似 array_unshift()
和 array_push()
的操作,不過是針對裡面的某個 key 的 value 操作。
值得一提的是:它使用了 Support\Arr
來操作 array 的 has / get / set。Support\Arr
實作了特別的功能,是 key 可以使用 .
代表 array 的階層關係,就如同 JavaScript 一樣,舉例如下:
$config = new Config\Repository([ |
好處是,如果沒有實作這樣的功能時,就得先取得 array 後,再使用 array 操作來取得更底層的元素,這樣就有機會引發 Runtime 的錯誤:
$config = new Config\Repository([ |
當然也有壞處:key 不能有關鍵字 .
,因此會發現 Laravel 設定都是使用 _
作單字分隔的。
Laravel 如何使用 Config
Laravel 一開始 bootstrap 載入的 LoadConfiguration 裡,正是在初始化 Config:
public function bootstrap(Application $app) |
而從 loadConfigurationFiles()
的程式裡,可以知道設定是從 config
目錄下,載入全部的 .php
檔,然後再一一設定回 config 實例裡。只要有遵守設定格式,如:
// myconfig.php |
就能在 Laravel 的執行時期取得這份設定:
config('myconfig.foo') // return string 'bar' |
這是如何做到的呢?首先要先了解 config()
做了什麼事,它是 Foundation 的 helper 函式。
function config($key = null, $default = null) |
app()
原始碼可以參考這裡
從這段程式碼可以了解以下行為:
config()
會從 Container 取得config
物件config(['key' => 'value])
可以加設定到config
物件config('key')
是從config
物件取得設定
如此一來,就能簡單的對 Config 物件進行操作。
如何替換 Config
上面已經了解 Config 怎麼用了,那想換用別家的,像 zend-config
看起來也不錯用,該如何做呢?主要會有兩個重點:實作與初始化
我們知道 Config 它實作了兩個介面,一個是 Contracts\Config\Repository
,另一個是 ArrayAccess
。而事實上,整個 Framework 也只依賴這兩個介面。因此,只要實作一個 Adapter 去實作這兩個介面即可取代原有的 Config。
另一個問題是初始化,這就必須調整初始化的過程才行。一種方法是:Laravel 預設的樣版會實作一個 Kernel 去繼承 Foundation\Http\Kernel
,只要在這個類別覆寫 $bootstrappers
屬性即可更改初始化過程,如:
protected $bootstrappers = [ |
CustomLoadConfiguration
只要實作 bootstrap(Application $app)
即可,另外要把 Adapter 物件設定到 Container 的 ‘config’ 下,如:
$app->instance('config', new MyAdapter()); |
另一種方法是,在 bootstrap/app.php
綁定實作階段的時候,把自定義的實作綁定到預設的實作上即可,如:
$app->singleton( |
至於為什麼會成功呢?請再回頭複習一下 bootstrap 流程 與 Container 分析,就會理解了。
本日回顧
Config 本身雖然設計很簡單,但 Laravel 使用的方法可不簡單。從 Laravel 如何使用這個物件,可以了解整個流程,與如何安全與簡單地更動流程。
另外,可以思考一件事:Config 本身幾乎涵蓋了整個 Laravel 的生命週期,而 Laravel 本身複雜的流程,應該會影響 Config 的設計,但事實上沒有,反而 Config 任務變得非常單純,單純到可以獨立抽離出來使用。Laravel 如何將複雜的流程配上單純的物件,是很值得大家參考學習的。