Laravel Facade 解讀
大家好,今天帶來的內容是 Laravel 的 Facade 機制實現原理。
Facade的簡單使用
資料庫的使用:
$users = DB::connection('foo')->select(...);
IOC容器
眾所周知,IOC容器是 Laravel 框架的最最重要的部分。它提供了兩個功能,IOC和容器。
- IOC(Inversion of Control),也叫控制反轉。說白了,就是控制物件的生成,使開發者不用關心物件的如何生成,只需要關心它的使用即可。
- 而通過IOC機制生成的物件例項需要一個存放的位置,以便之後繼續使用,便是它的容器功能。
這次不準備講解IOC容器的具體實現,之後會有文章詳細解讀它。關於IOC容器,讀者只需要記住兩點即可:
- 根據配置生成物件例項;
- 儲存物件例項,方便隨時取用;
簡化後 Facade 類
<?php namespace facades; abstract class Facade { protected static $app; /** * Set the application instance. * * @param\Illuminate\Contracts\Foundation\Application$app * @return void */ public static function setFacadeApplication($app) { static::$app = $app; } /** * Get the registered name of the component. * * @return string * * @throws \RuntimeException */ protected static function getFacadeAccessor() { throw new RuntimeException('Facade does not implement getFacadeAccessor method.'); } /** * Get the root object behind the facade. * * @return mixed */ public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor()); } /** * Resolve the facade root instance from the container. * * @paramstring|object$name * @return mixed */ protected static function resolveFacadeInstance($name) { return static::$app->instances[$name]; } public static function __callStatic($method, $args) { $instance = static::getFacadeRoot(); if (! $instance) { throw new RuntimeException('A facade root has not been set.'); } switch (count($args)) { case 0: return $instance->$method(); case 1: return $instance->$method($args[0]); case 2: return $instance->$method($args[0], $args[1]); case 3: return $instance->$method($args[0], $args[1], $args[2]); case 4: return $instance->$method($args[0], $args[1], $args[2], $args[3]); default: return call_user_func_array([$instance, $method], $args); } } }
程式碼說明:
- $app中存放的就是一個IOC容器例項,它是在框架初始化時,通過 setFacadeApplication() 這個靜態方法設定的
- 它實現了 __callStatic 魔術方法
- getFacadeAccessor() 方法需要子類去繼承,返回一個string的標識,通過這個標識,IOC容器便能返回它所繫結類(框架初始化或其它時刻繫結)的物件
- 通過 $instance 呼叫具體的方法
建立自己的Facade:
TEST1 的具體邏輯:
<?php class Test1 { public function hello() { print("hello world"); } }
TEST1 類的Facade:
<?php namespace facades; /** * Class Test1 * @package facades * * @method static setOverRecommendInfo [設定播放完畢時的回撥函式] * @method static setHandlerPlayer [明確指定下一首時的執行類] */ class Test1Facade extends Facade { protected static function getFacadeAccessor() { return 'test1'; } }
使用:
use facades\Test1Facade; Test1Facade::hello();// 這是 Facade 呼叫
解釋:
- facades\Test1Facade 呼叫靜態方法 hello() 時,由於沒有定義此方法,會呼叫 __callStatic;
-
在 __callStatic 中,首先是獲取對應的例項,即
return static::$app->instances[$name];
。這其中的$name
,即為facades\Test1
裡的 test1 - $app, 即為 IOC 容器,類的例項化過程,就交由它來處理。