各类知识收集,PHP技术分享与解决方案各类知识收集,PHP技术分享与解决方案各类知识收集,PHP技术分享与解决方案

Str Tom,为分享PHP技术和解决方案,贡献一份自己的力量!
收藏本站(不迷路),每天更新好文章!
当前位置:首页 > CMS教程 > PHP

Laravel核心解读Facades

管理员 2023-09-05
PHP
113

Laravel核心解读Facades

内容导读

收集整理的这篇技术教程文章主要介绍了Laravel核心解读Facades,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6912字,纯文字阅读大概需要10分钟

内容图文

这篇文章主要介绍了关于Laravel核心解读Facades,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

什么是Facades

Facades是我们在Laravel应用开发中使用频率很高的一个组件,叫组件不太合适,其实它们是一组静态类接口或者说代理,让开发者能简单的访问绑定到服务容器里的各种服务。Laravel文档中对Facades的解释如下:

Facades 为应用程序的 服务容器 中可用的类提供了一个「静态」接口。Laravel 本身附带许多的 facades,甚至你可能在不知情的状况下已经在使用他们!Laravel 「facades」作为在服务容器内基类的「静态代理」,拥有简洁、易表达的语法优点,同时维持着比传统静态方法更高的可测试性和灵活性。

我们经常用的Route就是一个Facade, 它是IlluminateSupportFacadesRoute类的别名,这个Facade类代理的是注册到服务容器里的router服务,所以通过Route类我们就能够方便地使用router服务中提供的各种服务,而其中涉及到的服务解析完全是隐式地由Laravel完成的,这在一定程度上让应用程序代码变的简洁了不少。下面我们会大概看一下Facades从被注册进Laravel框架到被应用程序使用这中间的流程。Facades是和ServiceProvider紧密配合的所以如果你了解了中间的这些流程对开发自定义Laravel组件会很有帮助。

注册Facades

说到Facades注册又要回到再介绍其它核心组建时提到过很多次的Bootstrap阶段了,在让请求通过中间件和路由之前有一个启动应用程序的过程:

//Class: IlluminateFoundationHttpKernel 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 = [               'IlluminateFoundationBootstrapDetectEnvironment',             'IlluminateFoundationBootstrapLoadConfiguration',              'IlluminateFoundationBootstrapConfigureLogging',             'IlluminateFoundationBootstrapHandleExceptions',             'IlluminateFoundationBootstrapRegisterFacades',             'IlluminateFoundationBootstrapRegisterProviders',             'IlluminateFoundationBootstrapBootProviders',            ];*/            $this->app->bootstrapWith($this->bootstrappers());    }}

在启动应用的过程中IlluminateFoundationBootstrapRegisterFacades这个阶段会注册应用程序里用到的Facades。

class RegisterFacades{    /**     * Bootstrap the given application.     *     * @param  IlluminateContractsFoundationApplication  $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' => IlluminateSupportFacadesApp::class,    'Artisan' => IlluminateSupportFacadesArtisan::class,    'Auth' => IlluminateSupportFacadesAuth::class,    ......    'Route' => IlluminateSupportFacadesRoute::class,    ......]

看一下AliasLoader里是如何注册这些别名的

// class: IlluminateFoundationAliasLoaderpublic 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方法为把IlluminateSupportFacadesRoute::class类创建一个别名类Route,所以我们在程序里使用别Route其实使用的就是`IlluminateSupportFacadesRoute类。

解析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的构造方法)被IlluminateRoutingRoutingServiceProvider注册到服务容器里的:

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服务对应的类就是IlluminateRoutingRouter, 所以Route Facade实际上代理的就是这个类,Route::get实际上调用的是IlluminateRoutingRouter对象的get方法

/** * Register a new GET route with the router. * * @param  string  $uri * @param  Closure|array|string|null  $action * @return IlluminateRoutingRoute */public function get($uri, $action = null){    return $this->addRoute(['GET', 'HEAD'], $uri, $action);}

补充两点:

  1. 解析服务时用的static::$app是在最开始的RegisterFacades里设置的,它引用的是服务容器。

  2. static::$app['router'];以数组访问的形式能够从服务容器解析出router服务是因为服务容器实现了SPL的ArrayAccess接口, 对这个没有概念的可以看下官方文档ArrayAccess

总结

通过梳理Facade的注册和使用流程我们可以看到Facade和服务提供者(ServiceProvider)是紧密配合的,所以如果以后自己写Laravel自定义服务时除了通过组件的ServiceProvider将服务注册进服务容器,还可以在组件中提供一个Facade让应用程序能够方便的访问你写的自定义服务。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

Laravel中间件(Middleware)的解读

Laravel路由(Route)解读

以上就是Laravel核心解读Facades的详细内容,更多请关注Gxl网其它相关文章!

内容总结

以上是为您收集整理的Laravel核心解读Facades全部内容,希望文章能够帮你解决Laravel核心解读Facades所遇到的程序开发问题。 如果觉得技术教程内容还不错,欢迎将网站推荐给程序员好友。

内容备注

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

扫码关注

qrcode

QQ交谈

回顶部