Laravel源碼入門-啓動引導過程(九)RegisterFacades

上篇:Laravel源碼入門-啓動引導過程(八)HandleExceptions

上文介紹了 HandleExceptions,在 《Laravel源碼入門-啓動引導過程(五)$kernel->handle($request)》中第四個要載入的是 RegisterFacades,也就是 Foundation\Http\Kernel::bootstrapers[] 的第四個

\Illuminate\Foundation\Bootstrap\RegisterFacades::class, 如下:

// Illuminate\Foundation\Http\Kernel.php 片段

   /**
     * The bootstrap classes for the application.
     * 引導類,起引導作用的類
     *
     * @var array
     */
    protected $bootstrappers = [
        // 載入服務器環境變量(.env 文件)
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
        // 載入配置信息(config 目錄)
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
        // 配置如何處理異常
        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
        // 註冊 Facades
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
        // 註冊 Providers
        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
        // 啓動 Providers
        \Illuminate\Foundation\Bootstrap\BootProviders::class,
    ];

我們再直接貼出 RegisterFacades 類的代碼,進行分析,非常直觀,如下

<?php

namespace Illuminate\Foundation\Bootstrap;

use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Facade;
use Illuminate\Contracts\Foundation\Application;

class RegisterFacades
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        Facade::clearResolvedInstances();

        Facade::setFacadeApplication($app);

        AliasLoader::getInstance($app->make('config')->get('app.aliases', []))->register();
    }
}

代碼雖然直觀,但是對於Laravel的初學者,有個問題是難以理解它的一些概念,Facade就是其一。少於程序語言能夠做這樣的概念的重構,有點做博士論文的味道,以至於我們所說的Laravel的學習曲線長,主要就是因爲學術味道過於濃重,無法上手就用。

來看看Facade,collins詞典的解釋是:The facade of a building, especially a large one, is its front wall or the wall that faces the street.用來說明建築,那麼建築的facade是什麼呢,是他的前牆面,所謂”前牆面“實際是臨街的一面,很清楚了,通俗說建築的外立面。

谷歌出來的Facade的圖片大多是這裏圖片呈現的樣子,可以看到,建築的外立面是需要重點裝飾的,以至於我們可以通過說某個建築外面立的樣子來明顯定位他。下面具體說。我們來看看大家舉例子時,對於facade的經典例程,如下:

 

Cache::get('akey');

先說這句代碼的意思,表面看是我們一般理解的,Cache類的一個靜態方法get(),返回的是通過get()獲取鍵值爲‘akey’的值。但是實際上,這裏的Cache不是緩存類,get()也不是Cache類的靜態方法,甚至不是Cache類的方法。那到底是什麼呢?

我們接着外立面的概念,虛擬一個類吧,Illuminate\Foundation\Building,建築物類,假如是 laravel 的 Illuminate的基礎類中的一個類。再虛擬一個類,Illumniate\Supports\Facades\Building,這個不叫建築物類了,我們把它叫做建築物外立面類。它位於 Illuminiate支持中的 Facades中。如果說我們要寫得更清晰的話,可以使用這樣寫:

Illuminate\Foundation\BuildingFoundation;

Illumniate\Supports\Facades\BuildingFacade;

當然因爲有 namespace 的使用,我們就不用謝後綴的同義反復了。粗淺理解,我們本身有BuildingFoundation,再給建築外面加個殼子,就成爲BuildingFacade,當都建成以後,我們再去稱呼他們時,往往會用 他的外殼,或者說外觀的樣子來做代詞指代,比如 鳥巢和水立方,實際上他們是國家體育場(http://www.n-s.cn/)和國家游泳中心(www.water-cube.com/cn)的Facade。順理成章了,當我們以 BuildFacade::get()使用時,實際上BuildFacade沒有這個方法,而是調用的 BuildFoundation的get()方法。

這樣做有什麼好處呢,一般認爲是便於可測試性與降低耦合性,說得直白一些,就像說鳥巢和水立方,比說國家體育場和國家游泳中心更方便,和更具有好的辨認性一樣。更進一步,在複雜的應用容器中,對象如星空浩繁,數量龐大,大項目更是如此,如何那麼容易就能提取出、表達出某個對象呢,靠傳參數、傳指針的方式,已經讓我們搞得暈頭轉向,到不如,給他做個殼子(Facade)讓他更好提取出來,所有耦合性也就降低了。實際上,真正的耦合性沒有降低,或者說,根本不是降低了真正的業務邏輯上的耦合性,而是laravel找到一個簡便有效的辦法可以訪問需要訪問的功能或對象而已。

總結一句,BuildingFacade 更容易地解析(make())出需要的對象 BuildingFoundation。

=======

瞭解了 Facade,讓我們再次回到具體 的 RegisterFacades 代碼清單:

<?php

namespace Illuminate\Foundation\Bootstrap;

use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Facade;
use Illuminate\Contracts\Foundation\Application;

class RegisterFacades
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        // 第一步:清空所有已經解析的實例,源代碼就一句:
        // static::$resolvedInstance = [];見 Illuminate\Support\Facades\Facade.php

        Facade::clearResolvedInstances();

        // 第二步:設置 $app,源代碼也是一句:
        // static::$app = $app;

        Facade::setFacadeApplication($app);

        // 第三步:獲取應用配置信息->獲取Facade類別名->獲取別名下的實例->註冊實例
        // 下面是源代碼,我們格式化一下,便於閱讀和查看:
        // AliasLoader::getInstance($app->make('config')->get('app.aliases', []))->register();
        
        // 3.1 獲取配置信息庫(Illuminate\Cache\Repository.php)
        $config = $app->make('config');
        dump($config);
        
        // 3.2 獲取配置庫中的 app.aliases 所有Facade別名
        $aliases = $config->get('app.aliases', []);
        dump($aliases);

        // 3.3 有Facade別名獲取別名實例(如果沒有就創建:new static())
        $instance = AliasLoader::getInstance($aliases);
        // 查看註冊前的 $instance。
        dump($instance);

        // 3.4 註冊實例(看源碼使用了spl_autoload_register([$this, 'load'], true, true);)
        $instances->register();
        // 查看註冊後的 $instance。
        dump($instance);
    }
}

dump($config)結果:

dump($aliases)結果:所有的Facades(建築的外立面)

註冊前後dump($instance)結果:

附錄:Facade的官方介紹:https://laravel.com/docs/5.4/facades

反思:說到Facade之於我們來說,就是穴位之於中醫。中醫不像西醫,不知道也不想知道身體內的具體影像、或很細微的結構的東西,他就通過經脈,通過把脈知道病情,通過按摩具體穴位實現治癒功能。除此,Facade之於我們,也更像武林高手,點穴即可!點!點!Facade::xxx()!

反思:例子拓展:Facade都位於 Illuminate\Support\Facades\

仿造:https://laravel.com/docs/5.4/facades#facade-class-reference

Facade Class Service Container Binding 備註
NationalStadium Illuminate\Foundation\NationalStadium birdsnest http://www.n-s.cn/
NationalAquaticsCenter Illuminate\Foundation\NationalAquaticsCenter watercube http://www.water-cube.com/cn/

下篇:Laravel源碼入門-啓動引導過程(十)RegisterProviders

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章