Laravel 中 Facade 门面的实现
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 协议》,转载必须注明作者和本文链接