浅谈 thinkphp composer 扩展包加载原理

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


前言


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


概览


  1. 当进行 composer update 或者 composer require 操作时。则会执行service:discover这个命令。把当前所有已经加载的库信息都进行一次匹配。如果匹配到了think关键字的services属性。则把服务类输出成配置文件到vendor/services.php文件中
  2. 当一次应用初始化(通常为一次访问开始时).则会引入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 = '<?php ' . PHP_EOL . $header . "return " . var_export($services, true) . ';'; file_put_contents($this->app->getRootPath() . 'vendor/services.php', $content); $output->writeln('<info>Succeed!</info>');
}

一直到这就算结束了


写在最后

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

浅谈 thinkphp composer 扩展包加载原理的更多相关文章

  1. 深入解析 composer 的自动加载原理 (转)

    深入解析 composer 的自动加载原理 转自:https://segmentfault.com/a/1190000014948542 前言 PHP 自5.3的版本之后,已经重焕新生,命名空间.性状 ...

  2. composer 实现自动加载原理

    简介 一般在框架中都会用到composer工具,用它来管理依赖.其中composer有类的自动加载机制,可以加载composer下载的库中的所有的类文件.那么composer的自动加载机制是怎么实现的 ...

  3. 【原】从一个bug浅谈YUI3组件的资源加载

    篇前声明:为了不涉及业务细节,篇内信息统一以某游戏,某功能代替 前不久,某游戏准备内测客户端,开发人员测试过程中发现某功能突然不灵了,之前的测试一切ok,没有发现任何异常,第一反应是,游戏内浏览器都是 ...

  4. 深入解析 composer 的自动加载原理

    PHP 自5.3的版本之后,已经重焕新生,命名空间.性状(trait).闭包.接口.PSR 规范.以及 composer 的出现已经让 PHP 变成了一门现代化的脚本语言.PHP 的生态系统也一直在演 ...

  5. laravel框架应用和composer扩展包开发

    laravel5.5+ laravel官方地址 laravel是目前最流行的php框架,发展势头迅猛,应用非常广泛,有丰富的扩展包可以应付你能想到的各种应用场景,laravel框架思想前卫,跟随时代潮 ...

  6. 使用PSR-4配合composer autoload 自动加载文件夹

    require 文件很麻烦,使用PSR-4搭配composer一次加载,终生受用. 感觉类似java中的import了,自己先记录一下最近理解的. 用composer管理自己的包吧 安装compose ...

  7. laravel composer 扩展包开发(超详细)

    laravel composer 扩展包开发(超详细) 置顶 2018年02月05日 11:09:16 Simael__Aex 阅读数:10396    版权声明:转载请注明出处:http://blo ...

  8. 详解composer的自动加载机制

    composer是一个用PHP开发的用来管理项目依赖的工具,当你在项目中声明了依赖关系后,composer可以自动帮你下载和安装这些依赖库,并实现自动加载代码. 安装composer composer ...

  9. java 启动查看jar包加载顺序并设置classpath

    本文为博主原创,转载请注明出处: 1.idea查看jar包加载顺序 jdk8 可以通过     -XX:+TraceClassPaths    参数进行查看jar包的加载顺序 jdk11 可以通过  ...

  10. thinkphp pathinfo nginx 无法加载模块:Index

    thinkphp 报了 无法加载模块:Index 错误位置 FILE: /var/multrix/wxactivity_archive/ThinkPHP/Library/Think/Dispatche ...

随机推荐

  1. HTTP TCP UDP WEBSOCKET

    概念: TCP和UDP:传输层协议:(卡车) HTTP:应用层协议:(货物).HTTP(超文本传输协议)是利用TCP在两台电脑(通常是Web服务器和客户端)之间传输信息的协议.客户端使用Web浏览器发 ...

  2. nginx+vite 项目打包及部署到服务器二级路由

    项目打包及部署到服务器二级路由 例如:我希望将打包的项目部署到 http://localhost:8088/web/ 上 一. 项目配置及打包 项目部署到服务器二级路由需要配置基础路径base,即需要 ...

  3. JVM的垃圾收集算法

    介绍分代收集理论和几种垃圾收集算法的思想及其发展过程. 分代收集理论 当前商业虚拟机的垃圾收集器,大多数都遵循了 "分代收集"(Generational Collection)的理 ...

  4. flak_login用法

    基础的信息和全局配置这里就不多说,需要用到再斟酌也可以的.这里也是针对每个模块较为常用的进行解释说明,后期再使用过程中遇到会进行补充. Login_Manager LoginManager是一个类,有 ...

  5. pandas之读取文件

    当使用 Pandas 做数据分析的时,需要读取事先准备好的数据集,这是做数据分析的第一步.Panda 提供了多种读取数据的方法: read_csv() 用于读取文本文件 read_json() 用于读 ...

  6. [智能制造] 如何利用生产软件(MES)进行生产信息收集?

    1 如何保证生产管理软件所收集信息的准确性? 1.1 当前制造企业使用MES系统收集信息的现状 原以为使用了MES生产管理系统后,会得到稽核员的肯定. 但没想到,在实际的稽核过程中,稽核员还是发现目前 ...

  7. [SpringBoot]Spring Boot Framework @ Environment / ApplicationContext & SpringApplication

    [#]: 表示较为重要 1 Spring Boot Overview SpringBoot是一个快速开发框架,快速的将一些常用的第三方依赖整合(原理:通过Maven子父工程的方式),简化XML配置,全 ...

  8. 1.springsecurity基于内存和数据库的认证

    1.总结: 昨天主要是使用security实现了基于内存的认证和基于数据库的认证(实际项目中使用): 在security的项目中,必须配置WebSecurityConfigurerAdaptor的实现 ...

  9. mariabackup -prepare step on increment backup failed

    问题描述:使用mariabackup对maridb10.6.4进行物理备份,进行增量恢复的时候报错.截止到目前,还是mariadb的一个bug,还没有修复.在增备的过程中如果出现新库的建立,数据库就会 ...

  10. c++基本数据结构

    基本数据结构: 一.线性表 1.顺序结构 线性表可以用普通的一维数组存储. 你可以让线性表可以完成以下操作(代码实现很简单,这里不再赘述): 返回元素个数. 判断线性表是否为空. 得到位置为p的元素. ...