Lumen開發:lumen原始碼解讀之初始化(1)——app例項

qq_26249609發表於2018-11-22

先來看看入口檔案public/index.php

//請求頭
header('Content-Type: application/json; charset=utf-8');
 
/*
 |--------------------------------------------------------------------------
 | Create The Application(建立應用程式)
 |--------------------------------------------------------------------------
 | 首先我們需要一個應用例項。
 | 這將建立一個應用程式的例項/容器和應用程式準備好接收HTTP /控制檯從環境要求。
 */
$app = require __DIR__.'/../bootstrap/app.php';
 
/*
 |--------------------------------------------------------------------------
 | Run The Application (執行應用程式)
 |--------------------------------------------------------------------------
 | 一旦我們有了應用程式,
 | 我們就可以通過核心處理傳入的請求,並將相關的響應傳送回客戶機的瀏覽器,
 | 讓他們享受我們為他們準備的創造性和奇妙的應用程式。
 */
$app->run();

那麼現在最重要的就是bootstrap/app.php了

require_once __DIR__ . '/../vendor/autoload.php';
 
try {
    (new Dotenv\Dotenv(__DIR__ . '/../'))->load();
} catch (Dotenv\Exception\InvalidPathException $e) {
    //
}

這裡是引入Composer的包,之前講過,這裡不詳談。Dotenv是env配置的使用。

/*
|--------------------------------------------------------------------------
| Create The Application(建立應用程式)
|--------------------------------------------------------------------------
|
| 在這裡,我們將載入環境並建立作為該框架的中心部分的應用程式例項。
| 我們將使用這個應用程式作為這個框架的“IOC”容器和路由器。
|
*/
 
$app = new Laravel\Lumen\Application(
    realpath(__DIR__ . '/../')
);
 
$app->withFacades();
 
$app->withEloquent();
Laravel\Lumen\Application

class Application extends Container
{
    use Concerns\RoutesRequests,
        Concerns\RegistersExceptionHandlers;
。
。
。

/**
  * Create a new Lumen application instance.(建立一個新的Lumen應用程式例項。)
  */
public function __construct($basePath = null)
{
    if (! empty(env('APP_TIMEZONE'))) {
        date_default_timezone_set(env('APP_TIMEZONE', 'UTC'));
    }
 
    $this->basePath = $basePath;
 
    $this->bootstrapContainer();
    $this->registerErrorHandling();
}

這個可以說是整個Lumen應用程式最最核心的類了,上繼承了核心容器類(Container),左右引用了Concerns\RoutesRequests(路由),Concerns\RegistersExceptionHandlers(異常處理),下又例項了app物件,很是重要喔!!!$this->bootstrapContainer();

/**
 * Bootstrap the application container.(引導應用程式容器)
 *
 * @return void
 */
protected function bootstrapContainer()
{
    static::setInstance($this);
 
    $this->instance('app', $this);
    $this->instance('Laravel\Lumen\Application', $this);
 
    $this->instance('path', $this->path());
 
    $this->registerContainerAliases();
}

Lumen的依賴注入服務主要都是在容器(Container)中進行,所以說這個步驟很重要,

先看看setInstance()函式

/**
 * Set the shared instance of the container.(設定容器的共享例項。)
 *
 * @param  \Illuminate\Contracts\Container\Container|null  $container
 * @return static
 */
public static function setInstance(ContainerContract $container = null)
{
    return static::$instance = $container;
}

簡單一句話,把當前繼承Container,實現ContainerContract介面的Application的app例項,註冊到Container的$instance物件中,感覺這樣就實現了相互之間的貫穿,後面會有大用!

然後就到了$this->instance()函式了,

/**
   * Register an existing instance as shared in the container.(登記一個現有的例項所共享的容器。)
   */
  public function instance($abstract, $instance)
  {
      $this->removeAbstractAlias($abstract);//從上下文繫結快取中刪除一個別名。
 
      unset($this->aliases[$abstract]);//刪除對應註冊型別別名。
 
       //檢查以確定此型別是否已被繫結,
      //如果有我們將觸發與容器註冊的回撥和反射可以消費類已經解決這裡的更新。
      $this->instances[$abstract] = $instance;

        if ($this->bound($abstract)) {  //確定給定的型別已被繫結。
            $this->rebound($abstract);
        }
  }
	//從上下文繫結快取中刪除一個別名。
    protected function removeAbstractAlias($searched)
    {
        if (! isset($this->aliases[$searched])) {
            return;
        }

        foreach ($this->abstractAliases as $abstract => $aliases) {
            foreach ($aliases as $index => $alias) {
                if ($alias == $searched) {
                    unset($this->abstractAliases[$abstract][$index]);
                }
            }
        }
    }
 	//確定給定的型別已被繫結。
    public function bound($abstract)
    {   
        return isset($this->bindings[$abstract]) ||
               isset($this->instances[$abstract]) ||
               $this->isAlias($abstract);
    }

再到$this->registerContainerAliases()函式,這個函式用於註釋核心容器的別名

protected function registerContainerAliases()
    {
        $this->aliases = [
            'Illuminate\Contracts\Foundation\Application' => 'app',
            'Illuminate\Contracts\Auth\Factory' => 'auth',
            'Illuminate\Contracts\Auth\Guard' => 'auth.driver',
            'Illuminate\Contracts\Cache\Factory' => 'cache',
            'Illuminate\Contracts\Cache\Repository' => 'cache.store',
            'Illuminate\Contracts\Config\Repository' => 'config',
            'Illuminate\Container\Container' => 'app',
            'Illuminate\Contracts\Container\Container' => 'app',
            'Illuminate\Database\ConnectionResolverInterface' => 'db',
            'Illuminate\Database\DatabaseManager' => 'db',
            'Illuminate\Contracts\Encryption\Encrypter' => 'encrypter',
            'Illuminate\Contracts\Events\Dispatcher' => 'events',
            'Illuminate\Contracts\Hashing\Hasher' => 'hash',
            'log' => 'Psr\Log\LoggerInterface',
            'Illuminate\Contracts\Queue\Factory' => 'queue',
            'Illuminate\Contracts\Queue\Queue' => 'queue.connection',
            'request' => 'Illuminate\Http\Request',
            'Laravel\Lumen\Routing\UrlGenerator' => 'url',
            'Illuminate\Contracts\Validation\Factory' => 'validator',
            'Illuminate\Contracts\View\Factory' => 'view',
        ];
    }

有木有對這些名稱很熟悉的感覺!

至此$this->bootstrapContainer()就執行完了,再來看看$this->registerErrorHandling(),既然是異常處理,肯定是在Laravel\Lumen\Concerns\RegistersExceptionHandlers(異常處理)裡了

/**
 * Set the error handling for the application.(設定應用程式的錯誤處理。)
 *
 * @return void
 */
protected function registerErrorHandling()
{
    error_reporting(-1);
 
    set_error_handler(function ($level, $message, $file = '', $line = 0) {
        if (error_reporting() & $level) {
            throw new ErrorException($message, 0, $level, $file, $line);
        }
    });
 
    set_exception_handler(function ($e) {
        $this->handleUncaughtException($e);
    });
 
    register_shutdown_function(function () {
        $this->handleShutdown();
    });
}

到這裡,$app應用程式就初始好了,下一篇會接著講

$app->withFacades();//為應用程式註冊門面。
 
$app->withEloquent();//為應用程式載入功能強大的庫。

和後面的內容!!!

相關文章