這兩個概念對於 Laravel 的使用者來講應該並不陌生,尤爲是當你但願擴展或者替換 Laravel 核心庫的時候,理解和合理使用它們能夠極大提高 Laravel 的戰鬥力。這裏以建立一個本身的 ServiceProvider 爲例理解 Inversion of Control 和 Facade 在 Laravel 中的應用。php
控制反轉(Inversion of Control,縮寫爲IoC),是面向對象編程中的一種設計原則,能夠用來減低計算機代碼之間的耦合度。其中最多見的方式叫作依賴注入(Dependency Injection,簡稱DI),還有一種方式叫「依賴查找」(Dependency Lookup)。經過控制反轉,對象在被建立的時候,由一個調控系統內全部對象的外界實體,將其所依賴的對象的引用傳遞給它。 — 維基百科html
簡單說來,就是一個類把本身的的控制權交給另一個對象,類間的依賴由這個對象去解決。依賴注入屬於依賴的顯示申明,而依賴查找則是經過查找來解決依賴。laravel
注入一個類:編程
App::bind('foo', function($app) { return new FooBar; });
這個例子的意思是建立一個別名爲 foo 的類,使用時實際實例化的是 FooBar。數組
使用這個類的方法是:app
$value = App::make('foo');
$value 其實是 FooBar 對象。ide
若是但願使用單例模式來實例化類,那麼使用:this
App::singleton('foo', function() { return new FooBar; });
這樣的話每次實例化後的都是同一個對象。spa
注入類的更多例子能夠看 Laravel 官網設計
你可能會疑問上面的代碼應該寫在哪兒呢?答案是你但願他們在哪兒運行就寫在哪兒。0 —— 0 知道寫哪兒還用來看這種基礎文章麼!
爲了讓依賴注入的代碼不至於寫亂,Laravel 搞了一個 服務提供器(Service Provider)的東西,它將這些依賴彙集在了一塊,統一申明和管理,讓依賴變得更加容易維護。
定義一個服務提供器:
use Illuminate\Support\ServiceProvider; class FooServiceProvider extends ServiceProvider { public function register() { $this->app->bind('foo', function() { return new Foo; }); } }
這個代碼也不難理解,就是申明一個服務提供器,這個服務提供器有一個 register的方法。這個方法實現了咱們上面講到的依賴注入。
當咱們執行下面代碼:
App::register('FooServiceProvider');
咱們就完成一個注入了。可是這個仍是得手動寫,因此怎麼讓 Laravel 本身來作這事兒呢?
咱們只要在 app/config/app.php 中的 providers 數組裏面增長一行:
'providers' => [ … ‘FooServiceProvider’, ],
這樣咱們就能夠使用 App::make(‘foo’) 來實例化一個類了。
你不由要問了,這麼寫也太難看了吧?莫慌,有辦法。
爲了讓 Laravel 中的核心類使用起來更加方便,Laravel實現了門面模式。
外觀模式(Facade pattern),是軟件工程中經常使用的一種軟件設計模式,它為子系統中的一組接口提供一個統一的高層接口,使得子系統更容易使用。 — 維基百科
咱們使用的大部分核心類都是基於門面模式實現的。例如:
$value = Cache::get('key');
這些靜態調用實際上調用的並非靜態方法,而是經過 PHP 的魔術方法__callStatic() 講請求轉到了相應的方法上。
那麼如何講咱們前面寫的服務提供器也這樣使用呢?方法很簡單,只要這麼寫:
use Illuminate\Support\Facades\Facade; class Foo extends Facade { protected static function getFacadeAccessor() { return ‘foo’; } }
這樣咱們就能夠經過 Foo::test() 來調用咱們以前真正的 FooBar 類的方法了。
有時候咱們可能將 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 都會方便不少。
這裏總結一下建立本身類庫的方法: