Laravel 核心--Facades 門面

介紹

Facades 為應(yīng)用的 IoC 服務(wù)容器 的類提供了一個靜態(tài)的接口。Laravel 里面自帶了一些 Facades,如Cache等。Laravel 的門面作為服務(wù)容器中底層類的“靜態(tài)代理”,相比于傳統(tǒng)靜態(tài)方法伸刃,在維護時能夠提供更加易于測試、更加靈活僧叉、簡明優(yōu)雅的語法奕枝。

解釋

在 Laravel 應(yīng)用這個上下文里面棺榔,一個 Facade 就是一個類瓶堕,使用這個類可以訪問到來自容器里的一個對象,這個功能就是在 Facade 類里面定義的症歇。Laravel 的 Facades 還有任何你自己定義的 Facades郎笆,都會去繼承 Facade 這個類。

你的 Facade 類只需要實施一個的方法:getFacadeAccessor忘晤。要在容器里 resolve 什么出來宛蚓,都是在這個方法里去做的。Facade 這個基類里面使用了__callStatic() 魔術(shù)方法设塔,可以延遲到 resolved 對象上的凄吏,來自 Facade 的調(diào)用。

所以,當你使用 Facade 調(diào)用的時候痕钢,比如像這樣:Cache:get图柏,laravel 會從 Ioc 服務(wù)容器 里面 resolves 緩存管理類,然后再去調(diào)用這個類上面的 get 方法任连。Laravel 的 Facades 可以去定位服務(wù)蚤吹,它是一種使用 Laravel 的 Ioc 服務(wù)容器 的更方便的語法。

優(yōu)點

Facade 有諸多優(yōu)點随抠,其提供了簡單裁着、易記的語法,讓我們無需記住長長的類名即可使用 Laravel 提供的功能特性拱她,此外二驰,由于他們對 PHP 動態(tài)方法的獨到用法,使得它們很容易測試椭懊。

實際使用

下面的例子诸蚕,去調(diào)用了一下 Laravel 的緩存系統(tǒng)。先看一下下面這行代碼氧猬,你可能會覺得背犯,這是直接去調(diào)用 Cache 這個類上面的一個叫 get 的靜態(tài)的方法。

$value = Cache::get('key');

不過盅抚,如果你查看 Illuminate\Support\Facades\Cache 這個類漠魏,你會發(fā)現(xiàn)這里根本就沒有 get 這個靜態(tài)方法:

class Cache extends Facade {

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }

}

Cache 這個類繼承了 Facade 這個基類,它里面定義了一個叫 getFacadeAccessor() 的方法妄均。注意柱锹,這個方法的干的事就是去返回一個 Ioc 綁定的名字,這里就是 cache丰包。

當用戶在引用任何在 Cache 這個 Facade 上的靜態(tài)方法的時候禁熏,Laravel 就會從 Ioc 服務(wù)容器 里面去 resolves cache 這個綁定,并且會去執(zhí)行在對象上的這個所請求的方法(這里就是 get 這個方法)邑彪。

所以瞧毙,我們在調(diào)用 Cache::get 的時候,它的真正的意思是這樣的:

$value = $app->make('cache')->get('key');

導(dǎo)入 Facades

注意寄症,在使用 facade 的時候宙彪,如果控制器里面用到了命名空間,你需要把 Facade 類導(dǎo)入到這個命名空間里有巧。所有的 Facades 都是在全局命名空間下:

<?php namespace App\Http\Controllers;

use Cache;

class PhotosController extends Controller {

    /**
     * Get all of the application photos.
     *
     * @return Response
     */
    public function index()
    {
        $photos = Cache::get('photos');

        //
    }

}

創(chuàng)建 Facades

創(chuàng)建 Facade 只需要三個東西:

  • 一個 IoC 綁定释漆。
  • 一個 Facade 類。
  • 一個 Facade 別名的配置篮迎。

在下面我們定義了一個類:PaymentGateway\Payment 男图。

namespace PaymentGateway;

class Payment {

    public function process()
    {
        //
    }

}

我們需要能在 Ioc 服務(wù)容器 里面去 resolve 這個類示姿。所以,先要去添加一個 Service Provider 綁定:

