# Facades
- [簡介](#introduction)
- [何時使用 Facades](#when-to-use-facades)
- [Facades Vs. 依賴注入](#facades-vs-dependency-injection)
- [Facades Vs. 輔助函數](#facades-vs-helper-functions)
- [Facades 工作原理](#how-facades-work)
- [Facade 類參考](#facade-class-reference)
<a name="introduction"></a>
## 簡介
Facades(讀音:/f??s?d/ )為應用程序的 [服務容器](/docs/{{version}}/container) 中可用的類提供了一個「靜態」接口。Laravel 自帶了很多 Facades ,可以訪問絕大部分 Laravel 的功能。Laravel Facades 實際上是服務容器中底層類的「靜態代理」,它提供了簡潔而富有表現力的語法,甚至比傳統的靜態方法更具可測試性和擴展性。
所有的 Laravel Facades 都在 `Illuminate\Support\Facades` 命名空間中定義。所以,我們可以輕松地使用 Facade :
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});
在 Laravel 的文檔中,很多示例代碼都會使用 Facades 來演示框架的各種功能。
<a name="when-to-use-facades"></a>
## 何時使用 Facades
Facades 有很多好處,它為我們使用 Laravel 的功能提供了簡單、易記的語法,而無需記住必須手動注入或配置的長長的類名。此外,由于它們對 PHP 動態方法的獨特用法,使得測試起來非常容易。
然而,在使用 Facades 時,有些地方還需要特別注意。使用 Facades 最主要的風險就是會引起類作用范圍的膨脹。因為 Facades 使用起來非常簡單而且不需要注入,就會使得我們在不經意間在單個類中使用許多 Facades,從而導致類變的越來越大。而使用依賴注入的時候,使用的類越多,構造方法就會越長,在視覺上就會引起注意,提醒你這個類有點龐大了。因此在使用 Facades 的時候,要特別注意控制好類的大小,讓類的作用范圍保持短小。
> {tip} 在開發與 Laravel 進行交互的第三方擴展包時,建議最好選擇注入 [Laravel 契約](/docs/{{version}}/contracts) ,而不是使用 Facades 的方式來使用類。因為擴展包是在 Laravel 本身之外構建,所以你無法使用 Laravel Facades 測試輔助函數。
<a name="facades-vs-dependency-injection"></a>
### Facades Vs. 依賴注入
依賴注入的主要優點之一是切換注入類的實現的能力。這在測試的時候很有用,因為你可以注入一個 mock 或者 stub ,并斷言在 stub 上調用的各種方法。
通常,真正的靜態方法是不可能被 mock 或者 stub。但是,因為 Facades 使用動態方法來代理從服務容器解析的對象的方法調用,我們可以像測試注入的類實例一樣來測試 Facades。例如,像下面的路由:
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});
我們可以用下面的測試代碼來驗證使用預期的參數來調用 `Cache::get` 方法:
use Illuminate\Support\Facades\Cache;
/**
* 一個基礎功能的測試用例。
*
* @return void
*/
public function testBasicExample()
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$this->visit('/cache')
->see('value');
}
<a name="facades-vs-helper-functions"></a>
### Facades Vs. 輔助函數
除了 Facades, Laravel 還包含各種「輔助函數」來實現一些常用的功能,比如生成視圖、觸發事件、調度任務或者發送 HTTP 響應。許多輔助函數的功能都有與之對應的 Facade。例如,下面這個 Facade 的調用和輔助函數的作用是一樣的:
return View::make('profile');
return view('profile');
這里的 Facades 和輔助函數之間沒有實際的區別。當你使用輔助函數時,你可以使用對應的 Facade 進行測試。例如,下面的路由:
Route::get('/cache', function () {
return cache('key');
});
在底層,輔助函數 `cache` 實際是調用 `Cache` facade 中的 `get` 方法。因此,盡管我們使用的是輔助函數,我們依然可以編寫以下測試來驗證該方法是否使用我們預期的參數來調用:
use Illuminate\Support\Facades\Cache;
/**
* 一個基礎功能的測試用例。
*
* @return void
*/
public function testBasicExample()
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$this->visit('/cache')
->see('value');
}
<a name="how-facades-work"></a>
## Facades 工作原理
在 Laravel 應用中,Facade 就是一個可以從容器訪問對象的類。其中核心的部件就是 `Facade` 類。不管是 Laravel 自帶的 Facades,還是用戶自定義的 Facades ,都繼承自 `Illuminate\Support\Facades\Facade` 類。
`Facade` 基類使用了 `__callStatic()` 魔術方法將你的 Facades 的調用延遲,直到對象從容器中被解析出來。在下面的例子中,調用了 Laravel 的緩存系統。通過瀏覽這段代碼,可以假定在 `Cache` 類中調用了靜態方法 `get`:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\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 。這個 Facade 作為訪問 `Illuminate\Contracts\Cache\Factory` 接口底層實現的代理。我們使用 Facade 進行的任何調用都將傳遞給 Laravel 緩存服務的底層實例。
如果我們看一下 `Illuminate\Support\Facades\Cache` 這個類,你會發現類中根本沒有 `get` 這個靜態方法:
class Cache extends Facade
{
/**
* 獲取組件的注冊名稱。
*
* @return string
*/
protected static function getFacadeAccessor() { return 'cache'; }
}
`Cache` Facade 繼承了 `Facade` 的類庫,并且定義了 `getFacadeAccessor()` 方法。這個方法的作用是返回服務容器綁定的名稱。當用戶調用 `Cache` Facade 中的任何靜態方法時, Laravel 會從 [服務容器](/docs/{{version}}/container) 中解析 `cache` 綁定以及該對象運行所請求的方法(在這個例子中就是 `get` 方法)。
<a name="facade-class-reference"></a>
## Facade 類參考
在下面你可以找到每個 Facade 類及其對應的底層類。這是一個查找給定 Facade 類 API 文檔的工具。[服務容器綁定](/docs/{{version}}/container) 的可用鍵值也包含在內。
| Facade | 類 | 服務容器綁定 |
| ----- | ----- | ----- |
| App | [Illuminate\Foundation\Application](https://laravel.com/api/{{version}}/Illuminate/Foundation/Application.html) | `app` |
| Artisan | [Illuminate\Contracts\Console\Kernel](https://laravel.com/api/{{version}}/Illuminate/Contracts/Console/Kernel.html) | `artisan` |
| Auth | [Illuminate\Auth\AuthManager](https://laravel.com/api/{{version}}/Illuminate/Auth/AuthManager.html) | `auth` |
| Blade | [Illuminate\View\Compilers\BladeCompiler](https://laravel.com/api/{{version}}/Illuminate/View/Compilers/BladeCompiler.html) | `blade.compiler` |
| Bus | [Illuminate\Contracts\Bus\Dispatcher](https://laravel.com/api/{{version}}/Illuminate/Contracts/Bus/Dispatcher.html) | |
| Cache | [Illuminate\Cache\Repository](https://laravel.com/api/{{version}}/Illuminate/Cache/Repository.html) | `cache` |
| Config | [Illuminate\Config\Repository](https://laravel.com/api/{{version}}/Illuminate/Config/Repository.html) | `config` |
| Cookie | [Illuminate\Cookie\CookieJar](https://laravel.com/api/{{version}}/Illuminate/Cookie/CookieJar.html) | `cookie` |
| Crypt | [Illuminate\Encryption\Encrypter](https://laravel.com/api/{{version}}/Illuminate/Encryption/Encrypter.html) | `encrypter` |
| DB | [Illuminate\Database\DatabaseManager](https://laravel.com/api/{{version}}/Illuminate/Database/DatabaseManager.html) | `db` |
| DB (Instance) | [Illuminate\Database\Connection](https://laravel.com/api/{{version}}/Illuminate/Database/Connection.html) | |
| Event | [Illuminate\Events\Dispatcher](https://laravel.com/api/{{version}}/Illuminate/Events/Dispatcher.html) | `events` |
| File | [Illuminate\Filesystem\Filesystem](https://laravel.com/api/{{version}}/Illuminate/Filesystem/Filesystem.html) | `files` |
| Gate | [Illuminate\Contracts\Auth\Access\Gate](https://laravel.com/api/{{version}}/Illuminate/Contracts/Auth/Access/Gate.html) | |
| Hash | [Illuminate\Contracts\Hashing\Hasher](https://laravel.com/api/{{version}}/Illuminate/Contracts/Hashing/Hasher.html) | `hash` |
| Lang | [Illuminate\Translation\Translator](https://laravel.com/api/{{version}}/Illuminate/Translation/Translator.html) | `translator` |
| Log | [Illuminate\Log\Writer](https://laravel.com/api/{{version}}/Illuminate/Log/Writer.html) | `log` |
| Mail | [Illuminate\Mail\Mailer](https://laravel.com/api/{{version}}/Illuminate/Mail/Mailer.html) | `mailer` |
| Notification | [Illuminate\Notifications\ChannelManager](https://laravel.com/api/{{version}}/Illuminate/Notifications/ChannelManager.html) | |
| Password | [Illuminate\Auth\Passwords\PasswordBrokerManager](https://laravel.com/api/{{version}}/Illuminate/Auth/Passwords/PasswordBrokerManager.html) | `auth.password` |
| Queue | [Illuminate\Queue\QueueManager](https://laravel.com/api/{{version}}/Illuminate/Queue/QueueManager.html) | `queue` |
| Queue (Instance) | [Illuminate\Contracts\Queue\Queue](https://laravel.com/api/{{version}}/Illuminate/Contracts/Queue/Queue.html) | `queue` |
| Queue (Base Class) | [Illuminate\Queue\Queue](https://laravel.com/api/{{version}}/Illuminate/Queue/Queue.html) | |
| Redirect | [Illuminate\Routing\Redirector](https://laravel.com/api/{{version}}/Illuminate/Routing/Redirector.html) | `redirect` |
| Redis | [Illuminate\Redis\Database](https://laravel.com/api/{{version}}/Illuminate/Redis/Database.html) | `redis` |
| Request | [Illuminate\Http\Request](https://laravel.com/api/{{version}}/Illuminate/Http/Request.html) | `request` |
| Response | [Illuminate\Contracts\Routing\ResponseFactory](https://laravel.com/api/{{version}}/Illuminate/Contracts/Routing/ResponseFactory.html) | |
| Route | [Illuminate\Routing\Router](https://laravel.com/api/{{version}}/Illuminate/Routing/Router.html) | `router` |
| Schema | [Illuminate\Database\Schema\Blueprint](https://laravel.com/api/{{version}}/Illuminate/Database/Schema/Blueprint.html) | |
| Session | [Illuminate\Session\SessionManager](https://laravel.com/api/{{version}}/Illuminate/Session/SessionManager.html) | `session` |
| Session (Instance) | [Illuminate\Session\Store](https://laravel.com/api/{{version}}/Illuminate/Session/Store.html) | |
| Storage | [Illuminate\Contracts\Filesystem\Factory](https://laravel.com/api/{{version}}/Illuminate/Contracts/Filesystem/Factory.html) | `filesystem` |
| URL | [Illuminate\Routing\UrlGenerator](https://laravel.com/api/{{version}}/Illuminate/Routing/UrlGenerator.html) | `url` |
| Validator | [Illuminate\Validation\Factory](https://laravel.com/api/{{version}}/Illuminate/Validation/Factory.html) | `validator` |
| Validator (Instance) | [Illuminate\Validation\Validator](https://laravel.com/api/{{version}}/Illuminate/Validation/Validator.html) | |
| View | [Illuminate\View\Factory](https://laravel.com/api/{{version}}/Illuminate/View/Factory.html) | `view` |
| View (Instance) | [Illuminate\View\View](https://laravel.com/api/{{version}}/Illuminate/View/View.html) | |
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@clayidols](http://blog.clayidols.com) | <img class="avatar-66 rm-style" src="https://avatars2.githubusercontent.com/u/21217903?v=4&s=460"> | Review | 癡呆哥哥 |
| [@JokerLinly](https://laravel-china.org/users/5350) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/5350_1481857380.jpg"> | Review | Stay Hungry. Stay Foolish. |
---
> {note} 歡迎任何形式的轉載,但請務必注明出處,尊重他人勞動共創開源社區。
>
> 轉載請注明:本文檔由 Laravel China 社區 [laravel-china.org](https://laravel-china.org) 組織翻譯,詳見 [翻譯召集帖](https://laravel-china.org/topics/5756/laravel-55-document-translation-call-come-and-join-the-translation)。
>
> 文檔永久地址: https://d.laravel-china.org
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- HomeStead
- Valet
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- 門面(Facades)
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- 重定向
- Session
- 表單驗證
- 錯誤與日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- 用戶認證
- API認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 交流說明