Route::get('/', function () {
return view('welcome');
});
在laravel中的路由檔案routes/web.php
有這麼一段程式碼,用於配置路由。這裡Route
就是用Facade
實現類方法get
的靜態呼叫。
Laravel中的Facade解決類什麼問題?
在php中,很多情況都需要使用一個容器獲取到所有的物件,然後再呼叫改物件的方法,這樣在編寫程式碼的時候就會看到很長的一個呼叫鏈。例如:
在Yii2中,幾乎所有的系統類都是在app容器當中,對這些系統類進行操作都需要執行Yii::$app->route
獲取到類例項,然後在執行方法Yii::$app->route->get()
。但是如果用Facade實現之後的呼叫就是Route::get()
。這樣的寫法是的程式碼更加簡潔。
Laravel中Facade是怎麼實現的?
思路是透過__callStatic
魔術方法將方法呼叫代理到實際的物件方法中去。
abstract class Facade
{
...
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
...
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) {
return $name;
}
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
...
public static function getFacadeAccessor(){
//子類返回類名
}
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
}
class Route extends Facade{
public static function getFacadeAccessor(){
return 'router';
}
}
根據每個Facade
中提供的getFacadeAccessor
返回實際的物件類名,獲取類物件。每個類物件一旦建立,就放在一個靜態陣列中,因此在一次請求中最多隻會被建立一次。
有沒有其他的實現方式?
從上面的程式碼可以看到,其實核心就是一個靜態代理的功能。那麼有沒有其他的實現方式了呢?
class Facade{
public static $instance;
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) {
return $name;
}
if (isset(static::$instance)) {
return static::$instance;
}
return static::$instance = static::$app[$name];
}
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
}
class Route extends Facade{
}
可以看出,上面的方式也能夠實現靜態代理,類似於Facade的功能。都是透過魔術方法實現。作用上,都簡化了程式碼編寫。
兩種不同實現方式的區別
第二種實現方式有一個很大的缺點,那就是必須繼承Facade
類。PHP本身只能繼承一個類,所以第二種實現方式對於一些需要繼承其他類的物件是不適合的。
Laravel的實現方式,對類本身沒有束縛,任何類物件都能夠透過建立一個Facade物件實現靜態代理。有很大的靈活性。
轉載自 公眾號【寫PHP的老王】
本作品採用《CC 協議》,轉載必須註明作者和本文連結