App::bind('payment', function()
{
    return new \PaymentGateway\Payment;
});

去注冊這個綁定最好的方法就是去創(chuàng)建一個新的 Service Provider 逊笆,把它命名為 PaymentServiceProvider 峻凫,然后把它綁定到 register 方法上。再去配置 laravel 在 config/app.php 這個配置文件里加載你的 Service Provider览露。

下一步就是去創(chuàng)建自己的 Facade 類:

use Illuminate\Support\Facades\Facade;

class Payment extends Facade {

    protected static function getFacadeAccessor() {
             return 'payment'; 
    }

}

最后荧琼,如果你愿意,可以去給 Facade 添加一個別名差牛,放到 config/app.php 配置文件里的 aliases 數(shù)組里命锄。

可以去調(diào)用 Payment 類的一個實例上的 process 這個方法了。像這樣:

Payment::process();

何時使用 Facade

注意

在使用 Facade 也有需要注意的地方偏化,一個最主要的危險就是類范圍蠕變脐恩。由于Facade 如此好用并且不需要注入,在單個類中使用過多Facade侦讨,會讓類很容易變得越來越大驶冒。使用依賴注入則會讓此類問題緩解,因為一個巨大的構(gòu)造函數(shù)會讓我們很容易判斷出類在變大韵卤。因此骗污,使用Facade的時候要尤其注意類的大小,以便控制其有限職責沈条。

注:構(gòu)建與 Laravel 交互的第三方擴展包時需忿,最好注入 Laravel 契約而不是使用門面,因為擴展包在 Laravel 之外構(gòu)建蜡歹,你將不能訪問 Laravel 的門面測試輔助函數(shù)屋厘。

Facade vs. 依賴注入

依賴注入的最大優(yōu)點是可以替換注入類的實現(xiàn),這在測試時很有用月而,因為你可以注入一個模擬或存根并且在存根上斷言不同的方法汗洒。

但是在靜態(tài)類方法上進行模擬或存根卻行不通,不過父款,由于Facade 使用了動態(tài)方法對服務(wù)容器中解析出來的對象方法調(diào)用進行了代理溢谤,我們也可以像測試注入類實例那樣測試門面。例如铛漓,給定以下路由:

use Illuminate\Support\Facades\Cache;

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

我們可以這樣編寫測試來驗證 Cache::get 方法以我們期望的方式被調(diào)用:

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');
}

Facade vs. 輔助函數(shù)

除了Facade之外溯香,Laravel 還內(nèi)置了許多輔助函數(shù)用于執(zhí)行通用任務(wù)鲫构,比如生成視圖浓恶、觸發(fā)事件、分配任務(wù)结笨,以及發(fā)送 HTTP 響應(yīng)等包晰。很多輔助函數(shù)提供了和相應(yīng) Facade 一樣的功能湿镀,例如,下面這個Facade調(diào)用和輔助函數(shù)調(diào)用是等價的:

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

Facade和輔助函數(shù)之間并不存在實質(zhì)性差別伐憾,使用輔助函數(shù)的時候勉痴,可以像測試相應(yīng)門面那樣測試它們。例如树肃,給定以下路由:

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

在調(diào)用底層蒸矛, cache 方法會去調(diào)用 Cache Facade上的 get方法,因此胸嘴,盡管我們使用這個輔助函數(shù)雏掠,我們還是可以編寫如下測試來驗證這個方法以我們期望的方式和參數(shù)被調(diào)用:

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');
}

Facade 工作原理

在 Laravel 應(yīng)用中,Facade就是一個為容器中對象提供訪問方式的類劣像。該機制原理由 Facade 類實現(xiàn)乡话。Laravel 自帶的 Facade,以及我們創(chuàng)建的自定義門面耳奕,都會繼承自 Illuminate\Support\Facades\Facade 基類绑青。可以參考 Facade 實現(xiàn)原理

Facade 類只需要實現(xiàn)一個方法:getFacadeAccessor屋群。正是 getFacadeAccessor方法定義了從容器中解析什么闸婴,然后 Facade 基類使用魔術(shù)方法 __callStatic() 從你的門面中調(diào)用解析對象。

