ThinkPHP6源碼分析之應用初始化

ThinkPHP6 源碼分析之應用初始化php

官方羣點擊此處laravel

App Constructsql

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

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 來看,是支持自定義根目錄路徑的。json

● 設置了 thinkPath, rootPath, appPath, runtimePath數組

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

● 設置當前容器實例 APP架構

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

這裏須要注意的是 App 類是繼承 Container 的,因此就是將自身實例綁定到容器中。app

在這裏彷佛整個應用就已經初始化結束了?這裏我須要把一部分 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();

}

 

以上就是ThinkPHP6源碼分析之應用初始化的詳細內容

以上內容但願幫助到你們,不少PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們,須要的能夠加入個人官方羣點擊此處

相關文章
相關標籤/搜索