laravel5.5源碼筆記(3、門面類facade)

上次說了provider,那麼此次來講說facadephp

首先是啓動的源頭,從laravel的kernel類中的$bootstrappers 數組,咱們能夠看到它的一些系統引導方法,其中的RegisterFacades即是用來註冊facade門面類的了。前端

    protected $bootstrappers = [
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
        \Illuminate\Foundation\Bootstrap\BootProviders::class,
    ];

 

 一樣是有一個register類,經過這個類進行別名等註冊操做laravel

namespace Illuminate\Foundation\Bootstrap;

use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Facade;
use Illuminate\Foundation\PackageManifest;
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全部已綁定實例
        Facade::clearResolvedInstances();
        //將app存入對象
        Facade::setFacadeApplication($app);
        //將這些別名數組經過構造函數存入對象中
        AliasLoader::getInstance(array_merge(
            //經過Illuminate\Config\Repository獲取config/app.php中的aliases數組
            $app->make('config')->get('app.aliases', []),
            //還記得最開始的博文中提到的那個包清單嗎,這裏也從中獲取了它的aliases
            $app->make(PackageManifest::class)->aliases()
        //經過spl_autoload_register函數註冊另外一種自動加載函數
        ))->register();
    }
}
    public static function getInstance(array $aliases = [])
    {
        //註冊時的實例是空的,會經過構造方法把剛剛傳入的別名數組存入對象
        if (is_null(static::$instance)) {
            return static::$instance = new static($aliases);
        }

        $aliases = array_merge(static::$instance->getAliases(), $aliases);

        static::$instance->setAliases($aliases);

        return static::$instance;
    }

    private function __construct($aliases)
    {
        $this->aliases = $aliases;
    }
    public function register()
    {
        if (! $this->registered) {
            $this->prependToLoaderStack();

            $this->registered = true;
        }
    }

    /**
     * Prepend the load method to the auto-loader stack.
     *
     * @return void
     */
    protected function prependToLoaderStack()
    {
        //最後經過自動加載函數將本對象中的load方法放入自動加載隊列的前端,在咱們經過類名調用方法時,會觸發自動加載函數隊列,會優先觸發這個函數,查找到對應文件的路徑而後加載相應文件
        spl_autoload_register([$this, 'load'], true, true);
    }
    public function load($alias)
    {
        //若傳入的命名空間不爲當前facade數組內纔會經過這個方法加載
        if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
            $this->loadFacade($alias);

            return true;
        }
        //不然直接返回其別名
        if (isset($this->aliases[$alias])) {
            return class_alias($this->aliases[$alias], $alias);
        }
    }

    /**
     * Load a real-time facade for the given alias.
     *
     * @param  string  $alias
     * @return void
     */
    protected function loadFacade($alias)
    {
        require $this->ensureFacadeExists($alias);
    }

    /**
     * Ensure that the given alias has an existing real-time facade class.
     *
     * @param  string  $alias
     * @return string
     */
    protected function ensureFacadeExists($alias)
    {
        //從緩存中返回路徑
        if (file_exists($path = storage_path('framework/cache/facade-'.sha1($alias).'.php'))) {
            return $path;
        }
        
        file_put_contents($path, $this->formatFacadeStub(
            $alias, file_get_contents(__DIR__.'/stubs/facade.stub')
        ));

        return $path;
    }

 因爲laravel中composer的執行過程過於繁瑣,這裏就不作深究了。原理是同樣的,經過別名找到命名空間的類名,再由composer的類名與文件路徑映射關係,自動加載函數找到相應文件加載進來。bootstrap

 

那麼咱們來自定義一個門面類試一下數組

一、新建一個facade類,這裏返回的test是上一篇博客中定義的對象緩存

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class Test extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'App\Contracts\Test';
    }
}

二、將它添加到config/app.php的aliases別名數組中app

'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
        //剛剛新建的facades
        'Test' => \App\Facades\Test::class,
    ],

三、在路由文件中調用它composer

Route::any('/index', function (){
    Test::doing();
});

咱們會發現,即便咱們沒有經過app對象進行make也沒有任何命名空間的引入,它就這樣被調用了。ide

若是是在類中調用,那麼就要麻煩一些了,須要ues這個別名,注意這一點函數

namespace App\Http\Controllers;

use Illuminate\Http\Request;
//use App\Contracts\Test;
//注意這裏只引入了別名,因爲命名空間衝突,因此我註釋了其餘部分
use Test;

class IndexController extends Controller
{
//    public function __construct(Test $test)
//    {
//        $this->test = $test;
//    }

    public function index(Test $test)
    {
        Test::doing();
//        app()->make('App\Contracts\Test')->doing();
//        echo '<br>';
//
//        //只有經過構造方法進行自動加載依賴的方式才能觸發契約的when綁定
//        $this->test->doing();
//
//        echo '<br>';
//        //由於laravel中的上下文綁定只能具體到類,因此這裏的$test實例依然爲普通綁定
//        $test->doing();

    }
}

 經過這個demo的實踐,facade仍是比較簡單的。

相關文章
相關標籤/搜索