分析 Facade
Laravel 的 Facade 是個很神奇的設計。使用的時候是靜態呼叫,但實質上是對某個實例呼叫。也因這個特性,所以有辦法做測試替身(Test Double)。
基本概念
Facade 利用了 PHP 的幾個特性並搭配 Laravel 元件實作出來的,首先是 Magic Method,不一定要為類別定義方法,就能呼叫;再來是靜態方法可以被覆寫,讓靜態類別可以被繼承的;最後它跟 Container 是互相搭配的好夥伴。
剛有提到靜態方法可以覆寫,那個方法是 getFacadeAccessor()
:
protected static function getFacadeAccessor() |
這個方法預設會丟例外。意指如果子類沒有覆寫,將無法使用這個功能。
我們來看一個基本的範例 Request:
class Request extends Facade |
它繼承的實作是回傳了 request
字串。而當我們使用這個 Facade,如 Request::ip()
時,__callStatic()
即會被觸發:
public static function __callStatic($method, $args) |
再來就是看 getFacadeRoot()
是如何解析實例的:
public static function getFacadeRoot() |
這個 $app
正是剛剛提到要搭配的 Container,使用 setFacadeApplication()
即可設定。只要有 Container 就能建構所有實例。至於究竟什麼地方被呼叫到了?在分析 bootstrap 流程時,有一小段細節並沒有提到:RegisterFacades 的實作:
public function bootstrap(Application $app) |
這下謎底全揭曉了,因此我們可以知道,下面這些程式碼得到的結果都是一樣的:
Request::ip(); |
一樣都是從 Container 取得 request
並呼叫對應的方法與回傳。
但需注意是,預設的 Facade 初始化的時機點在哪,像 Request 是在進 route middleware 之前才初始化的。若是 global middleware 或在更早之前,如設定 service provider 時,Container 還沒有存放實例,這時 Facade 的 magic 就會失效了。
另一個類別 AliasLoader 留到明天繼續討論。