运行时所有者
php_embed_init()、php_request_startup()、php_embed_shutdown(),以及 MINIT/RINIT/RSHUTDOWN/MSHUTDOWN 的最终调度者。
PHP、PHPX、TypePHP 生成模块与具体项目的 init/shutdown 调用关系;覆盖原生 bin、ext、lib,多 TypePHP 模块,以及 WASI command / component。
php_embed_init()、php_request_startup()、php_embed_shutdown(),以及 MINIT/RINIT/RSHUTDOWN/MSHUTDOWN 的最终调度者。
php::request_init() 初始化 Decimal、Native GC、Box 资源;php::request_shutdown() 执行 Native finalizer 并清理请求缓存。
生成 zend_module_entry、项目专属 MINIT/MSHUTDOWN/RINIT/RSHUTDOWN,以及 typephp_<project>_runtime_* ABI。
全局变量、静态属性、数组常量、请求模板、Python module cache、项目符号 cache,以及 bin 模式的 main()。
module_init(zend_module_entry *) 表示“向 Zend 注册并启动一个模块”;生成在项目命名空间里的 static module_init() 表示“初始化项目请求级数据”。后者不是 MINIT。
| 模式 | PHP runtime 所有者 | 项目模块何时注册 | 项目 RINIT/RSHUTDOWN | 入口 | 多模块结论 |
|---|---|---|---|---|---|
ext | 外部 PHP SAPI(CLI/FPM/Embed) | PHP module startup 期间 | PHP 自动调度 | 外部 PHP 脚本调用编译符号 | 支持多个,但 PHP 符号不得冲突 |
bin | 生成的 C++ main() | php_embed_init() 完成后才注册 | 自身项目由 PHPX 手动补调 | RINIT 中 php::eval(... main()) | 可再加载多个常规 ext |
lib | 宿主显式调用项目 runtime ABI | 与 bin 相同,属于晚注册模块 | 自身项目由 PHPX 手动补调 | 宿主调用导出函数,无生成 main | 可加载多个库;同进程只能有一个活动 Zend runtime |
| WASI command | WASM _start/main | 与原生 bin 同构 | 手动补调自身项目 | 执行 TypePHP main() | 单实例、静态链接;无动态 ext |
| WASI component library | WIT runtime resource | create-runtime 时 | resource 创建/析构负责 | #[WasmExport] 方法 | 每个 Component 实例仅一个活动 resource |
假设 PHP 同时加载 typephp_app_a、typephp_app_b。两个模块都在 PHP 收集 request handlers 之前注册,因此走标准 Zend 模块生命周期。
php::request_init() 首次真正初始化;A module_init()module_init()php::request_shutdown() 清共享 PHPX 状态;再清 Btypephp_<project> 命名空间,runtime/get-module 符号也带项目名。多个 ext 不再因为 PHPX misc 或通用表名发生原生符号冲突。php_embed_init() 内部已经完成 SAPI startup、PHP module startup 和 PHP request startup。此后 bin 才取得自身的 zend_module_entry 并注册,所以自身项目不在 PHP 预先收集的 RINIT/RSHUTDOWN handler 列表中。
typephp_<bin>_runtime_init(argc, argv)zend_register_module_ex() + zend_startup_module_ex() → bin::MINITphp::request_init()(通常已被 ext 初始化)→ 项目 module_init()php_embed_init() 期间已经收集完 module handler 数组;bin 模块注册得更晚,不在数组里。不手动补调会遗漏项目全局变量、Native roots、请求数组模板和缓存清理。lib 与 bin 使用同一份 PHPX Embed 实现,但定义 TYPEPHP_NO_MAIN,不会生成 C++ main()。宿主必须调用项目名隔离的 ABI。
typephp_demo_runtime_init(argc, argv);
// 调用 demo 导出的 TypePHP 函数
typephp_demo_runtime_shutdown();
| 操作 | 结论 | 原因 |
|---|---|---|
| 只加载 A、B 的动态库,不调用 init | 可以 | 导出 runtime/get-module 符号带项目名;装载代码不等于启动 ZendVM。 |
init(A) → use(A) → shutdown(A) → init(B) | 可串行 | 前一 runtime 必须完整退出后,下一库才可重新启动进程级 PHP Embed 状态。 |
init(A) → init(B),两个同时活动 | 不支持 | ZendVM/Embed 是进程级状态;每个 lib 的局部 runtime_started 无法阻止另一 lib 再次调用 php_embed_init()。 |
| 多个项目需要同时工作 | 一个 owner | 使用一个 bin/lib 拥有 runtime,其余能力作为启动前加载的 ext,或合并为同一个 TypePHP 项目。 |
WASI 使用静态链接的 PHP、PHPX 和 TypePHP 生成代码。浏览器与 Wasmtime 的 Host API 不同,但 PHP/ZendVM 生命周期相同。当前不支持在运行时动态加载 .so/.dll 形式的 TypePHP ext。
mode: command/library 决定生命周期入口(生成 main,或由 runtime resource 管理);wasm: component/browser 决定产物与 Host 适配方式。它们是正交配置,浏览器构建并不自动等于 library 模式。_start/main 自动包围_startruntime_init,返回 resourceruntime_shutdownfinally 中显式调用 runtime[Symbol.dispose]();直接终止 Worker 只会回收整个实例,不保证 shutdown callback 被执行。php::request_shutdown() 后接 module_clean()。module_clean() 仍各执行一次。| 符号 | 定义层 | 寿命 | 职责 |
|---|---|---|---|
php_embed_init/shutdown | PHP Embed SAPI | 整个 runtime | 启动/关闭 SAPI、PHP modules 和一个 PHP request。 |
PHP_MINIT_FUNCTION(typephp_x) | TypePHP 生成模块 | module | 注册项目类/函数/属性元数据;安装共享 TypePHP handler。 |
PHP_RINIT_FUNCTION(typephp_x) | TypePHP 生成模块 | request | 调用 PHPX request init,再初始化项目请求状态;bin 额外执行 main。 |
php::request_init/shutdown | PHPX | 每线程/每 request 共享 | 管理 Decimal、Native GC、Box 和动态调用缓存;对多模块调用幂等。 |
static module_init() | 生成的项目命名空间 | request | 初始化项目 globals、静态属性、数组常量、请求模板和 roots。 |
static module_clean() | 生成的项目命名空间 | request | 清项目 globals/cache,并将 user-code symbol pointer 表归零。 |
module_init(zend_module_entry *) | PHPX Embed glue | module | 调用 Zend API 注册晚到的 bin/lib 项目模块并触发其 MINIT。 |
typephp_<project>_runtime_init/shutdown | TypePHP 稳定 ABI,PHPX 实现 | runtime | bin main、native lib host、WIT adapter 共同使用的外层入口。 |
php_<project>_embed_get_module | TypePHP 生成模块 | module | 返回该项目唯一的 zend_module_entry;项目名避免多模块 C++ 符号冲突。 |
php_embed_shutdown() 后析构持有 request zval 的 C++ 对象。module_init() 当作 Zend MINIT,或在 MINIT 中创建请求 zval。bin、ext、lib、WASI command 还是 component library。php_embed_init() 后晚注册。compiler/src/Translator.php::genExtension():生成项目 module entry、MINIT/MSHUTDOWN/RINIT/RSHUTDOWN、module_init/module_clean。phpx/src/misc/typephp_main.cc:原生 bin/lib 与 WASI 共用的 Embed runtime owner、晚注册模块和 shutdown 顺序。phpx/src/core/base.cc::php::request_init/request_shutdown:PHPX 请求级共享状态。phpx/include/typephp_runtime.h:项目名隔离的 runtime/get-module ABI 宏。compiler/src/Build/WasmInterfaceGenerator.php:WIT runtime resource、单实例约束、异常边界和 resource destructor。projects/php-8.5.9/sapi/embed/php_embed.c:php_embed_init/shutdown 内部的 SAPI/module/request 调度。projects/php-8.5.9/main/main.c::php_request_shutdown():shutdown function、析构、RSHUTDOWN、内存池销毁的标准顺序。