剛剛開始學Laravel就會接觸到路由
Route::get('/', function () { return view('welcome'); });
后來筆者一本正經的去讀過Route類的代碼,驚訝的發現並沒有get這個方法,之后了解到Laravel用了Facade模式。
Facade本質上是一個“把工作推給別人做的”的類。
Facade存在的價值,可以從服務容器談起。服務容器,可見我的另一篇博文,地址:http://www.cnblogs.com/sweng/p/6430374.html
舉個例子,不知道大家以前寫代碼有沒有過obj->method(arg1,arg2)->func(arg3,arg4);的體驗。學過服務容器的讀者知道,這行代碼就是把服務容器里的對象取出來,並調用他的方法。這對熟悉服務容器里注冊過哪些類的開發人員來說,這種代碼還是可以接受的。但是如果像路由定義那樣,也要寫成這樣冗長的形式,實在太不優雅了。所以用Facade模式可以很好的精簡代碼長度。
我們先寫一個DB類
namespace API; class DB{ public function __construct($args){ } public function Write($str){ echo 'Write:'.$str.PHP_EOL; } public function Read($str){ echo 'Read:'.$str.PHP_EOL; } }
數據庫讀寫是整個系統非常常用的操作。但是DB類會注冊在服務容器里,每次數據庫讀寫都要把DB類的對象從服務容器里取出,實在很不方便。
我們寫一個Facade類
class Facade{ public function __construct(){ // } public static function getInstance($classname,$args){ return new $classname($args); } public static function getFacadeAccessor(){ // } public static function __callstatic($method,$arg){ $instance=static::getInstance(static::getFacadeAccessor(),[1,2,3]); return call_user_func_array(array($instance,$method),$arg); } }
要理解這個類,我們只要關注最后一個函數,就是__callstatic魔術方法。這個方法就是Facade類型對象在調用他自身沒有定義過的函數時,就會調用__callstatic方法,是一個“候選人”的角色。
我們再定義一個DBFacade類
class DBFacade extends Facade{ public static function getFacadeAccessor(){ return API\DB::class; } }
每一個Facade子類都要實現getFacadeAccessor方法,返回只是一個類名字符串,用來代入getInstance方法,來創建一個真正“做事情”的類。
此時,Facade已經可以用了,我們調用DBFacade的靜態方法
DBFacade::Write('hello');
閱讀代碼,我們發現,其實DBFacade是沒有Write方法的,於是就調用他父類Facade的__callstatic魔術方法,魔術方法我們已經在父類里面實現了。
以前聽過同行抱怨,PHP語法亂,難記。但實際上像魔術方法把Facade實現的非常簡潔,可見語法設計的精妙。