0

0

laravel为什么要用门面

WBOY

WBOY

发布时间:2022-06-06 16:02:10

|

2236人浏览过

|

来源于php中文网

原创

在laravel中,因为门面能够为应用的服务容器提供一个“静态”接口,相比于传统的静态方法,门面提供的“静态”接口相当于是服务容器底层类中的一个静态代表,能够提供更加灵活和易于测试的语法,所以在laravel中要用到门面。

laravel为什么要用门面

本文操作环境:Windows10系统、Laravel6版、Dell G3电脑。

laravel为什么用门面

 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() 方法里面定义的那些。

DaGaoPeng(大高朋网团购程序)
DaGaoPeng(大高朋网团购程序)

大高朋团购系统是一套Groupon模式的开源团购程序,开发的一套网团购程序,系统采用ASP+ACCESS开发的团购程序,安装超简,功能超全面,在保留大高朋团购系统版权的前提下,允许所有用户免费使用。大高朋团购系统内置多种主流在线支付接口,所有网银用户均可无障碍支付;短信发送团购券和实物团购快递发货等。 二、为什么选择大高朋团购程序系统? 1.功能强大、细节完善 除了拥有主流团购网站功能,更特别支

下载

接下来,我们主要看的就是 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() 等方法的实现,看看它们是怎么根据我们的配置文件来使用不同的缓存存储方案的。

【相关推荐:laravel视频教程

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

37

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

37

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

45

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

9

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Laravel---API接口
Laravel---API接口

共7课时 | 0.6万人学习

PHP自制框架
PHP自制框架

共8课时 | 0.6万人学习

PHP面向对象基础课程(更新中)
PHP面向对象基础课程(更新中)

共12课时 | 0.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号