1、简介

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

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

use Illuminate\Support\Facades\Cache;

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

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

2、何时使用门面

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

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

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

门面 vs 依赖注入

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

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

use Illuminate\Support\Facades\Cache;

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

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

use Illuminate\Support\Facades\Cache;

/**
* 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 Illuminate\Support\Facades\Cache;

/**
* 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 自带的门面,以及我们创建的自定义门面,都会继承自 Illuminate\Support\Facades\Facade 基类。

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

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

<?php

namespace App\Http\Controllers;

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

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

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

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

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

4、门面类列表

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

门面

服务容器绑定

App
Illuminate\Foundation\Application
app

Artisan
Illuminate\Contracts\Console\Kernel
artisan

Auth
Illuminate\Auth\AuthManager
auth

Blade
Illuminate\View\Compilers\BladeCompiler
blade.compiler

Bus
Illuminate\Contracts\Bus\Dispatcher

Cache
Illuminate\Cache\Repository
cache

Config
Illuminate\Config\Repository
config

Cookie
Illuminate\Cookie\CookieJar
cookie

Crypt
Illuminate\Encryption\Encrypter
encrypter

DB
Illuminate\Database\DatabaseManager
db

DB (Instance)
Illuminate\Database\Connection

Event
Illuminate\Events\Dispatcher
events

File
Illuminate\Filesystem\Filesystem
files

Gate
Illuminate\Contracts\Auth\Access\Gate

Hash
Illuminate\Contracts\Hashing\Hasher
hash

Lang
Illuminate\Translation\Translator
translator

Log
Illuminate\Log\Writer
log

Mail
Illuminate\Mail\Mailer
mailer

Password
Illuminate\Auth\Passwords\PasswordBroker
auth.password

Queue
Illuminate\Queue\QueueManager
queue

Queue (Instance)
Illuminate\Contracts\Queue\Queue
queue

Queue (Base Class)
Illuminate\Queue\Queue

Redirect
Illuminate\Routing\Redirector
redirect

Redis
Illuminate\Redis\Database
redis

Request
Illuminate\Http\Request
request

Response
Illuminate\Contracts\Routing\ResponseFactory

Route
Illuminate\Routing\Router
router

Schema
Illuminate\Database\Schema\Blueprint

Session
Illuminate\Session\SessionManager
session

Session (Instance)
Illuminate\Session\Store

Storage
Illuminate\Contracts\Filesystem\Factory
filesystem

URL
Illuminate\Routing\UrlGenerator
url

Validator
Illuminate\Validation\Factory
validator

Validator (Instance)
Illuminate\Validation\Validator

View
Illuminate\View\Factory
view

View (Instance)
Illuminate\View\View

核心概念 —— 门面(Facades)的更多相关文章

  1. Laravel 的核心概念

    工欲善其事,必先利其器.在开发Xblog的过程中,稍微领悟了一点Laravel的思想.确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Larav ...

  2. Laravel 核心概念

    工欲善其事,必先利其器.在开发Xblog的过程中,稍微领悟了一点Laravel的思想.确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Larav ...

  3. 领域驱动设计(DDD)部分核心概念的个人理解

    领域驱动设计(DDD)是一种基于模型驱动的软件设计方式.它以领域为核心,分析领域中的问题,通过建立一个领域模型来有效的解决领域中的核心的复杂问题.Eric Ivans为领域驱动设计提出了大量的最佳实践 ...

  4. Javascript本质第一篇:核心概念

    很多人在使用Javascript之前都至少使用过C++.C#或Java,面向对象的编程思想已经根深蒂固,恰好Javascript在语法上借鉴了Java,虽然方便了Javascript的入门,但要深入理 ...

  5. [程序设计语言]-[核心概念]-02:名字、作用域和约束(Bindings)

    本系列导航 本系列其他文章目录请戳这里. 1.名字.约束时间(Binding Time) 在本篇博文开始前先介绍两个约定:第一个是“对象”,除非在介绍面向对象语言时,本系列中出现的对象均是指任何可以有 ...

  6. laravel框架总结(六) -- 门面(facades)

    Facades 为应用程序的服务容器中可用的类提供了一个「静态」接口.   Laravel 本身附带许多的 facades,甚至你可能在不知情的状况下已经在使用他们!   xpower的静态接口(门面 ...

  7. spring技术核心概念纪要

    一.背景 springframework 从最初的2.5版本发展至今,期间已经发生了非常多的修正及优化.许多新特性及模块的出现,使得整个框架体系显得越趋庞大,同时也带来了学习及理解上的困难. 本文阐述 ...

  8. ElasticSearch学习笔记-01 简介、安装、配置与核心概念

    一.简介 ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎.设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便.支持通过HTTP使用JSON进 ...

  9. Playmaker Input篇教程之引入的核心概念

    Playmaker Input篇教程之引入的核心概念 Playmaker Input引入的核心概念 Playmaker引入了4个核心概念:状态机.动作.变量和事件.了解它们是学习操作Playmaker ...

随机推荐

  1. 使用paramiko进行打包操作

    使用paramiko执行ssh命令的时候有一个很坑爹的地方:它无法准确的识别你的系统环境变量,所以使用一些命令的时候会发现,直接在系统中执行该命令的时候可以,但是换成paramiko执行的时候会报错说 ...

  2. OC内存管理基础

    OC 内存管理基础 一. retain和release基本使用 使用注意: 1.你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作) 2.你不想再使用(占用)某个对象,就 ...

  3. mockjs学习总结(方便前端模拟数据,加快开发效率)

      基本介绍: 在我们前端开发中经常遇到这样的事情,接口没有写好,只能写静态页面,如何才能用很简单的方法模拟后端数据呢?mockjs就干了这件事,而且干的还挺好. 下面是我作为初学者的一些总结经验,期 ...

  4. 看京东如何把Intel RealSense技术用在物流上

    提起Intel RealSense 3D 深度摄像头,总是离不开无人机.机器人等前沿硬件产品,比如 CES 2016 上让人眼前一亮的自动避障无人机Yuneec “台风 H”,Segway.Nineb ...

  5. Hadoop on Mac with IntelliJ IDEA - 3 解决MRUnit - No applicable class implementing Serialization问题

    本文讲述在IntelliJ IDEA中使用MRUnit 1.0.0测试Mapper派生类时因MapDriver.withInput(final K1 key, final V1 val)的key参数被 ...

  6. TreeView节点拖拉操作

    //这个拖拽的感觉不对     unit Unit1;interfaceuses  Windows, Messages, SysUtils, Classes, Graphics, Controls, ...

  7. 关于IE8中使用Jquery load方法无法正常加载页面

    最近发现,在IE8中使用Jquery load方法时无法正常加载页面,页面显示空白,没有加载.调试发现,页面多了一个</div>标签,但在FF和CH下表现正常.希望能给遇到同样问题的码农有 ...

  8. Python 学习之二:Python超短教程

    前言 本教程综合Stanford CS231N和UC Berkerley CS188的Python教程. 教程非常短,但适合有一定编程基础.学过其它语言的童鞋. Python 启动Python 解释器 ...

  9. yii中阻止 SHOW CREATE TABLE and SHOW COLUMNS 每次执行

    Disable SHOW CREATE TABLE and SHOW COLUMNS in Yii为啥会显示:SHOW CREATE TABLE and SHOW COLUMNS 答案:This is ...

  10. slots - Python的结构体 转

          上个月看了篇文章 “SAVING 9 GB OF RAM WITH PYTHON’S __SLOTS__”,原来Python也有类似结构体的东东.拖了一个月才写这篇,是因为太久没看pyth ...