01 | 深入理解 Swoole 的底层加载原理

首发原文链接:深入理解 Swoole 的底层加载原理

PHP 扩展加载

我们从 php-src/sapi/cli/php_cli.c:1159 文件的入口函数 int main(int argc, char *argv[]) 开始分析。
大家可以先看下面这张图,描述了整个关键函数的加载、调用流程。从模块的初始化,到最后资源的释放回收整个流程,都体现在其中了。「如果图片看不清,可以在文章末尾点击 阅读原文 查看原图」

Swoole 入口文件

我们先看下 Swoole 源码中对入口文件的定义,接下来我们再看在 PHP 中对扩展定义的结构体。

// swoole-src/php_swoole.h:40
extern zend_module_entry swoole_module_entry; // Swoole扩展的模块入口
#define phpext_swoole_ptr &swoole_module_entry PHP_MINIT_FUNCTION(swoole); // 在PHP启动时被调用,用于初始化模块的全局状态。
PHP_MSHUTDOWN_FUNCTION(swoole); // 在PHP关闭时被调用,用于清理和释放模块的全局资源。
PHP_RINIT_FUNCTION(swoole); // 每个PHP请求开始时被调用,用于初始化每个请求的相关资源。
PHP_RSHUTDOWN_FUNCTION(swoole); // 在每个PHP请求结束时被调用,用于释放每个请求的相关资源。
PHP_MINFO_FUNCTION(swoole); // 定义了模块信息的获取函数。这个函数用于返回关于模块的信息,例如版本号、配置选项等。// 定义了Swoole扩展的全局变量。这些全局变量可以在整个扩展中访问,用于存储一些配置选项和状态信息。
// clang-format off
ZEND_BEGIN_MODULE_GLOBALS(swoole)zend_bool display_errors;zend_bool cli;zend_bool use_shortname;zend_bool enable_coroutine;zend_bool enable_preemptive_scheduler;zend_bool enable_library;zend_bool enable_fiber_mock;long socket_buffer_size;int req_status;
ZEND_END_MODULE_GLOBALS(swoole)
// clang-format onextern ZEND_DECLARE_MODULE_GLOBALS(swoole);

在 PHP 的 Zend 虚拟解析引擎中,对 PHP 扩展的入口文件,进行了统一的定义。基于 PHP 开发的扩展都得实现这一标准,因此 Swoole 也不例外。

// php-src/Zend/zend_modules.h:71
struct _zend_module_entry {....//  PHP 引擎加载模块时需要执行的函数zend_result (*module_startup_func)(INIT_FUNC_ARGS);// PHP 引擎关闭模块时需要执行的函数zend_result (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);// 每个请求开始时需要执行的函数zend_result (*request_startup_func)(INIT_FUNC_ARGS);// 每个请求结束时需要执行的函数zend_result (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);// 执行 phpinfo 函数时需要显示的模块信息void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);....
};

我们通过这张图来看下对应关系。

下面我们对逐个函数进行分析。

PHP_MINIT_FUNCTION

如上述所说,这个函数主要是定义了大量的全局常量、及一些子模块的初始化工作。

