Facades 類別名設定流程 (class_alias)

mjczz發表於2019-01-05

場景描述:

// web.php中
Route::get('/', function () {
    return view('welcome');
});
  • 為何能直接使用Route,其實是呼叫了Illuminate\Support\Facades\Route類。然後通過facade獲取物件執行物件方法(看我上一篇文章facade原理)
  • 為何呼叫Route也就呼叫了Illuminate\Support\Facades\Route類,這就是這篇文章的核心:
  • class_alias:為一個類建立別名

核心程式碼 類:Illuminate\Foundation\AliasLoader

public function load($alias)
    {
        if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
            $this->loadFacade($alias);

            return true;
        }

      // $alias來自於config/app.php中aliases陣列中的一個鍵值隊如:       
      // 'Route' => Illuminate\Support\Facades\Route::class 中的鍵“Route”
        if (isset($this->aliases[$alias])) {
            //'Route' => Illuminate\Support\Facades\Route::class,
            // class_alias:為一個類建立別名
            return class_alias($this->aliases[$alias], $alias);
        }
    }

具體流程如下:

  • 入口檔案index.php
    // 此處才包含了設定facade類別名的操作
    $response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
    );
  • 進入Illuminate\Foundation\Http\Kernel類(Kernel.php)

    /**
     * Handle an incoming HTTP request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function handle($request)
    {
        try {
            $request->enableHttpMethodParameterOverride();
            // 進入這行
            $response = $this->sendRequestThroughRouter($request);
        } catch (Exception $e) {
            $this->reportException($e);
    
            $response = $this->renderException($request, $e);
        } catch (Throwable $e) {
            $this->reportException($e = new FatalThrowableError($e));
    
            $response = $this->renderException($request, $e);
        }
    
        $this->app['events']->dispatch(
            new Events\RequestHandled($request, $response)
        );
    
        return $response;
    }
  • 進入方法sendRequestThroughRouter

    protected function sendRequestThroughRouter($request)
    {
        // 將request物件繫結到容器$app的instances陣列裡面,實現單例模式
        $this->app->instance('request', $request);
    
        // 實際執行了這行 unset(static::$resolvedInstance["request"]);
        Facade::clearResolvedInstance('request');
    
        // 重點:這裡的操作包含執行了Facade類的別名設定
        $this->bootstrap();
    
        return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                    ->then($this->dispatchToRouter());
    }
  • 進入bootstrap方法
    public function bootstrap()
    {
        if (! $this->app->hasBeenBootstrapped()) {
            // 執行容器例項$app裡面的bootstrapWith,攜帶引數是$this->bootstrappers()
            // $this->bootstrappers()最終返回的陣列是Kernel例項的屬性$bootstrappers
            // 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,
            // ];
            $this->app->bootstrapWith($this->bootstrappers());
        }
    }
  • 進入Illuminate\Foundation\Application類的bootstrapWith方法

    public function bootstrapWith(array $bootstrappers)
    {
    
        $this->hasBeenBootstrapped = true;
    
        foreach ($bootstrappers as $bootstrapper) {
            $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);
            // 當迴圈到\Illuminate\Foundation\Bootstrap\RegisterFacades::class
            // Illuminate\Foundation\Bootstrap\RegisterFacades解析出類的RegisterFacades的例項物件
            // 呼叫RegisterFacades的bootstrap方法
            $this->make($bootstrapper)->bootstrap($this);
    
            $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
        }
    }
  • 進入Illuminate\Foundation\Bootstrap\RegisterFacades類,進入bootstrap方法

    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        Facade::clearResolvedInstances();
    
        Facade::setFacadeApplication($app);
        // 這裡就是上面所說的 核心程式碼
        // 將config/app.php 裡的aliases陣列裡面的Facades類設定別名
        AliasLoader::getInstance(array_merge(
            $app->make('config')->get('app.aliases', []),
            $app->make(PackageManifest::class)->aliases()
        ))->register();
    }
  • 進入Illuminate\Foundation\AliasLoader類,執行文章開頭說得核心程式碼

相關文章