場景描述:
// 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類,執行文章開頭說得核心程式碼