首頁  >  文章  >  php框架  >  ThinkPHP6源碼分析之應用初始化

ThinkPHP6源碼分析之應用初始化

藏色散人
藏色散人轉載
2019-08-01 14:21:583617瀏覽

ThinkPHP6 原始碼分析之應用初始化

App Construct

先來看看在__construct 中做了什麼,基本上任何框架都會在這裡做一些基本的操作,也就是從這裡開始延伸出去。

public function __construct(string $rootPath = '')
{
    $this->thinkPath   = dirname(__DIR__) . DIRECTORY_SEPARATOR;
    $this->rootPath    = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
    $this->appPath     = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
    $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
    if (is_file($this->appPath . 'provider.php')) {
        $this->bind(include $this->appPath . 'provider.php');
    }
    static::setInstance($this);
    $this->instance('app', $this);
    $this->instance('think\Container', $this);
}

● 從魔術的方法的參數 rootPath 來看,是支援自訂根目錄路徑的。

● 設定了thinkPath, rootPath, appPath, runtimePath

● 綁定了預設的服務提供者,總共提供了兩個,app\Reques 和app\ExceptionHandle,實際上你使用的Request 就是它。具體到appPath 查看

● 設定目前容器實例APP

● 將App($this) 實例綁定到容器中,分別是app 和think\Container

#這裡要注意的是App 類別是繼承Container 的,所以就是將自身實例綁定到容器中。

在這裡似乎整個應用就已經初始化結束了?這裡我需要把 Request run 的一部分放在這裡說,因為那裡才是框架主要的初始化工作,我並不認為將這一部分初始化工作放在 Request run 中是合理的。

主要的初始化

public function initialize()
{
    $this->initialized = true;
    $this->beginTime = microtime(true);
    $this->beginMem  = memory_get_usage();
    // 加载环境变量
    if (is_file($this->rootPath . '.env')) {
        $this->env->load($this->rootPath . '.env');
    }
    $this->configExt = $this->env->get('config_ext', '.php');
    $this->debugModeInit();
    // 加载全局初始化文件
    $this->load();
    // 加载框架默认语言包
    $langSet = $this->lang->defaultLangSet();
    $this->lang->load($this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $langSet . '.php');
    // 加载应用默认语言包
    $this->loadLangPack($langSet);
    // 监听AppInit
    $this->event->trigger('AppInit');
    date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
    // 初始化
    foreach ($this->initializers as $initializer) {
        $this->make($initializer)->init($this);
    }
    return $this;
}

● 載入.env 環境變數檔案

● 載入設定檔以及應用程式內的檔案

# ● 載入應用程式內的common.php

    ● 載入助理函數在thinkPath 目錄下的helper.php

● 載入設定檔

#● 載入應用目錄下的event. php 事件

● 註冊應用程式目錄下的service.php 服務

● 載入語言包

● 監聽AppInit 事件,利用該事件可以做一些請求前的工作

● 設定時區

● 注入所有服務並且啟動服務

#服務註冊

初始化過程中,進行服務註冊,那麼服務註冊做了哪些事情?該如何使用的服務呢?

public function register($service, bool $force = false)
{
    $registered = $this->getService($service);
    if ($registered && !$force) {
        return $registered;
    }
    if (is_string($service)) {
        $service = new $service($this);
    }
    if (method_exists($service, 'register')) {
        $service->register();
    }
    if (property_exists($service, 'bind')) {
        $this->bind($service->bind);
    }
    $this->services[] = $service;
}

● 服務是否註冊過,如果需要強制重新註冊

● 實例化服務

● 如果實作了register 方法,則需要執行register 方法

● 如果設定了bind 屬性,則需要將service 實例綁定到容器

● 最後合併到整個service 陣列中,等待boot

服務啟動

目前在初始化的時候只有下面三個服務,在$this->initializers 數組中

foreach ($this->initializers as $initializer) {
        $this->make($initializer)->init($this);
}

這三個服務分別是:

think\initializer\BootService
think\initializer\Error
think\initializer\RegisterService

● Error 服務是用來處理框架異常和錯誤的

● RegisterService 從字面的意思是註冊服務的

● BootService 是啟用服務的

Error 處理在之後再說,這裡說一下RegisterService 和BootService。

當從Container 中make 出RegisterService 的時候

這裡有個隱藏的靜態方法make,每次如果第一次從Container 中make 出來的實例物件都會執行make 方法,當然首先必須你實現了該方法。

隨後會執行 Init 方法。當你進入到 RegisterService 的時候,你會看到該方法。方法內容如下:

public function init(App $app)
{
    $file = $app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . 'services.php';
    $services = $this->services;
    if (is_file($file)) {
        $services = array_merge($services, include $file);
    }
    foreach ($services as $service) {
        if (class_exists($service)) {
            $app->register($service);
        }
    }
}

該方法就很奇怪了,和我想像的有點不一樣。服務是直接從 runtime 目錄下面取得的,而不是在 config 目錄下的 service.php 中。為什麼會這樣呢?由於 composer 的發展,TP 框架也可以提供套件的自動發現的功能,這也證明了開發小組不斷向社區靠攏。下面來看看是如何實現的。

因為這都是得益於composer 的,所以來看rootPath 下的composer.json,到最下面,你會發現下面的配置

"scripts": {
    "post-autoload-dump": [
        "@php think service:discover",
        "@php think vendor:publish"
    ]
}

從配置來看,框架總共提供了兩個指令,service:discover 和vendor:publish。具體實作這裡就不說了,你只要知道套件的發現是由 service:discover 實現的。

還有就是這裡預設注入了三個服務。

PaginatorService::class,
ValidateService::class,
ModelService::class,

最後再來看看 BootService,這就很簡單了。從命名來講就不難看出,下面就是程式碼,正常的啟動服務,但這裡要說明的是,服務類別中必須實作了 boot 方法才會啟動。

public function init(App $app)
{
    $app->boot();
}

以上就是整個應用程式的初始化,具體細節在之後討論。

本文來自ThinkPHP框架技術文章欄:http://www.php.cn/phpkj/thinkphp/

#

以上是ThinkPHP6源碼分析之應用初始化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:learnku.com。如有侵權,請聯絡admin@php.cn刪除