剛剛開始學(xué)Laravel就會(huì)接觸到路由

1
2
3
Route::get('/'function () {
    return view('welcome');
});

后來筆者一本正經(jīng)的去讀過Route類的代碼,驚訝的發(fā)現(xiàn)并沒有g(shù)et這個(gè)方法,之后了解到Laravel用了Facade模式。

Facade本質(zhì)上是一個(gè)“把工作推給別人做的”的類。

Facade存在的價(jià)值,可以從服務(wù)容器談起。服務(wù)容器,可見我的另一篇博文,地址:http://www.cnblogs.com/sweng/p/6430374.html

舉個(gè)例子,不知道大家以前寫代碼有沒有過obj->method(arg1,arg2)->func(arg3,arg4);的體驗(yàn)。學(xué)過服務(wù)容器的讀者知道,這行代碼就是把服務(wù)容器里的對(duì)象取出來,并調(diào)用他的方法。這對(duì)熟悉服務(wù)容器里注冊(cè)過哪些類的開發(fā)人員來說,這種代碼還是可以接受的。但是如果像路由定義那樣,也要寫成這樣冗長(zhǎng)的形式,實(shí)在太不優(yōu)雅了。所以用Facade模式可以很好的精簡(jiǎn)代碼長(zhǎng)度。

我們先寫一個(gè)DB類

1
2
3
4
5
6
7
8
9
10
11
12
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;
    }
}

數(shù)據(jù)庫(kù)讀寫是整個(gè)系統(tǒng)非常常用的操作。但是DB類會(huì)注冊(cè)在服務(wù)容器里,每次數(shù)據(jù)庫(kù)讀寫都要把DB類的對(duì)象從服務(wù)容器里取出,實(shí)在很不方便。

我們寫一個(gè)Facade類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);
    }
}

要理解這個(gè)類,我們只要關(guān)注最后一個(gè)函數(shù),就是__callstatic魔術(shù)方法。這個(gè)方法就是Facade類型對(duì)象在調(diào)用他自身沒有定義過的函數(shù)時(shí),就會(huì)調(diào)用__callstatic方法,是一個(gè)“候選人”的角色。

我們?cè)俣x一個(gè)DBFacade類

1
2
3
4
5
class DBFacade extends Facade{
    public static function getFacadeAccessor(){
        return API\DB::class;
    }
}

每一個(gè)Facade子類都要實(shí)現(xiàn)getFacadeAccessor方法,返回只是一個(gè)類名字符串,用來代入getInstance方法,來創(chuàng)建一個(gè)真正“做事情”的類。

此時(shí),F(xiàn)acade已經(jīng)可以用了,我們調(diào)用DBFacade的靜態(tài)方法

1
DBFacade::Write('hello');

閱讀代碼,我們發(fā)現(xiàn),其實(shí)DBFacade是沒有Write方法的,于是就調(diào)用他父類Facade的__callstatic魔術(shù)方法,魔術(shù)方法我們已經(jīng)在父類里面實(shí)現(xiàn)了。

以前聽過同行抱怨,PHP語(yǔ)法亂,難記。但實(shí)際上像魔術(shù)方法把Facade實(shí)現(xiàn)的非常簡(jiǎn)潔,可見語(yǔ)法設(shè)計(jì)的精妙。