Laravel 控制反轉和門面模式概念詳解
這兩個概念對于 Laravel 的使用者來說應該并不陌生,尤其是當你希望擴展或者替換 Laravel 核心庫的時候,理解和合理使用它們可以極大提升 Laravel 的戰斗力。這里以創建一個自己的 ServiceProvider 為例理解 Inversion of Control 和 Facade 在 Laravel 中的應用。
控制反轉(Inversion of Control)
什么是 IoC
控制反轉(Inversion of Control,縮寫為IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用傳遞給它。 — 維基百科
</blockquote>簡單說來,就是一個類把自己的的控制權交給另外一個對象,類間的依賴由這個對象去解決。依賴注入屬于依賴的顯示申明,而依賴查找則是通過查找來解決依賴。
Laravel 中的使用
注入一個類:
App::bind('foo', function($app) { return new FooBar; });這個例子的意思是創建一個別名為 foo 的類,使用時實際實例化的是 FooBar。
使用這個類的方法是:
$value = App::make('foo');$value 實際上是 FooBar 對象。
如果希望使用單例模式來實例化類,那么使用:
App::singleton('foo', function() { return new FooBar; });這樣的話每次實例化后的都是同一個對象。
注入類的更多例子可以看 Laravel 官網
你可能會疑問上面的代碼應該寫在哪兒呢?答案是你希望他們在哪兒運行就寫在哪兒。0 —— 0 知道寫哪兒還用來看這種基礎文章么!
服務提供器 (Service Providers)
為了讓依賴注入的代碼不至于寫亂,Laravel 搞了一個 服務提供器(Service Provider)的東西,它將這些依賴聚集在了一塊,統一申明和管理,讓依賴變得更加容易維護。
Laravel 中的使用
定義一個服務提供器:
use Illuminate\Support\ServiceProvider;class FooServiceProvider extends ServiceProvider {
public function register() { $this->app->bind('foo', function() { return new Foo; }); }
}</pre>
這個代碼也不難理解,就是申明一個服務提供器,這個服務提供器有一個 register的方法。這個方法實現了我們上面講到的依賴注入。
當我們執行下面代碼:
App::register('FooServiceProvider');我們就完成一個注入了。但是這個還是得手動寫,所以怎么讓 Laravel 自己來做這事兒呢?
我們只要在 app/config/app.php 中的 providers 數組里面增加一行:
'providers' => [ … ‘FooServiceProvider’, ],這樣我們就可以使用 App::make(‘foo’) 來實例化一個類了。
你不禁要問了,這么寫也太難看了吧?莫慌,有辦法。
門面模式(Facade)
為了讓 Laravel 中的核心類使用起來更加方便,Laravel實現了門面模式。
外觀模式(Facade pattern),是軟件工程中常用的一種軟件設計模式,它為子系統中的一組接口提供一個統一的高層接口,使得子系統更容易使用。 — 維基百科
</blockquote>Laravel 中的使用
我們使用的大部分核心類都是基于門面模式實現的。例如:
$value = Cache::get('key');這些靜態調用實際上調用的并不是靜態方法,而是通過 PHP 的魔術方法__callStatic() 講請求轉到了相應的方法上。
那么如何講我們前面寫的服務提供器也這樣使用呢?方法很簡單,只要這么寫:
use Illuminate\Support\Facades\Facade;class Foo extends Facade {
protected static function getFacadeAccessor() { return ‘foo’; }
}</pre>
這樣我們就可以通過 Foo::test() 來調用我們之前真正的 FooBar 類的方法了。
別名(Alias)
有時候我們可能將 Facade 放在我們擴展庫中,它有比較深的命名空間,如:\Library\MyClass\Foo。這樣導致使用起來并不方便。Laravel 可以用別名來替換掉這么長的名字。
我們只要在 app/config/app.php 中 aliases 下增加一行即可:
'aliases' => [ … 'Foo' => ‘Library\MyClass\Foo’, ],這樣它的使用就由 \Library\MyClass\Foo::test() 變成 Foo::test() 了。
總結
所以有了控制反轉(Inversion of Control)和門面模式(Facade),實際還有服務提供器(Service Providers)和別名(Alias),我們創建自己的類庫和擴展 Laravel 都會方便很多。
這里總結一下創建自己類庫的方法:
- 在 app/library/MyFoo 下創建類 MyFoo.php
- 在 app/library/MyFoo/providers 下創建 MyFooServiceProvider.php
- 在 app/library/MyFoo/facades 下創建 MyFooFacade.php
- 在 app/config/app.php 中添加 providers 和 aliases
</ol> 來源:閆肅的博客