下面的例子中芍躏,我們將會調(diào)用 Laravel 的緩存系統(tǒng)掠拳,瀏覽代碼后,也許你會覺得我們調(diào)用了 Cache 的靜態(tài)方法 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 Facade纸肉。該門面作為代理訪問底層 Illuminate\Contracts\Cache\Factory 接口的實現(xiàn)溺欧。我們對門面的所有調(diào)用都會被傳遞給 Laravel 緩存服務(wù)的底層實例。

如果我們查看 Illuminate\Support\Facades\Cache 類的源碼柏肪,將會發(fā)現(xiàn)其中并沒有靜態(tài)方法 get

class Cache extends Facade
{
    /**
     * 獲取組件注冊名稱
     *
     * @return string
     */
    protected static function getFacadeAccessor() { 
        return 'cache'; 
    }
}

Cache Facade 繼承 Facade 基類并定了 getFacadeAccessor方法姐刁,該方法的工作就是返回服務(wù)容器綁定類的別名,當用戶引用 Cache
類的任何靜態(tài)方法時烦味,Laravel 從服務(wù)容器中解析 cache
綁定聂使,然后在解析出的對象上調(diào)用所有請求方法(本例中是 get

門面類列表

下面列出了每個門面及其對應(yīng)的底層類,這對深入給定根門面的 API 文檔而言是個很有用的工具谬俄。服務(wù)容器綁定鍵也被包含進來:

門面 Facade class 服務(wù)容器綁定
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
Notification Illuminate\Notifications\ChannelManager
Password Illuminate\Auth\Passwords\PasswordBrokerManager 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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柏靶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子溃论,更是在濱河造成了極大的恐慌屎蜓,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钥勋,死亡現(xiàn)場離奇詭異炬转,居然都是意外死亡辆苔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門扼劈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驻啤,“玉大人,你說我怎么就攤上這事荐吵∑锶撸” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵先煎,是天一觀的道長沐旨。 經(jīng)常有香客問我,道長榨婆,這世上最難降的妖魔是什么磁携? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮良风,結(jié)果婚禮上谊迄,老公的妹妹穿的比我還像新娘。我一直安慰自己烟央,他們只是感情好统诺,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疑俭,像睡著了一般粮呢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钞艇,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天啄寡,我揣著相機與錄音,去河邊找鬼哩照。 笑死挺物,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的飘弧。 我是一名探鬼主播识藤,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼次伶!你這毒婦竟也來了痴昧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤冠王,失蹤者是張志新(化名)和其女友劉穎赶撰,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡扣囊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绒疗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侵歇。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吓蘑,靈堂內(nèi)的尸體忽然破棺而出惕虑,到底是詐尸還是另有隱情,我是刑警寧澤磨镶,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布溃蔫,位于F島的核電站,受9級特大地震影響琳猫,放射性物質(zhì)發(fā)生泄漏伟叛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一脐嫂、第九天 我趴在偏房一處隱蔽的房頂上張望统刮。 院中可真熱鬧,春花似錦账千、人聲如沸侥蒙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鞭衩。三九已至,卻和暖如春娃善,著一層夾襖步出監(jiān)牢的瞬間论衍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工聚磺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留饲齐,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓咧最,卻偏偏與公主長得像捂人,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子矢沿,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Laravel 的核心概念包括:服務(wù)容器滥搭、服務(wù)提供者、門面(Facades)捣鲸、契約(Contracts)瑟匆。 服務(wù)容...
    胖福哥閱讀 2,763評論 0 24
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法栽惶,內(nèi)部類的語法愁溜,繼承相關(guān)的語法疾嗅,異常的語法,線程的語...
    子非魚_t_閱讀 31,581評論 18 399
  • Facade 布局是在面向?qū)ο缶幊讨薪?jīng)常使用的一種軟件設(shè)計布局方式。Facade 實際上是一種包括復(fù)雜函數(shù)庫的類渐扮,...
    OneAPM閱讀 1,463評論 0 15
  • 原文鏈接 必備品 文檔:Documentation API:API Reference 視頻:Laracasts ...
    layjoy閱讀 8,603評論 0 121
  • 最近項目中要用到AR 解決了好幾天 今天終于迎來了喜報论悴。 先說easyAR如果ARviewcontroller ...
    slimsallen閱讀 1,321評論 0 0