环境
Laravel 5.4
原理
在Laravel中,门面为应用服务容器中绑定的类提供了一个“静态”接口,使得我们可以不用new
这些类出来,就可以直接通过静态接口调用这些类中的方法。
下面我们先看看一个门面类是怎么定义的:
namespace App\Facades;use Illuminate\Support\Facades\Facade;class Player extends Facade{ protected static function getFacadeAccessor() { return 'player'; }}
门面类都继承自Illuminate\Support\Facades\Facade
父类,这个父类中有一个魔术方法:
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); }
当我们静态调用一个不存在的方法时,例如Player::playOneSong()
,这个魔术方法就会被调用。它通过getFacadeRoot()
方法创建出一个对象,然后在这个对象上真正执行我们的方法。
再看看getFacadeRoot()
方法:
public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor()); }
这里通过我们自定义门面类中的getFacadeAccessor
方法,获取到一个service_id(暂且这么叫吧),然后传给resolveFacadeInstance
方法。
再往下看resolveFacadeInstance
方法:
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]; }
通过static::$app[$name]
从服务容器中获取 key 为name
的对象,服务容器会帮我们实例化出对应的对象(前提是已经绑定好)。
服务容器
$app
是一个对象,但它实现了ArrayAccess
接口,所以可以用这种数组的方式访问。
获取到对象后,放入到static::$resolvedInstance
静态变量中,这样下次再获取相同对象时,就不用重复实例化了。
来源地址:https://blog.csdn.net/ljfrocky/article/details/128944416