個人博客原文: http://www.qinblog.net/Articl...
laravel 提供了一個靈活的模式,那就是 facade 。框架內部的 DB、Auth、File 等功能也有相關的 facade 實現。那麼,該如何寫本身的 facade 呢?php
首先,facade 並非 laravel 獨有的東西,它就是設計模式中的外觀模式(Facade)。
固然,這裏就不長篇大論去討論外觀模式的定義了。這篇文章寫的很不錯 : 設計模式(九)外觀模式Facade(結構型)。
那麼,laravel 的 facade 作了什麼?
一樣的, laravel 實現了外觀模式的開關功能,而且使用魔術方法 __callstatic 實現了靜態方式調用、動態建立對象的功能。參考 (官方文檔)html
固然你可能以爲這些概念很抽象,都什麼玩意。那麼其實簡單的講,laravel 的 facade 就是將某些功能封裝成工具類,並且能以靜態方式調用工具類的方法。laravel
首先、以 laravel 5.1 框架,我以前寫過的 Geoip facade 爲例,說一下怎麼去創建本身的 facade。git
geoip 是一個能夠更具 IP 獲取國家、地域、城市信息的 PHP 擴展,基於 maxmind 數據庫。 github 在此。github
首先,爲 laravel 添加 geoip 擴展。
打開 composer.json,添加 "geoip2/geoip2": "~2.0" 到 require。
項目根目錄運行 composer update ( 須要安裝 composer )更新一下,geoip 的依賴和軟件包就被下載到 vendor 文件夾中了。 數據庫
而後下載 geoip 依賴的數據庫,免費庫的地址 : GeoLite2 json
我下載了 GeoLite2 Country 和 GeoLite2 City 庫,放到了 storage/geoipdb 中。bootstrap
在 app 目錄下新建 Facades 文件夾,裏面新建 Facades/GeoIP/GeoIP.php 和 Facades/GeoIP/Facade/GeoIP.php (建議每一個功能新建一個文件夾區分,好比我這裏給 GeoIP 新建一個文件夾,關於GeoIP 的東西全放到這裏)
注意,Facades/GeoIP 下的 GeoIP.php 是你要對 geoip 擴展進行封裝的類, Facades/GeoIP/Facade 下的 GeoIP.php 是你的 facade,用來給 laravel 解析使用,這兩個文件能夠不一樣名。設計模式
目錄結構如圖:app
Facades/GeoIP/Facade/GeoIP.php 以下
<?php namespace App\Facades\GeoIP\Facade; use Illuminate\Support\Facades\Facade; class GeoIP extends Facade { protected static function getFacadeAccessor() { return 'geoip'; } }
注意你的 facade 如今只有一個方法,返回了一個字符串 'geoip' , 這個字符串是一個標號,用來給 laravel 的服務提供者解析使用的。
Facades/GeoIP/GeoIP.php 以下(吐槽:寫的有點隨意)
<?php namespace App\Facades\GeoIP; use GeoIp2\Database\Reader; class GeoIP { /** * GeoIP country db path (base on storage_path). * * @var GeoIP */ private $_country_db = 'geoipdb/GeoLite2-Country.mmdb'; /** * GeoIP city db path (base on storage_path). * * @var GeoIP */ private $_city_db = 'geoipdb/GeoLite2-City.mmdb'; /** * Instance for GeoIP . * * @var GeoIP */ private $_instance; /** * Init instance. * */ public function init($mode) { switch ($mode) { case 'getCountry': $path = $this->_country_db; break; case 'getCity': $path = $this->_city_db; break; default: break; } $this->_instance = new Reader(storage_path($path)); } /** * Get Country infomations. * * @param String $ip * @return Array */ public function getCountry($ip) { $this->init(__FUNCTION__); $record = $this->_instance->country($ip); // 國家信息 $data['iso_code'] = $record->country->isoCode; $data['country_name'] = $record->country->name; $data['country_name_zh_cn'] = $record->country->names['zh-CN']; return $data; } /** * Get City infomations. * * @param String $ip * @return Array */ public function getCity($ip) { $this->init(__FUNCTION__); $record = $this->_instance->city($ip); $data['iso_code'] = $record->country->isoCode; $data['country_name'] = $record->country->name; $data['country_name_zh_cn'] = $record->country->names['zh-CN']; // 省、州信息 $data['sub_division_name'] = $record->mostSpecificSubdivision->name; $data['sub_division_name_zh_cn'] = $record->mostSpecificSubdivision->names['zh-CN']; $data['sub_division_code'] = $record->mostSpecificSubdivision->isoCode; // 城市信息 $data['city_name'] = $record->city->name; $data['postal_code'] = $record->postal->code; // 經緯度 $data['latitude'] = $record->location->latitude; $data['longitude'] = $record->location->longitude; return $data; } }
OK,如今 geoip 的經常使用功能已經封裝到方法中了。
完成了 facade 的建立和功能封裝,下面就要使用它了。本身建立的 facade 要在 laravel 使用是要進行註冊的,以便 laraval 在啓動時能自動注入依賴(請看 laravel 的依賴注入簡介 : laravel 依賴注入 學院君)
在 app/Providers 下新建 FacadesServiceProvider.php
能夠手動建,也能夠用 artisan 命令來生成,隨你喜歡。
app/Providers/FacadesServiceProvider.php 代碼以下:
<?php namespace App\Providers; use App\Service\ApiService; use Illuminate\Support\ServiceProvider; // include the class facade binded use App\Facades\GeoIP\GeoIP; class FacadesServiceProvider extends ServiceProvider { /** * 在容器中註冊綁定。 * * @return void */ public function register() { $this->app->singleton('geoip', function ($app) { return new GeoIP($app); }); } }
上面代碼可知,服務提供者註冊時會註冊一個單例,標號爲 'geoip',也就是咱們本身的 facade 返回的那個,而後回調函數會返回一個對象,也就是咱們封裝 geoip 功能的那個類的實例,不明白的同窗能夠看看 laravel 的服務提供者和服務容器相關知識哦。(注意要 use 將 facade 和封裝類的命名空間引用一下哦)
laravel 5.1 以上版本的話, config/app.php 中找到 providers 和 aliases ,將你的服務提供者和 facade 別名配置一下 :
providers 加入 :
App\Providers\FacadeServiceProvider::class,
aliases 加入(不用每次都寫很長的命名空間前綴) :
'GeoIP' => App\Facades\GeoIP\Facade\GeoIP::class,
對於 lumen 5.2 以上,須要在 bootstrap/app.php 中添加
$app->register(App\Providers\FacadesServiceProvider::class);
註冊完畢後,每次使用 facade::function 的時候,laravel 會自動解析 facade, 而後建立一個對象給用戶使用,,而無需用戶本身去 new 一個對象出來。
如今,在任何一個控制器,或者路由的回調函數中,使用
$res = GeoIP::getCountry('75.101.195.215'); var_dump($res);
你會發現,facade 已經能夠好好工做了,enjoy!
【1】設計模式(九)外觀模式Facade(結構型)
【2】Laravel 服務容器實例教程 —— 深刻理解控制反轉(IoC)和依賴注入(DI)
【3】Laravel 服務提供者實例教程 —— 建立 Service Provider 測試實例