ThinkPHP6 源碼分析之應用初始化 官方群點擊此處。 App Construct 先來看看在 __construct 中做了什麼,基本任何框架都會在這裡做一些基本的操作,也就是從這裡開始延伸出去。 public function __construct(string $rootPath = ' ...
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(); }
以上就是ThinkPHP6源碼分析之應用初始化的詳細內容
以上內容希望幫助到大家,很多PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裡入手去提升,對此我整理了一些資料,包括但不限於:分散式架構、高可擴展、高性能、高併發、伺服器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨需要的可以免費分享給大家,需要的可以加入我的官方群點擊此處。