当前位置: 主页 > 提点 > 详情
浅谈 thinkphp composer 扩展包加载原理 环球视讯

来源博客园   2023-06-14 22:21:52

浅谈 thinkphp composer 扩展包加载原理本文将介绍 ThinkPHP 中 Composer 扩展包的加载原理,帮助读者更好地理解和应用该功能。前言

如题,今天感觉好久没有更新博客了。最近迷上了物联网开发。一直在研究stm32、51这些东西。想起来前几天群里面有人问到tp扩展包原理。其实这个前几年也就研究过。网上搜了搜发现相关文章也很少(也有可能是我搜索姿势不对)今天就来写一篇thinkphp composer包加载原理

概览当进行 composer update或者 composer require操作时。则会执行service:discover这个命令。把当前所有已经加载的库信息都进行一次匹配。如果匹配到了think关键字的services属性。则把服务类输出成配置文件到vendor/services.php文件中当一次应用初始化(通常为一次访问开始时).则会引入vendor/services.php中的service服务类到当前应用内进行初始化源码解析composer包加载流程文字详解 建议先阅读一下这篇前两年我写的文章 Thinkphp6源码解析之分析 路由篇-请求流程

在第三步进入到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 = "app->getRootPath() . "vendor/services.php", $content);            $output->writeln("Succeed!");        }

一直到这就算结束了

写在最后

如果觉得这篇文章对你有帮助。不妨点个赞留个关注再走