如題,今天感覺好久沒有更新部落格了。最近迷上了物聯網開發。一直在研究stm32、51這些東西。想起來前幾天群裡面有人問到tp擴充套件包原理。其實這個前幾年也就研究過。網上搜了搜發現相關文章也很少(也有可能是我搜尋姿勢不對)今天就來寫一篇thinkphp composer包載入原理
composer update
或者 composer require
操作時。則會執行service:discover
這個命令。把當前所有已經載入的庫資訊都進行一次匹配。如果匹配到了think關鍵字的services屬性。則把服務類輸出成組態檔到vendor/services.php
檔案中vendor/services.php
中的service服務類到當前應用內進行初始化在第三步進入到Http->runWithRequest
這個方法中後。可以看到又呼叫了initialize
方法
追進這個方法可以看到
追進initialize
方法看實現
/**
* 初始化應用
* @access public
* @return $this
*/
public function initialize()
{
// 設定當前初始化狀態
$this->initialized = true;
// 設定應用開始時間
$this->beginTime = microtime(true);
// 獲取到php的記憶體
$this->beginMem = memory_get_usage();
// 載入環境變數 例如當前應用目錄下的 .env檔案
$this->loadEnv($this->envName);
// 設定組態檔字尾
$this->configExt = $this->env->get('config_ext', '.php');
// 偵錯模式設定
$this->debugModeInit();
// 載入全域性初始化檔案
$this->load();
// 載入應用預設語言套件
$this->loadLangPack();
// 監聽AppInit
$this->event->trigger(AppInit::class);
// 設定php預設時區
date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
// 初始化當前系統設定的預設服務
foreach ($this->initializers as $initializer) {
// 呼叫make函數生成物件。並且執行物件中的init方法
$this->make($initializer)->init($this);
}
return $this;
}
重點是初始化當前系統設定的預設服務
這個$this->make($initializer)->init($this)
函數,看看initializers
屬性
/**
* 應用初始化器
* @var array
*/
protected $initializers = [
Error::class,
RegisterService::class,
BootService::class,
];
追到這裡就是關鍵了。上面把這裡面的類進行初始化。並且執行類中的init方法。直接看RegisterService::class
類的init
方法
public function init(App $app)
{
// 獲取當前專案根目錄。拼接上 vendor/services.php
$file = $app->getRootPath() . 'vendor/services.php';
$services = $this->services;
if (is_file($file)) {
$services = array_merge($services, include $file);
}
// 初始化services
foreach ($services as $service) {
if (class_exists($service)) {
$app->register($service);
}
}
}
讀到這裡的可以看看自己專案vendor目錄下是不是有一個services.php
,接下來講一講composer.json
這個檔案
在tp框架中的composer.json
有這樣一個設定
這裡這個概念我直接讓chatgpt來解讀。解讀內容如下
接下來直接看service:discover
這個命令。追到vendor\topthink\framework\src\think\console\command\ServiceDiscover.php
檔案
public function execute(Input $input, Output $output)
{
// 獲取到當前專案根目錄下的 vendor/composer/installed.json 檔案
if (is_file($path = $this->app->getRootPath() . 'vendor/composer/installed.json')) {
// json解析
$packages = json_decode(@file_get_contents($path), true);
// Compatibility with Composer 2.0
if (isset($packages['packages'])) {
$packages = $packages['packages'];
}
$services = [];
foreach ($packages as $package) {
// 判斷當前包是否在extra欄位裡面宣告了think關鍵字中的services屬性。如果宣告了就把services給裝載到services變數內
if (!empty($package['extra']['think']['services'])) {
$services = array_merge($services, (array) $package['extra']['think']['services']);
}
}
$header = '// This file is automatically generated at:' . date('Y-m-d H:i:s') . PHP_EOL . 'declare (strict_types = 1);' . PHP_EOL;
// 用var_export函數把services變數列印成可讀性程式碼。並且寫入到根目錄vendor目錄下的services
$content = '<?php ' . PHP_EOL . $header . "return " . var_export($services, true) . ';';
file_put_contents($this->app->getRootPath() . 'vendor/services.php', $content);
$output->writeln('<info>Succeed!</info>');
}
一直到這就算結束了
如果覺得這篇文章對你有幫助。不妨點個贊留個關注再走