Laravel 配置項即時載入的服務提供者

Laravel 配置項即時載入的服務提供者 (根目錄:/var/www/laravel/)

全部即時載入的服務註冊完成以後,會當即調用 register 方法,並標記爲已載入。
隨後經過 \Illuminate\Foundation\Bootstrap\BootProviders 啓動項來調用全部的即時加載服務提供者的 boot 方法

查看根據 config/app.php 中的 providers 生成的 bootstrap/cache/services.php
'eager' => 
  array (
    // 系統服務提供者
    0 => 'Illuminate\\Auth\\AuthServiceProvider',                       // 注入驗證相關對象
    1 => 'Illuminate\\Cookie\\CookieServiceProvider',                   // 注入cookie對象
    2 => 'Illuminate\\Database\\DatabaseServiceProvider',               // 注入db相關對象
    3 => 'Illuminate\\Encryption\\EncryptionServiceProvider',           // 注入加解密對象
    4 => 'Illuminate\\Filesystem\\FilesystemServiceProvider',           // 注入文件相關對象
    5 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',// 注入基礎的請求對象
    6 => 'Illuminate\\Notifications\\NotificationServiceProvider',      // 注入通知對象
    7 => 'Illuminate\\Pagination\\PaginationServiceProvider',           // 注入分頁相關對象
    8 => 'Illuminate\\Session\\SessionServiceProvider',                 // 注入session相關對象
    9 => 'Illuminate\\View\\ViewServiceProvider',                       // 注入視圖相關對象
    10 => 'Laravel\\Passport\\PassportServiceProvider',                 // 注入passport相關對象
    
    // 配置項服務提供者
    11 => 'App\\Providers\\AppServiceProvider',
    12 => 'App\\Providers\\AuthServiceProvider',
    13 => 'App\\Providers\\EventServiceProvider',
    14 => 'App\\Providers\\RouteServiceProvider',
  )

路由相關服務提供者

// 主要是註冊完以後的 boot 方法調用
App\\Providers\\RouteServiceProvider
public function boot()
{
    // 能夠加入本身的操做
    parent::boot();
}
public function boot()
{
    $this->setRootControllerNamespace();
    // 若執行了 php artisan routes:cache(自動生成路由緩存文件,注意:建議只在項目上線時操做),直接加載 
    if ($this->app->routesAreCached()) {
        $this->loadCachedRoutes();
    } else {
        // 加載路由
        $this->loadRoutes();
        // 設置系統啓動時的事件監聽函數
        $this->app->booted(function () {
            $this->app['router']->getRoutes()->refreshNameLookups();
        });
    }
}
protected function setRootControllerNamespace()
{
    if (! is_null($this->namespace)) {
        // 設置 $this->instances['url'] (\Illuminate\Routing\UrlGenerator對象)的 rootNamespace 屬性
        $this->app[UrlGenerator::class]->setRootControllerNamespace($this->namespace);
    }
}
public function routesAreCached()
{
    return $this['files']->exists($this->getCachedRoutesPath());
}
public function getCachedRoutesPath()
{
    return $this->bootstrapPath().'/cache/routes.php';
}
protected function loadRoutes()
{
    if (method_exists($this, 'map')) {
        $this->app->call([$this, 'map']);
    }
}
public function map()
{
    $this->mapApiRoutes();
    $this->mapWebRoutes();
}
// API 相關的路由
protected function mapApiRoutes()
{
    Route::prefix('api')
         ->middleware('api')
         ->namespace($this->namespace)
         ->group(base_path('routes/api.php'));
}
// WEB 相關的路由
protected function mapWebRoutes()
{
    Route::middleware('web')
         ->namespace($this->namespace)
         ->group(base_path('routes/web.php'));
}
public function booted($callback)
{
    $this->bootedCallbacks[] = $callback;
    // 若是應用已經啓動了,則直接調用
    if ($this->isBooted()) {
        $this->fireAppCallbacks([$callback]);
    }
}

// Route 是 Facde 的調用方式
分析: Route::middleware('web')
        ->namespace($this->namespace)
        ->group(base_path('routes/web.php'));

Route::middleware
public static function __callStatic($method, $args)
{
    // 獲取應用的 router 對象
    $instance = static::getFacadeRoot();

    if (! $instance) {
        throw new RuntimeException('A facade root has not been set.');
    }
    // 將 Router::middleware() 轉化爲應用的 Router->middleware() 方式,若 Router 沒有 middleware 方法,則直接觸發 __call
    return $instance->$method(...$args);
}
public function __call($method, $parameters)
{
    if (static::hasMacro($method)) {
        return $this->macroCall($method, $parameters);
    }
    // 將不存在的方法的調用委託給 RouteRegistrar 處理,
    return (new RouteRegistrar($this))->attribute($method, $parameters[0]);
}
public function attribute($key, $value)
{
    // 只容許指定的屬性設置($allowedAttributes = ['as', 'domain', 'middleware', 'name', 'namespace', 'prefix',])
    if (! in_array($key, $this->allowedAttributes)) {
        throw new InvalidArgumentException("Attribute [{$key}] does not exist.");
    }
    // 支持.方式來存放屬性
    $this->attributes[array_get($this->aliases, $key, $key)] = $value;

    return $this;
}
public function group($callback)
{
    $this->router->group($this->attributes, $callback);
}
public function group(array $attributes, $routes)
{
    $this->updateGroupStack($attributes);
    $this->loadRoutes($routes);
    array_pop($this->groupStack);
}
protected function loadRoutes($routes)
{
    if ($routes instanceof Closure) {
        $routes($this);
    } else {
        $router = $this;
        require $routes;
    }
}

小結php

Route::middleware('web')
        ->namespace($this->namespace)
        ->group(base_path('routes/web.php'));
        
實際就是將 middleware namespace 加入到 RouteRegistrar 對象裏面的 attributes 數組屬性,並返回
RouteRegistrar 對象,再調用 RouteRegistrar 對象的 group 方法,也就是調用 router 對象的 group
方法。最終就是將['middleware' => 'web', 'namespace' => $this->namespace] 數組設置給 
$this->router 的groupStack 屬性(將運用到全部的路由),再加載 config/web.php。
相關文章
相關標籤/搜索