• 核心概念 —— 门面(Facades)


     

    1、简介

    门面为应用的服务容器中的绑定类提供了一个“静态”接口。Laravel 内置了很多门面,你可能在不知道的情况下正在使用它们。Laravel 的门面作为服务容器中的底层类的“静态代理”,相比于传统静态方法,在维护时能够提供更加易于测试、更加灵活的、简明且富有表现力的语法。

    Laravel的所有门面都定义在 IlluminateSupportFacades 命名空间下,所以我们可以轻松访问到门面:

    use IlluminateSupportFacadesCache;
    
    Route::get('/cache', function () {
        return Cache::get('key');
    });
    

    在整个Laravel文档中,很多例子使用了门面来演示框架的各种功能特性

    2、何时使用门面

    门面有诸多优点,其提供了简单、易记的语法,让我们无需记住长长的类名即可使用Laravel提供的功能特性,此外,由于他们对PHP动态方法的独特用法,使得它们很容易测试。

    但是,使用门面也有需要注意的地方,一个最主要的危险就是类范围蠕变。由于门面如此好用并且不需要注入,在单个类中使用过多门面,会让类很容易变得越来越大。使用依赖注入则会让此类问题缓解,因为一个巨大的构造函数会让我们很容易判断出类在变大。因此,使用门面的时候要尤其注意类的大小,以便控制其有限职责。

    注:构建与Laravel交互的第三方扩展包时,最好注入Laravel契约而不是使用门面,因为扩展包在Laravel之外构建,你将不能访问Laravel的门面测试辅助函数。

    门面 vs 依赖注入

    依赖注入的最大优点是可以替换注入类的实现,这在测试时很有用,因为你可以注入一个模拟或存根并且在存根上断言不同的方法。

    但是在静态类方法上进行模拟或存根却行不通,不过,由于门面使用了动态方法对服务容器中解析出来的对象方法调用进行了代理,我们也可以像测试注入类实例那样测试门面。例如,给定以下路由:

    use IlluminateSupportFacadesCache;
    
    Route::get('/cache', function () {
        return Cache::get('key');
    });
    

    我们可以这样编写测试来验证 Cache::get 方法以我们期望的方式被调用:

    use IlluminateSupportFacadesCache;
    
    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        Cache::shouldReceive('get')
            ->with('key')
            ->andReturn('value');
    
        $this->visit('/cache')
            ->see('value');
    }
    
    门面 vs 辅助函数

    除了门面之外,Laravel还内置了许多辅助函数用于执行通用任务,比如生成视图、触发事件、分配任务,以及发送HTTP响应等。很多辅助函数提供了和响应门面一样的功能,例如,下面这个门面调用和辅助函数调用是等价的:

    return View::make('profile');
    return view('profile');
    

    门面和辅助函数并不实质性差别,使用辅助函数的时候,可以像测试相应门面那样测试它们。例如,给定以下路由:

    Route::get('/cache', function () {
        return cache('key');
    });
    

    在调用底层, cache 方法会去调用 Cache 门面上的 get 方法,因此,尽管我们使用这个辅助函数,我们还是可以编写如下测试来验证这个方法以我们期望的方式和参数被调用:

    use IlluminateSupportFacadesCache;
    
    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        Cache::shouldReceive('get')
            ->with('key')
            ->andReturn('value');
    
        $this->visit('/cache')
            ->see('value');
    }
    
    3、门面工作原理

    在 Laravel 应用中,门面就是一个为容器中对象提供访问方式的类。该机制原理由 Facade 类实现。Laravel 自带的门面,以及我们创建的自定义门面,都会继承自 IlluminateSupportFacadesFacade 基类。

    门面类只需要实现一个方法:getFacadeAccessor。正是 getFacadeAccessor 方法定义了从容器中解析什么,然后Facade 基类使用魔术方法 __callStatic() 从你的门面中调用解析对象。

    下面的例子中,我们将会调用 Laravel 的缓存系统,浏览代码后,也许你会觉得我们调用了 Cache 的静态方法 get

    <?php
    
    namespace AppHttpControllers;
    
    use Cache;
    use AppHttpControllersController;
    
    class UserController extends Controller{
        /**
         * 为指定用户显示属性
         *
         * @param  int  $id
         * @return Response
         */
        public function showProfile($id)
        {
            $user = Cache::get('user:'.$id);
    
            return view('profile', ['user' => $user]);
        }
    }

    注意我们在顶部位置引入了 Cache 门面。该门面作为代理访问底层 IlluminateContractsCacheFactory 接口的实现。我们对门面的所有调用都会被传递给 Laravel 缓存服务的底层实例。

    如果我们查看 IlluminateSupportFacadesCache 类的源码,将会发现其中并没有静态方法 get

    class Cache extends Facade{
        /**
         * 获取组件注册名称
         *
         * @return string
         */
        protected static function getFacadeAccessor() { 
            return 'cache'; 
        }
    }

    Cache 门面继承 Facade 基类并定义了 getFacadeAccessor 方法,该方法的工作就是返回服务容器绑定类的别名,当用户引用 Cache 类的任何静态方法时,Laravel 从服务容器中解析 cache 绑定,然后在解析出的对象上调用所有请求方法(本例中是 get)。

    4、门面类列表

    下面列出了每个门面及其对应的底层类,这对深入给定根门面的 API 文档而言是个很有用的工具。服务容器绑定键也被包含进来:

    门面

    服务容器绑定

    App
    IlluminateFoundationApplication
    app

    Artisan
    IlluminateContractsConsoleKernel
    artisan

    Auth
    IlluminateAuthAuthManager
    auth

    Blade
    IlluminateViewCompilersBladeCompiler
    blade.compiler

    Bus
    IlluminateContractsBusDispatcher

    Cache
    IlluminateCacheRepository
    cache

    Config
    IlluminateConfigRepository
    config

    Cookie
    IlluminateCookieCookieJar
    cookie

    Crypt
    IlluminateEncryptionEncrypter
    encrypter

    DB
    IlluminateDatabaseDatabaseManager
    db

    DB (Instance)
    IlluminateDatabaseConnection

    Event
    IlluminateEventsDispatcher
    events

    File
    IlluminateFilesystemFilesystem
    files

    Gate
    IlluminateContractsAuthAccessGate

    Hash
    IlluminateContractsHashingHasher
    hash

    Lang
    IlluminateTranslationTranslator
    translator

    Log
    IlluminateLogWriter
    log

    Mail
    IlluminateMailMailer
    mailer

    Password
    IlluminateAuthPasswordsPasswordBroker
    auth.password

    Queue
    IlluminateQueueQueueManager
    queue

    Queue (Instance)
    IlluminateContractsQueueQueue
    queue

    Queue (Base Class)
    IlluminateQueueQueue

    Redirect
    IlluminateRoutingRedirector
    redirect

    Redis
    IlluminateRedisDatabase
    redis

    Request
    IlluminateHttpRequest
    request

    Response
    IlluminateContractsRoutingResponseFactory

    Route
    IlluminateRoutingRouter
    router

    Schema
    IlluminateDatabaseSchemaBlueprint

    Session
    IlluminateSessionSessionManager
    session

    Session (Instance)
    IlluminateSessionStore

    Storage
    IlluminateContractsFilesystemFactory
    filesystem

    URL
    IlluminateRoutingUrlGenerator
    url

    Validator
    IlluminateValidationFactory
    validator

    Validator (Instance)
    IlluminateValidationValidator

    View
    IlluminateViewFactory
    view

    View (Instance)
    IlluminateViewView

  • 相关阅读:
    使用pyppeteer 下载chromium 报错 或速度慢
    Splash抓取jd
    Splash抓取javaScript动态渲染页面
    Django3+websocket+paramiko实现web页面实时输出
    django3 websockets
    MySQL数据库OLTP基准测试( sysbench)
    数据库链接池大小设置和相关测试
    Linux 性能调优IO篇:工具命令篇
    Linux 性能调优内存篇:工具命令篇
    Vue笔记:vue项目引入bootstrap、elementUI、echarts
  • 原文地址:https://www.cnblogs.com/zhengyanbin2016/p/6008067.html
Copyright © 2020-2023  润新知