// Swoole-src/ext-src/php_swoole.c:369
PHP_MINIT_FUNCTION(swoole) {// 定义常量ZEND_INIT_MODULE_GLOBALS(swoole, php_swoole_init_globals, nullptr);REGISTER_INI_ENTRIES();// clang-format off// MUST be on the same line for the inspection tool to recognize correctlySW_REGISTER_STRING_CONSTANT("SWOOLE_VERSION", SWOOLE_VERSION);...// 事件循环等子模块的初始化/** <Sort by dependency> **/php_swoole_event_minit(module_number);// basephp_swoole_atomic_minit(module_number);...SwooleG.fatal_error = fatal_error;// 设置 Swoole socket 默认缓存区大小Socket::default_buffer_size = SWOOLE_G(socket_buffer_size);SwooleG.dns_cache_refresh_time = 60;// 初始化 Zend 引擎字符串资源分配zend::known_strings_init();return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION

这个函数的主要是做清扫的作用,清除运行过程中的变量、及关闭相应的资源,避免资源泄露等。

// Swoole-src/ext-src/php_swoole.c:774
PHP_MSHUTDOWN_FUNCTION(swoole) {// 调用 Zend 引擎释放字符串资源zend::known_strings_dtor();// 释放 Swoole 运行过程中资源php_swoole_runtime_mshutdown();// 释放 Swoole Websocket 服务资源php_swoole_websocket_server_mshutdown();
#ifdef SW_USE_PGSQLphp_swoole_pgsql_mshutdown();
#endif#ifdef SW_USE_ORACLEphp_swoole_oracle_mshutdown();
#endif#ifdef SW_USE_SQLITEphp_swoole_sqlite_mshutdown();
#endif// 执行 Swoole 的清理工作swoole_clean();return SUCCESS;
}

PHP_RINIT_FUNCTION

每个请求开始需要做的一些初始化工作,主要是针对 Http Server 实现的。

// Swoole-src/ext-src/php_swoole.c:982
PHP_RINIT_FUNCTION(swoole) {if (!SWOOLE_G(cli)) {return SUCCESS;}// 开始请求的初始化工作SWOOLE_G(req_status) = PHP_SWOOLE_RINIT_BEGIN;// 将 Swoole 更改为运行状态SwooleG.running = 1;php_swoole_register_shutdown_function("swoole_internal_call_user_shutdown_begin");...// 初始化 Swoole 的 Http Server 等模块php_swoole_http_server_rinit();php_swoole_coroutine_rinit();php_swoole_runtime_rinit();
#ifdef SW_USE_ORACLEphp_swoole_oracle_rinit();
#endif// 结束请求的初始化工作SWOOLE_G(req_status) = PHP_SWOOLE_RINIT_END;return SUCCESS;
}

PHP_RSHUTDOWN_FUNCTION

针对请求资源进行释放,并及时关闭相应的连接资源。

// Swoole-src/ext-src/php_swoole.c:1018
PHP_RSHUTDOWN_FUNCTION(swoole) {if (!SWOOLE_G(cli)) {return SUCCESS;}// 开始请求的清理工作SWOOLE_G(req_status) = PHP_SWOOLE_RSHUTDOWN_BEGIN;rshutdown_callbacks.execute();// 释放 Swoole 事件循环资源等swoole_event_free();php_swoole_server_rshutdown();php_swoole_async_coro_rshutdown();php_swoole_redis_server_rshutdown();php_swoole_coroutine_rshutdown();php_swoole_coroutine_scheduler_rshutdown();php_swoole_runtime_rshutdown();// 清理 Swoole 进程相关的资源php_swoole_process_clean();// 更改 Swoole 的运行状态SwooleG.running = 0;// 结束请求的清理工作SWOOLE_G(req_status) = PHP_SWOOLE_RSHUTDOWN_END;...return SUCCESS;
}

PHP_MINFO_FUNCTION

这个最好理解了,就是打印这个扩展的信息,例如:Swoole 的作者、版本等信息。

PHP_MINFO_FUNCTION(swoole) {char buf[64];php_info_print_table_start();php_info_print_table_header(2, "Swoole", "enabled");php_info_print_table_row(2, "Author", "Swoole Team <team@swoole.com>");php_info_print_table_row(2, "Version", SWOOLE_VERSION);...php_info_print_table_end();DISPLAY_INI_ENTRIES();
}

总结

首先,理解 Swoole 扩展的加载原理,最重要的是要搞懂最开始提到的 PHP 扩展加载全流程。我就是在这个全流程的分析上,花了大量的时间。经常分析到一半,发现逻辑不对,然后就反复的分析其中的关联关系。

其次,对于之前只写 PHP 业务代码,没有接触过 PHP 源代码的人来说,简直就是看天书。因此,如果有志于学习源码的朋友,一定到有足够的耐心,反复研读、琢磨。

最后,Swoole 作为 PHP 在异步通信框架领域的一个重要的扩展,还是值得好好学习的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/573035.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++初学者:像C#一样优雅写程序

C语言的强大&#xff0c;在于自由自在&#xff0c;你可以随便怎么写程序&#xff0c;不讲格式&#xff0c;可以很整齐&#xff0c;也可以鬼画符&#xff0c;只要能运行就可以了&#xff0c;程序员可以自由发挥。 如图&#xff1a; 国际C语言大赛中的代码 图2 C的语言更强大&…

Django auth模块

【一】命令行创建用户 【1】语法 python manage.py createsuper【2】示例 用户名 默认是是电脑名称 邮箱 可以填也可以不填 密码 terminal中&#xff1a;输入密码不显示出来manage.py中&#xff1a;明文输入输入密码太简单会提示 Username (leave blank to use administra…

【爬虫基础】第6讲 opener的使用

在爬虫中&#xff0c;opener是一个用来发送HTTP请求的对象。它可以用来模拟浏览器发送请求&#xff0c;包括设置请求头、处理Cookie等操作。使用opener可以实现一些高级功能&#xff0c;如模拟登录、处理验证码等。 方法1&#xff1a; from urllib.request import Request,bu…

自动驾驶传感器:惯性导航IMU原理

自动驾驶传感器&#xff1a;惯性导航IMU原理 附赠自动驾驶学习资料和量产经验&#xff1a;链接 组合导航里包含了GNSS卫星导航模块与IMU惯性导航模块&#xff0c;前一篇文章写了GNSS模块&#xff0c;本章写IMU惯导&#xff0c;也是本系列最后一篇文章。 1. 惯性测量单元&…

python学习13:python中的字符串格式化

python中的字符串格式化另外一种方式 我们前面是使用的%d,%f,%s占位符来实现字符串的格式化的&#xff1b;这次我们通过f"{}"来快速实现格式化&#xff0c;代码示例如下&#xff1a;

vue 预览excel文件的又一伟大实践 —— vue-office

实际上&#xff0c;预览excel这个功能&#xff0c;我之前已经写过一个文章了。如下&#xff0c;使用的是 luckysheet/luckyExcel 实现的。 vue 实现在线预览Excel-LuckyExcel/LuckySheet实现方案_excel在线预览的方案-CSDN博客 但是最近客户使用发现一个bug&#xff0c;就是某…

WPF —— DockPanel、ProgressBar 控件详解

ProgressBar 控件详解 1Progress bar简介 ProgressBar&#xff1a;进度条控件。 WPF带有一个方便的控件用于显示进度&#xff0c;称ProgressBar。它的工作原理就是设置最小值和最大值然后通过递增一个值&#xff0c;这样就可以直观的显示当前进度情况。 2 Progress bar常用的…

web——xml,xxe

xml的格式 &#xff0c;我们可以通过这个读取文件 改成这个 这样就可以知道&#xff0c;文件里的信息&#xff0c;但这是有回显的&#xff0c;因为&#xff0c;有prinetf 带外测试 将数据包改成这个 就发现漏洞存在 这是有回显的情况 数据包这么写 然后在自己的服务器…

如何用Flask中的Blueprints构建大型Web应用

本文分享自华为云社区《构建大型Web应用Flask中的Blueprints指南》&#xff0c;作者&#xff1a; 柠檬味拥抱。 什么是Blueprints&#xff1f; 什么是Blueprints&#xff1f; Blueprints是Flask中的一种模式&#xff0c;用于将应用程序分解为可重用的模块。每个蓝图实际上是…

elementui日期时间选择框自定义组件

1.需求场景 业务中需要&#xff0c;日期选择框方便客户对日期的选择&#xff08;比如近5天&#xff0c;本周&#xff0c;本月&#xff0c;本年等等&#xff09;&#xff0c;并按小时展示。 2.组件代码MyDateTimeChange.vue <template><el-date-pickerv-model"…

【LVGL-键盘部件,实体按键控制】

LVGL-二维码库 ■ LVGL-键盘部件■ 示例一&#xff1a;键盘弹窗提示■ 示例二&#xff1a;设置键盘模式■ 综合示例&#xff1a; ■ LVGL-实体按键控制■ 简介 ■ LVGL-键盘部件 ■ 示例一&#xff1a;键盘弹窗提示 lv_keyboard_set_popovers(kb,true);■ 示例二&#xff1a;设…

Vue脚手架

Vue脚手架 学习目标&#xff1a; 理解Node.js基本使用方法理解包资源管理器NPM的使用理解webpack的作用理解 vue-cli 脚手架 (重点)Element-UI 组件库 1.vue的格式&#xff1a;new Vue({//作用的视图el:"id选择器",//vue中的数据/*data:{key:value,key:value,...}…