如何使用 Laravel Facades ?
Facade 佈局是在物件導向程式設計中經常使用的一種軟體設計佈局方式。Facade 實際上是一種包括複雜函式庫的類,提供了更加簡潔易讀的介面。Facade 佈局還能為一組結構複雜、設計簡陋的 API 提供統一、設計周到的 API。
Laravel 框架與該佈局的特點相似,也稱為 Facades。在本教程中,我們會學習如何在其他框架應用 Laravel 的 “Facades”。在繼續學習之前,讓我們簡單瞭解一下 Ioc 容器。
首先,我們瞭解 Laravel 的 facades 內部工作結構。之後再討論如何將之改造並用於其他環境。
Laravel 中的 Facades
Laravel facade 是一種為容器內部服務提供類似靜態介面的類。據其文件描述,Facades 是可觸及容器服務底層實現方式的代理。
不過,在 PHP 社群,有關其名稱的爭論一直不斷。一些人堅持修改此名稱以避免開發者的困惑,因為其並未完全實現 Facade 佈局。如果你也受此名稱困擾,大可以為其取個別名。但是,請注意,下文將會用到的 Laravel 框架基類(base class)將會稱為 Facade。
How Facades Are implemented in Laravel
Facades 在 Laravel 中如何實現
你可能也知道,容器內的每個服務都有個唯一名稱。在 laravel 應用中,可使用 App::make()
方法或 app()
輔助函式從容器中直接獲取服務。
<?php
App::make('some_service')->methodName();
前面已經提過,Laravel 使用 facade 類的好處是讓開發者使用服務時更加便捷。使用 facade 類之後,下面的程式碼就能達到相同的效果:
// ...
someService::methodName();
// ...
在 Laravel 中,所有服務都包含一個 facade 類。這些 facade 類繼承自 Illuminate/Support
包中的 Facade 基類。它們只需實現 getFacadeAccessor
方法即可,後者會返回容器內的服務名。
在上面的示例中,someService
代表 facade 類。methodName
其實是容器內原服務的一個方法。如果跳出 Laravel 的語境檢視上面的示例,則表示一個名為 someService
的類引出名為 methodName()
的靜態方法。但 Laravel 並不是這樣實現介面的。在下一節,我們將介紹 Laravel 的 Facade 基類在幕後的運作方式。
Base Facade
Facade 類包含一個名為 $app
的私有屬性,其值為服務容器的引用。如果要在 Laravel 之外使用 facades,必須使容器明確使用 setFacadeApplication()
方法。
在 facade 基類內部,__callStatic
魔術方法用於處理實際並不存在的靜態方法的呼叫。如果呼叫 Laravel facade 類的靜態方法, __callStatic
方法便會啟用,因為 facade 類並未實現該方法。因此,__callStatic
會從容器獲取各自的服務,進而呼叫之。
以下是 facade 基類中 __callStatic
方法的實現方式:
<?php
// ...
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
switch (count($args)) {
case 0:
return $instance->$method();
case 1:
return $instance->$method($args[0]);
case 2:
return $instance->$method($args[0], $args[1]);
case 3:
return $instance->$method($args[0], $args[1], $args[2]);
case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);
default:
return call_user_func_array([$instance, $method], $args);
}
}
在上面的方法中,getFacadeRoot()
會從容器獲取服務。
Facade 類解析
每個 facade 類均繼承自基類。我們只需實現 getFacadeAccessor()
方法,該方法用於返回容器中的服務名。
<?php namespace App\Facades;
use Illuminate\Support\Facades\Facade as BaseFacade;
class SomeServiceFacade extends BaseFacade {
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor() { return 'some.service'; }
}
別名
由於 Laravel facades 是 PHP 類,在使用之前我們得匯入它們。PHP 支援名稱空間與自動匯入,因此只要呼叫全限定名,即可自動載入這些類。PHP 還支援使用 use
指令給類取別名:
use App\Facades\SomeServiceFacade
SomeServiceFacade:SomeMethod();
然而,在需要某個特定的 facade 類時,我們必須在每個指令碼檔案都寫一遍上面的程式碼。Laravel 在處理 facade 別名時有其獨特的方法——別名載入器(alias loader)。
Laravel 如何給 Facades 加別名
所有的別名都儲存在 app.php
配置檔案的 aliases
陣列中,該檔案儲存在 /config
目錄下。
檢視該陣列,會發現每個別名都與一個全限定類名對應。這意味著我們可以給 facade 類選定任意的名字。
// ..
'aliases' => [ // ... 'FancyName' => 'App\Facades\SomeServiceFacade', ],
現在,讓我們看看 Laravel 如何使用該陣列給 facade 類取別名。在引導階段,Laravel 會使用來自 Illuminate\Foundation
包的 AliasLoader
服務。AliasLoader
以該別名陣列為引數,遍歷其所有元素,使用 PHP 的 spl_autoload_register 建立一個 __autoload
函式佇列。各個 __autoload
函式會用 PHP 的 class_alias 函式為各個 facade 類建立別名。
因此,我們無需像使用 use
指令時那樣在使用類前匯入之併為其建立別名。當我們試圖使用一個不存在的類時,PHP 會檢查 __autoload
佇列以得到合適的 autoloader。這時,AliasLoader
已經記下所有的 __autoload
函式。各個 autoloader 會選定一個類名並根據別名陣列推匯出對應的初始類名。最後,它會為其建立別名。請參考下面的方法呼叫:
<?php
// FancyName is resolved to App\Facades\SomeServiceFacade according to the aliases array
FancyName::someMethod()
在幕後,FancyName
會對應至 App\Facades\SomeServiceFacade
。
在其他框架使用 Facades
現在,我們已經瞭解 Laravel 如何處理 facades 與別名,我們可以將 Laravel 的 facade 方法運用到其他環境中。接下來,我們會在 Silex 框架使用 facades。然而,只要遵循同樣的理念,你也可以將之用在別的框架。
Silex 擁有繼承自 Pimple
的容器。使用 $app
物件即可呼叫容器內的服務:
<?php
$app['some.service']->someMethod()
有了 facade 類,我們可以為 Silex 服務提供一個類似靜態的介面。此外,我們也可以使用 AliasLoader
服務為這些 facades 建立有意義的別名。因此,我們可以重組上面的程式碼:
<?php
SomeService::someMethod();
必備條件
為了使用 facade 基類,我們要使用 composer
指令安裝 Illuminate\Support
包:
composer require illuminate\support
此包還包含其他服務。但目前我們只需要 facade 基類。
建立 Facades
只需繼承 Facade 基類並實現 getFacadeAccessor
方法,即可為服務建立 facade。
在本文中,所有 facades 都會儲存在 src/Facades
路徑下。例如:名為 some.service
的服務,其 facade 類如下:
<?php
namespace App\Facades
use Illuminate\Support\Facades\Facade;
class SomeServiceFacade extends Facade {
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor() { return 'some.service'; }
}
請注意,此類位於 app\facades
名稱空間下。
現在只剩下設定 facade 類的應用容器。如前所述,在靜態語境下呼叫 facade 類的方法,會觸發 __callStatic
方法。該方法會用 getFacadeAccessor()
返回的資料識別容器內的服務,並試圖獲取之。在 Laravel 之外使用 facade 基類時,容器物件並不是自動設定的,需要手動設定。
為此,使用 facade 基類的 setFacadeApplication
方法,可以設定 facade 類的應用容器。
在 app.php
檔案,新增以下程式碼:
<?php
Illumiante\Support\Facade::setFacadeApplication($app);
這會給繼承自 facade 基類的所有 facades 設定容器。
現在,無需直接從容器獲取服務,我們可以使用剛剛建立的 facade 類來獲取,該類還允許我們呼叫靜態語境下的所有方法。
實現別名
為了給 facade 類建立別名,我們將使用之前介紹過的 AliasLoader
。AliasLoader
類由 illuminate\foundation
包提供,可以下載整個包,也可以拷貝部分程式碼保持為檔案。
如果你想拷貝原始檔,建議將其儲存在 src/Facades
目錄下。你可以根據專案的結構為 AliasLoader
類建立名稱空間。
在本例中,我們將拷貝程式碼並將其儲存在 app/facades
名稱空間下。
建立別名陣列
在 config
目錄下建立 aliases.php
檔案,並填入 alias-facade 繫結:
<?php
return [
'FancyName' => 'App\Facades\SomeService',
];
FancyName
是我們給 App\Facades\SomeService
建立的別名。
註冊別名
AliasLoader
是一種單例服務。要建立或得到別名載入器(alias loader)的例項,需呼叫 getInstance
方法並以別名陣列為引數。最後,為了註冊這些別名,需呼叫其 register
方法。
再次開啟 app.php
檔案,加入以下程式碼:
<?php
// ...
$aliases = require __DIR__ . '/../../config/aliases.php';
App\Facades\AliasLoader::getInstance($aliases)->register();
現在,大功告成了!我們可以這樣使用該服務:
<?php
FancyName::methodName();
進行包裝
一個 Facade 類只需實現 getFacadeAccessor
方法即可,後者會返回容器內的服務名。若要在 Laravel 環境外使用 facade,必須使用 setFacadeApplication()
方法明確設定服務容器。
要引用 facade 類,我們可以使用全限定類名或使用 PHP 的 use
指令匯入之。或者,遵循 Laravel 給 facades 建立別名的方法,使用 alias loader。
原文連結:http://www.sitepoint.com/how-laravel-facades-work-and-how-to-use-them-elsewhere/ (作者:Reza Lavaryan)本文系 OneAPM 工程師編譯整理。
OneAPM for PHP 能夠深入到所有 PHP 應用內部完成應用效能管理 能夠深入到所有 PHP 應用內部完成應用效能管理和監控,包括程式碼級別效能問題的可見性、效能瓶頸的快速識別與追溯、真實使用者體驗監控、伺服器監控和端到端的應用效能管理。想閱讀更多技術文章,請訪問 OneAPM 官方技術部落格。
本文轉自 OneAPM 官方部落格
相關文章
- Laravel 5.8 新增FacadesLaravel
- Laravel 原始碼閱讀指南 -- FacadesLaravel原始碼
- 2.3 - Laravel - 5.6 - Facade - Facades Real-Time 機制Laravel
- 如何在 Laravel 中使用鎖Laravel
- Laravel如何優雅的使用SwooleLaravel
- 按月分表如何使用 Laravel 關聯模型Laravel模型
- 新手如何使用laravel安裝PhpSpreadsheetLaravelPHP
- Laravel 如何使用 Docker 快速架起 Echo Server(上)LaravelDockerServer
- Facades 原理 (程式碼執行流程分析)
- 如何在 Laravel 中靈活的使用 TraitLaravelAI
- Laravel10,Laravel廣播,Laravel-echo使用Laravel
- Laravel 如何在blade檔案中使用Vue元件LaravelVue元件
- 如何在laravel中使用Repository Pattern(倉庫模式)Laravel模式
- 如何使用 Laravel Collections 類編寫神級程式碼Laravel
- 如何快速使用 Heroku 來部署你的 Laravel 應用Laravel
- Laravel 中使用 Laravel-Excel 美化LaravelExcel
- Laravel 使用 RedisLaravelRedis
- laravel rabbitmq 使用LaravelMQ
- Laravel Policy 使用Laravel
- Facades 類別名設定流程 (class_alias)
- laravel使用EasyWeChat 使用Laravel
- 如何讓普通使用者也用上 Laravel-admin 。。Laravel
- 程式設計卡片 002 - Laravel 中如何使用 AdminLte程式設計Laravel
- Laravel 之道特別篇 4: Laravel-admin 關於如何使用圖示神器 IconfontLaravel
- Laravel 配合 jwt 使用LaravelJWT
- Laravel 下 Elasticsearch 使用LaravelElasticsearch
- Laravel佇列使用Laravel佇列
- laravel中使用jwtLaravelJWT
- Laravel使用event事件Laravel事件
- Laravel Faker 使用技巧Laravel
- Laravel Collection 基本使用Laravel
- Laravel Sanctum 的使用Laravel
- Laravel 之 Cookie 使用LaravelCookie
- Laravel 重度使用者,如何給 Lumen 新增便捷的命令操作Laravel
- laravel如何渲染模板字串Laravel字串
- Laravel passport 多端使用者使用LaravelPassport
- 如何使用 Laravel 的佇列機制?有哪些場景需要使用佇列 ?Laravel佇列
- 在非 laravel 專案中使用 laravel 的特性Laravel