您好,欢迎访问一九零五行业门户网

Laravel核心解读Facades

这篇文章主要介绍了关于laravel核心解读facades,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下
什么是facadesfacades是我们在laravel应用开发中使用频率很高的一个组件,叫组件不太合适,其实它们是一组静态类接口或者说代理,让开发者能简单的访问绑定到服务容器里的各种服务。laravel文档中对facades的解释如下:
facades 为应用程序的 服务容器 中可用的类提供了一个「静态」接口。laravel 本身附带许多的 facades,甚至你可能在不知情的状况下已经在使用他们!laravel 「facades」作为在服务容器内基类的「静态代理」,拥有简洁、易表达的语法优点,同时维持着比传统静态方法更高的可测试性和灵活性。我们经常用的route就是一个facade, 它是\illuminate\support\facades\route类的别名,这个facade类代理的是注册到服务容器里的router服务,所以通过route类我们就能够方便地使用router服务中提供的各种服务,而其中涉及到的服务解析完全是隐式地由laravel完成的,这在一定程度上让应用程序代码变的简洁了不少。下面我们会大概看一下facades从被注册进laravel框架到被应用程序使用这中间的流程。facades是和serviceprovider紧密配合的所以如果你了解了中间的这些流程对开发自定义laravel组件会很有帮助。
注册facades说到facades注册又要回到再介绍其它核心组建时提到过很多次的bootstrap阶段了,在让请求通过中间件和路由之前有一个启动应用程序的过程:
//class: \illuminate\foundation\http\kernel protected function sendrequestthroughrouter($request){ $this->app->instance('request', $request); facade::clearresolvedinstance('request'); $this->bootstrap(); return (new pipeline($this->app)) ->send($request) ->through($this->app->shouldskipmiddleware() ? [] : $this->middleware) ->then($this->dispatchtorouter());}//引导启动laravel应用程序public function bootstrap(){ if (! $this->app->hasbeenbootstrapped()) { /**依次执行$bootstrappers中每一个bootstrapper的bootstrap()函数 $bootstrappers = [ 'illuminate\foundation\bootstrap\detectenvironment', 'illuminate\foundation\bootstrap\loadconfiguration', 'illuminate\foundation\bootstrap\configurelogging', 'illuminate\foundation\bootstrap\handleexceptions', 'illuminate\foundation\bootstrap\registerfacades', 'illuminate\foundation\bootstrap\registerproviders', 'illuminate\foundation\bootstrap\bootproviders', ];*/ $this->app->bootstrapwith($this->bootstrappers()); }}
在启动应用的过程中illuminate\foundation\bootstrap\registerfacades这个阶段会注册应用程序里用到的facades。
class registerfacades{ /** * bootstrap the given application. * * @param \illuminate\contracts\foundation\application $app * @return void */ public function bootstrap(application $app) { facade::clearresolvedinstances(); facade::setfacadeapplication($app); aliasloader::getinstance(array_merge( $app->make('config')->get('app.aliases', []), $app->make(packagemanifest::class)->aliases() ))->register(); }}
在这里会通过aliasloader类的实例将为所有facades注册别名,facades和别名的对应关系存放在config/app.php文件的$aliases数组中
'aliases' => [ 'app' => illuminate\support\facades\app::class, 'artisan' => illuminate\support\facades\artisan::class, 'auth' => illuminate\support\facades\auth::class, ...... 'route' => illuminate\support\facades\route::class, ......]
看一下aliasloader里是如何注册这些别名的
// class: illuminate\foundation\aliasloaderpublic static function getinstance(array $aliases = []){ if (is_null(static::$instance)) { return static::$instance = new static($aliases); } $aliases = array_merge(static::$instance->getaliases(), $aliases); static::$instance->setaliases($aliases); return static::$instance;}public function register(){ if (! $this->registered) { $this->prependtoloaderstack(); $this->registered = true; }}protected function prependtoloaderstack(){ // 把aliasloader::load()放入自动加载函数队列中,并置于队列头部 spl_autoload_register([$this, 'load'], true, true);}
通过上面的代码段可以看到aliasloader将load方法注册到了spl __autoload函数队列的头部。看一下load方法的源码:
public function load($alias){ if (isset($this->aliases[$alias])) { return class_alias($this->aliases[$alias], $alias); }}
在load方法里$aliases配置里的facade类创建了对应的别名,比如当我们使用别名类route时php会通过aliasloader的load方法为把illuminate\support\facades\route::class类创建一个别名类route,所以我们在程序里使用别route其实使用的就是`illuminate\support\facades\route类。
解析facade代理的服务把facades注册到框架后我们在应用程序里就能使用其中的facade了,比如注册路由时我们经常用route::get('/uri', 'controller@action);,那么route是怎么代理到路由服务的呢,这就涉及到在facade里服务的隐式解析了, 我们看一下route类的源码:
class route extends facade{ /** * get the registered name of the component. * * @return string */ protected static function getfacadeaccessor() { return 'router'; }}
只有简单的一个方法,并没有get, post, delete等那些路由方法, 父类里也没有,不过我们知道调用类不存在的静态方法时会触发php的__callstatic静态方法
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);}//获取facade根对象public static function getfacaderoot(){ return static::resolvefacadeinstance(static::getfacadeaccessor());}/** * 从服务容器里解析出facade对应的服务 */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];}
通过在子类route facade里设置的accessor(字符串router), 从服务容器中解析出对应的服务,router服务是在应用程序初始化时的registerbaseserviceproviders阶段(具体可以看application的构造方法)被\illuminate\routing\routingserviceprovider注册到服务容器里的:
class routingserviceprovider extends serviceprovider{ /** * register the service provider. * * @return void */ public function register() { $this->registerrouter(); ...... } /** * register the router instance. * * @return void */ protected function registerrouter() { $this->app->singleton('router', function ($app) { return new router($app['events'], $app); }); } ......}
router服务对应的类就是\illuminate\routing\router, 所以route facade实际上代理的就是这个类,route::get实际上调用的是\illuminate\routing\router对象的get方法
/** * register a new get route with the router. * * @param string $uri * @param \closure|array|string|null $action * @return \illuminate\routing\route */public function get($uri, $action = null){ return $this->addroute(['get', 'head'], $uri, $action);}
补充两点:
解析服务时用的static::$app是在最开始的registerfacades里设置的,它引用的是服务容器。
static::$app['router'];以数组访问的形式能够从服务容器解析出router服务是因为服务容器实现了spl的arrayaccess接口, 对这个没有概念的可以看下官方文档arrayaccess
总结通过梳理facade的注册和使用流程我们可以看到facade和服务提供者(serviceprovider)是紧密配合的,所以如果以后自己写laravel自定义服务时除了通过组件的serviceprovider将服务注册进服务容器,还可以在组件中提供一个facade让应用程序能够方便的访问你写的自定义服务。
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注!
相关推荐:
laravel中间件(middleware)的解读
laravel路由(route)解读
以上就是laravel核心解读facades的详细内容。
其它类似信息

推荐信息