Laravel中门面的意思和作用是什么,使用门面的意义在哪
Admin 2022-06-14 群英技术资讯 511 次浏览
在laravel中,因为门面能够为应用的服务容器提供一个“静态”接口,相比于传统的静态方法,门面提供的“静态”接口相当于是服务容器底层类中的一个静态代表,能够提供更加灵活和易于测试的语法,所以在laravel中要用到门面。
本文操作环境:Windows10系统、Laravel6版、Dell G3电脑。
Laravel 中的门面总体上还是遵循着门面模式的基本思想的。Laravel 中的门面是为应用的服务容器提供一个【静态】接口,相当于是服务容器底层类中的一个【静态代表】,能够提供更加灵活、易于测试、优雅的语法。
对于 Laravel 中的门面来说,我们会经常使用到,比如说缓存。
Cache::get('key');
再比如我们之前经常用的数据库和 Redis 。
DB::connection('mysql2')->table('db_test')->get()->toArray(); Redis::connection('default')->client()->get('test')
发现没有,门面全是用的静态方法。但是你点过去,会发现这个门面类里面什么东西都没有呀!
class Cache extends Facade { protected static function getFacadeAccessor() { return 'cache'; } }
在 Facade 类中,别的方法函数我们先不用看,直接拉到最底下,你会发现一个魔术方法,__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); }
__callStatic() 的意思是通过静态调用时如果没有定义对应的方法,就进入到 __callStatic() 方法中,比如我们调用的 Cache::get() 这个方法,实际上当前的 Cache 门面类以及它的父类 Facade 都没有定义这个方法,那么就直接进入到了 __callStatic() 中。接着,它就通过 getFacadeRoot() 获取我们当前门面的实例对象,然后调用实例对象中的 get() 方法。
好了,到此为止,其实如果面试的时候有面试官问你 Laravel 中的门面模式是如何实现的时候,你就可以自信地说核心就是这个 __callStatic() 魔术方法了。那么这个具体的实例对象又是从哪里来的呢?我们继续往下看。
实例对象
接下来我们看看 Facade 中的具体实例对象是怎么获取的。这里我们又要回到服务容器中。不过还是先从门面入口来看看吧。
在 __callStatic() 方法中,我们会看到调用了一个 static::getFacadeRoot() 方法来获得具体的实例对象。
public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor()); }
这个方法的内容很简单,就是调用了另外两个方法,注意 getFacadeAccessor() 是我们的各个门面子类中实现的,比如例子中就是在 Cache 这个类中实现的。它只是返回一个实例的别名,还记得这个别名是在哪里定义的吗?我们在服务容器中看到过,就是 vendor/laravel/framework/src/Illuminate/Foundation/Application.php 中 registerCoreContainerAliases() 方法里面定义的那些。
接下来,我们主要看的就是 static::resolveFacadeInstance() 这个方法。从名字我们可以出,它的意思是 解决门面实例 ,这货要是不返回一个实例对象那还真对起它的名字了。
protected static function resolveFacadeInstance($name) { if (is_object($name)) { return $name; } if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } if (static::$app) { return static::$resolvedInstance[$name] = static::$app[$name]; } }
第一个判断,如果传递进来的是一个对象,直接返回。第二个判断,如果当前实例数组中已经有了,就不再创建了,类似于一个 享元模式 的效果。注意,静态的成员数组哦!什么意思呢?静态的全局共享的,也就是说,你这个实例对象创建之后,其他地方都可以使用,完全的单例状态。最后一个判断,app 也就是我们的服务容器存在的话,进行服务容器的操作。
我们先来看下这个 app 属性是什么时候赋值的。在讲服务提供者时,Kernel 中有一个 bootstrappers 属性数组,其中有一个 RegisterFacades 提供者。很明显,它是用于注册门面的一个服务提供者,在这个服务提供者中,我们会看到这样的代码。
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(); }
其中的 Facade::setFacadeApplication() 就是将 服务容器 的 Application 对象注入到了门面类的静态成员变量 app 中。注意,同样是静态的,全局存在的。
然后我们继续回到 resolveFacadeInstance() 方法中。
protected static function resolveFacadeInstance($name) { // ………… // ………… if (static::$app) { return static::$resolvedInstance[$name] = static::$app[$name]; } }
这里怎么回事,怎么就通过 static::$app[$name] 就能获得一个实例对象了呢?别激动,别着急,想想怎么让一个对象可以进行这样的数组操作?我们之前学过的哦!
就是这个 ArrayAccess 接口,它必须实现的那几个方法可以让对象像数组一样去使用。
OK,知道原理了,我们来看看是不是这样,找到 Application 的父类 vendor/laravel/framework/src/Illuminate/Container/Container.php 。
class Container implements ArrayAccess, ContainerContract { // ………… // ………… public function offsetGet($key) { return $this->make($key); } // ………… // ………… }
真像大白了吧?不再需要我继续多解释了吧?关于 make() 方法在之前的服务容器中已经讲解过了哦。
好了,剩下的内容交给你了,请根据 vendor/laravel/framework/src/Illuminate/Foundation/Application.php 中 registerCoreContainerAliases() 方法中的别名找到 Cache 的具体实现类,然后分析它的 get()、set()、forget() 等方法的实现,看看它们是怎么根据我们的配置文件来使用不同的缓存存储方案的。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
swoole增加了多进程管理模块来替代PHP的pcntl,它相比pcntl的不同点是:swoole_process提供了pcntl没有的进程间通信swoole_process支持重定向标准输入和输出。
这篇文章主要介绍了PHP八大设计模式案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
swoole和rabbitmq的区别:RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。Swoole是一个PHP的C扩展,可用来开发PHP的高性能高并发TCP/UDP Server。
swoole在协程编程中可直接使用try/catch处理异常。但必须在协程内捕获,不得跨协程捕获异常。不仅是应用层throw的Exception,底层的一些错误也是可以被捕获的。
在thinkphp中,模型指的是企业数据和业务规则,在实际项目开发中主要实现与数据库进行操作;模型类的命名需要除去表前缀的数据库名称,采用驼峰法命名,并且首字母使用大写,模型类完成了基本的 CURD、ActiveRecord模式、连贯操作和统计查询等。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008