2026年8月26日14:11:48
PHPX 深度分析:TypePHP 的运行时基石
一、定位与角色
PHPX 是 Swoole(韩天峰)开发的 Zend Engine API 的 C++17 封装库,是 TypePHP 编译器的运行时基石。
在 TypePHP 的编译流水线中,PHPX 承担了运行时层的全部职责:
PHP 源码
│ (TypePHP 编译器,纯 PHP)
▼
C++17 源码 ── 调用 ──► PHPX API (php::Variant, php::Array, php::Object...)
│ │
▼ ▼
原生机器码 Zend Engine (libphp)
关键区别:TypePHP 编译器本身完全用 PHP 编写 ,而 PHPX 是纯 C++ 库 ,二者通过生成的 C++ 代码中的
php::命名空间调用衔接。
二、整体架构
┌─────────────────────────────────────────────────────────────┐
│ TypePHP 生成的 C++ 代码 │
│ (php_App__Service__calculate, php_main, ...) │
├─────────────────────────────────────────────────────────────┤
│ typephp_* 专用层 │
│ typephp_runtime.h / typephp_helper.h / typephp_fiber_*.h │
│ (嵌入式运行时、属性钩子、持久缓存、std容器Box、热/冷属性) │
├─────────────────────────────────────────────────────────────┤
│ PHPX 核心层 (Core) │
│ ┌──────────┬──────────┬──────────┬──────────┬───────────┐ │
│ │ Variant │ Array │ Object │ String │ Reference │ │
│ │ (zval) │(HashTable)│(zend_object)│(zend_string)│(zend_reference)│
│ ├──────────┼──────────┼──────────┼──────────┼───────────┤ │
│ │ Closure │ Box │ Resource │ Args │ Helper │ │
│ └──────────┴──────────┴──────────┴──────────┴───────────┘ │
├─────────────────────────────────────────────────────────────┤
│ PHPX 扩展层 (Extension) │
│ ┌──────────────┬──────────────┬──────────────────────────┐ │
│ │ Class 层 │ Func 层 │ Constant 层 │ │
│ │ (50+ PHP扩展) │ (60+ 内置函数)│ (扩展常量注册) │ │
│ └──────────────┴──────────────┴──────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ php::fn / php::std 直连层 │
│ (消除 zend_call_function 开销,直接调用 Zend 内部 C 函数) │
├─────────────────────────────────────────────────────────────┤
│ 高精度数值 / Native GC / Python 桥接 │
│ bigInt(GMP) decimal(libmpdec) bigFloat(MPFR) │
├─────────────────────────────────────────────────────────────┤
│ Zend Engine C API │
│ (php.h, zend_API.h, zend_types.h, sapi/embed...) │
└─────────────────────────────────────────────────────────────┘
三、核心类型系统
3.1 基础类型别名(phpx_types.h)
namespace php {
typedef zend_long Int; // int64_t,PHP 整数
typedef double Float; // PHP 浮点数
typedef bool Bool; // PHP 布尔
}
编译期静态断言确保 zend_long == int64_t 且 C++ 标准 >= C++17。
3.2 Variant ------ 通用值容器(核心中的核心)
Variant 是 PHPX 最基础的类,内部持有一个 zval,代表任意 PHP 值:
class Variant {
zval val; // Zend 引擎的 zval 结构
public:
// 构造:从 null/bool/int/float/string/array/object/zval*
Variant();
Variant(zval *v, Ctor);
// 类型转换(RAII 安全,自动管理引用计数)
Int toInt() const;
Float toFloat() const;
String toString() const;
Array toArray() const;
Object toObject() const;
Bool toBool() const;
// 类型判断(直接 Z_TYPE_P 检查,零开销)
bool isNull() / isBool() / isInt() / isFloat() / isString()
bool isArray() / isObject() / isResource() / isReference()
// 操作符重载
Variant& operator=(const Variant&);
Variant& operator=(const zval*);
};
内存管理(RAII) :Variant 析构时自动调用 zval_ptr_dtor() 减少引用计数,拷贝构造时自动 ZVAL_COPY。这消除了手动管理 zval 引用计数的心智负担。
间接 zval(IS_INDIRECT) :PHPX 特别处理了 IS_INDIRECT 类型(指向另一个 zval 的指针,常用于 $GLOBALS、属性引用等),析构时正确解引用。
3.3 Array ------ PHP 数组封装
内部持有 zend_array(HashTable),支持:
offsetGet/offsetSet/offsetExists/offsetUnsetappend/push/pop/merge/countforeach迭代(通过ForeachIterator)- 初始化列表构造:
Array{1, 2, 3}或Array{``{"a", 1}, {"b", 2}}
3.4 Object ------ PHP 对象封装
内部持有 zend_object,支持:
newObject(className, args)------ 创建对象getProperty/setProperty/hasProperty------ 属性访问call(method, args)/callStatic(method, args)------ 方法调用getClassName()/getClassEntry()/instanceOf()_this隐式指针(在方法实现中自动绑定当前对象)
3.5 String ------ 二进制安全字符串
内部持有 zend_string,关键特性:
- 二进制安全 :不依赖
\0结尾,保留长度信息 length()/data()/toStdString()concat/substr/toInt/toFloat- 与
std::string、const char*互转
3.6 Reference ------ PHP 引用
封装 zend_reference,支持 toReference() 创建引用、引用传参等 PHP 引用语义。
3.7 Box ------ 原生对象包装器
Box 是 PHPX 中一个关键设计:将任意 C++ 对象 包装成 PHP 对象,使其可以被 PHP GC 管理、可以在 PHP 代码中传递。这是 TypePHP #[Native] 类和 std:: 容器的底层基础。
// typephp_helper.h 中的模板
template <typename T>
static inline T& toStdContainer(Var& var, uint32_t type_id) {
auto* base_box = var.toBox<Box>();
if (base_box->getTypeInfo() != type_id) throwStdContainerTypeMismatch();
auto* box = dynamic_cast<StdContainerBox<T>*>(base_box);
return box->container; // 直接访问内部 C++ 容器
}
StdContainerBox<T> 将 std::vector<T>、std::map 等 C++ 容器包装为 PHP 对象,TypePHP 的 std::vector(Type::Int) 最终就是一个持有 std::vector<int64_t> 的 Box。
四、嵌入式运行时(typephp_runtime)
这是 TypePHP 二进制模式(bin) 能够独立运行的核心。普通 PHP 扩展运行在 php-fpm/CLI 进程中,而 TypePHP 编译出的独立可执行文件需要自己初始化 PHP 运行时。
4.1 启动流程(typephp_runtime.cc)
extern "C" int typephp_runtime_start(
typephp_module_getter get_module, // 获取编译后的模块入口
int argc, char **argv
) {
php_embed_init(argc, argv); // ① 初始化 PHP embed SAPI
module = get_module(); // ② 获取 TypePHP 编译模块
module_init(module); // ③ 注册并启动模块(MINIT)
save_ps_args(argc, argv); // ④ 保存进程标题(ps)
zend_first_try {
cli_register_file_handles(); // ⑤ 注册 STDIN/STDOUT/STDERR 常量
SG(request_info).path_translated = "embed";
module->request_startup_func(...); // ⑥ RINIT:请求启动
} zend_end_try();
typephp_runtime_started = true;
return 0;
}
4.2 关闭流程
void typephp_runtime_stop() {
EG(flags) |= EG_FLAGS_IN_SHUTDOWN;
php_call_shutdown_functions(); // 执行 register_shutdown_function 注册的函数
zend_call_destructors(); // 调用对象析构
module->request_shutdown_func(); // RSHUTDOWN
module_shutdown(module); // MSHUTDOWN(手动从注册表移除,修复 PHP embed double-free bug)
php_embed_shutdown(); // 关闭 PHP
}
4.3 入口宏(typephp_main.cc)
// 每个 TypePHP 项目生成一个唯一的模块入口
TYPEPHP_EMBED_GET_MODULE_FUNCTION(TYPEPHP_PROJECT_NAME);
TYPEPHP_RUNTIME_INIT_FUNCTION(TYPEPHP_PROJECT_NAME) {
return typephp_runtime_start(TYPEPHP_EMBED_GET_MODULE(TYPEPHP_PROJECT_NAME), argc, argv);
}
#ifndef TYPEPHP_NO_MAIN
int main(int cpp_argc, char **cpp_argv) {
rc = TYPEPHP_RUNTIME_INIT(TYPEPHP_PROJECT_NAME)(cpp_argc, cpp_argv);
// ... 调用用户的 main() 函数 ...
TYPEPHP_RUNTIME_SHUTDOWN(TYPEPHP_PROJECT_NAME)();
return rc;
}
#endif
通过宏 TYPEPHP_PROJECT_NAME 避免多个 TypePHP 编译模块符号冲突。
4.4 PHP Embed Bug 修复
代码中特别注释了 PHP Embed 的一个 double-free bug :所有 interned strings 在请求关闭时被释放一次,然后在 php_embed_shutdown 中又被释放一次,导致 use-after-free。PHPX 通过在 module_shutdown 中手动将模块从 module_registry 哈希表中移除来规避这个问题。
五、php::fn ------ 直连函数层(性能关键)
普通方式调用 PHP 内置函数需要经过 zend_call_function(),涉及函数表查找、参数打包、栈帧创建等开销。PHPX 的 php::fn 命名空间提供了直接调用 Zend 内部 C 函数的封装,消除这层开销。
5.1 P0 级:纯内联(零开销)
namespace php::fn {
inline Int strlen(const String &s) {
return static_cast<Int>(s.length()); // 直接读 zend_string.len
}
inline Bool is_array(const Variant &value) {
return value.isArray(); // 直接 Z_TYPE_P 检查
}
inline Bool is_int(const Variant &value) {
return Z_TYPE_P(value.unwrap_ptr()) == IS_LONG; // 单行宏展开
}
}
这些函数在编译后就是几条 CPU 指令,没有函数调用开销。
5.2 P1 级:直接 Zend API
inline Int strcmp(const String &s1, const String &s2) {
return zend_binary_strcmp(s1.data(), s1.length(), s2.data(), s2.length());
}
inline String gettype(const Variant &value) {
zend_string *s = zend_zval_get_legacy_type(value.unwrap_ptr());
return String(s, php::Ctor::Move);
}
直接调用 zend_binary_strcmp、zend_zval_get_legacy_type 等 Zend 导出的 C 函数,跳过 zend_call_function。
5.3 覆盖范围
php::fn 覆盖了 60+ PHP 内置函数,按扩展分组:
func/core.h------ 核心函数(defined、define、function_exists 等)func/standard.h------ 标准库(array_、str_、var_dump、print_r 等)func/pcre.h、func/json.h、func/mbstring.h、func/curl.h、func/pdo.h等
六、php::std ------ AOT 标准库
php::std 是专门为 AOT 编译优化的标准库,与 php::fn 的区别在于:
php::fn封装的是已有 PHP 内置函数的直连版本php::std提供的是TypePHP 特有的原生类型和容器的方法实现
6.1 模块划分
| 头文件 | 内容 |
|---|---|
std/core.h |
核心工具(类型检查、类/函数存在性、get_class/gettype 等) |
std/array.h |
数组操作(array_map、array_filter、array_merge 等的直连实现) |
std/string.h |
字符串操作(strtoupper、strtolower、substr、explode 等) |
std/math.h |
数学函数(abs、floor、ceil、round、sqrt 等) |
std/datetime.h |
日期时间(date、time、strtotime、DateTime 方法等) |
std/fs.h |
文件系统(file_get_contents、file_put_contents、unlink 等) |
std/misc.h |
杂项(var_dump、print_r、sleep、usleep 等) |
6.2 通用方法(Universal Methods)的实现位置
TypePHP 中 $s->upper()、$arr->contains() 等通用方法,在编译期被解析为对 php::std 中对应函数的直接调用。例如 $s->upper() 编译为 php::std::strtoupper(s),完全没有方法派发开销。
七、Native GC ------ 原生对象垃圾回收
phpx_native_gc.h 实现了一套让 C++ 对象参与 PHP GC 的机制,这是 #[Native] 类能够正确管理内存的基础。
7.1 核心数据结构
struct NativeTypeDescriptor {
const char *name;
size_t size;
size_t alignment;
NativeTraceFn trace; // GC 标记阶段:遍历对象引用的 PHP 值
NativeFinalizeFn finalize; // 析构阶段:调用 C++ 析构逻辑
NativeDestroyFn destroy; // 释放阶段:释放 C++ 对象内存
};
7.2 NativeRootFrame ------ 根帧管理
class NativeRootFrame {
NativeRootFrame(NativeRootSlot *slots, size_t count);
~NativeRootFrame();
};
在函数调用栈上注册 C++ 原生对象指针作为 GC 根,确保函数执行期间这些对象不会被 PHP GC 错误回收。NativeRootSlot 使用类型擦除(void* + 访问函数指针)来安全地存储 T**,避免 C++ 严格别名规则违规。
7.3 NativeFinalizerChain ------ 继承析构链
class NativeFinalizerChain {
template <typename Callback>
void run(Callback &&callback) noexcept {
try { callback(); }
catch (zend_object *exception) { remember(exception); }
catch (...) { rememberCurrentException(); }
}
void rethrow(); // 所有析构执行完后重新抛出第一个异常
};
解决 C++ 继承体系中派生类析构抛出异常导致基类析构被跳过的问题------先执行所有析构,保存第一个异常,最后统一重抛。
八、高精度数值类型
| PHP 类型 | C++ 类 | 底层库 | 用途 |
|---|---|---|---|
bigInt |
php::BigInt |
GMP (GNU Multiple Precision) | 任意精度整数 |
decimal |
php::Decimal |
libmpdec(已随 PHPX 内置) | 精确十进制运算(无浮点误差) |
bigFloat |
php::BigFloat |
MPFR (Multiple Precision Floating-Point) | 任意精度浮点数 |
这些类型通过 phpx_big_int.h、phpx_decimal.h、phpx_big_float.h 暴露,支持运算符重载和方法链式调用($a->add($b)->mul(2)->toString())。
thirdparty/mpdecimal/ 目录包含完整的 libmpdec 源码(含 libmpdec C 库和 libmpdec++ C++ 封装),编译时静态链接进 PHPX,无需系统安装。
九、Python 桥接(phpx_python.h)
PHPX 内置了 Python 互操作层,支持:
- 在 PHP/C++ 代码中调用 Python 函数
- 在 Python 中调用 PHP 函数
- 类型自动转换(PHP Variant ↔ Python 对象)
TypePHP 的 --gen-python-helper 和 --convert-python-to-php 工具就建立在这层桥接之上。
十、扩展注册层(Class/Func/Constant)
10.1 覆盖范围
PHPX 预封装了 50+ PHP 扩展的类和函数注册,包括:
| 分类 | 扩展 |
|---|---|
| 核心 | standard, core, date, pcre, json, hash, filter, ctype |
| 数据库 | mysqli, pdo, pdo_mysql, pdo_sqlite, sqlite3 |
| 网络 | curl, sockets, openssl, swoole |
| 文本 | mbstring, iconv, tokenizer, gettext |
| XML | dom, xml, xmlreader, xmlwriter, simplexml, xsl, libxml |
| 图像 | gd, exif |
| 压缩 | zip, zlib, bz2 |
| 系统 | posix, pcntl, shmop, random, sodium, calendar |
| 其他 | spl, reflection, phar, session, fileinfo |
10.2 注册机制
PHPX_EXTENSION() {
Extension *ext = new Extension("my_extension", "1.0.0");
ext->onStart = [ext]() noexcept {
// 注册常量
ext->registerConstant("MY_CONST", 10000);
// 注册类
Class *c = new Class("MyClass");
c->addProperty("name", "", ZEND_ACC_PUBLIC);
c->registerFunctions(class_MyClass_methods); // 来自 arginfo
ext->registerClass(c);
// 注册函数
ext->registerFunction(PHPX_FN(my_function));
};
return ext;
}
使用 Lambda 回调管理生命周期(onStart/onShutdown),比传统 PHP 扩展的 PHP_MINIT_FUNCTION 宏更灵活。
10.3 arginfo 自动生成
bin/gen_stub.php 从 .stub.php 声明文件生成 *_arginfo.h,包含参数类型信息、函数签名、类方法表。这与 TypePHP 的 .stub.php 机制完全一致------TypePHP 编译器直接复用 PHPX 的 stub 体系。
十一、WASI/WebAssembly 支持
wasm/ 目录包含 WASI 构建支持:
build.sh/build-deps.sh/toolchain.sh------ WASI 工具链构建脚本CMakeLists.txt------ WASM 目标的 CMake 配置Wasi.php平台类 ------ WASI 平台抽象
PHPX 可以编译为 WASM 静态库,TypePHP 的 --wasm 模式就是将 PHP → C++ → WASM,通过 WASI 0.2 Component Model 运行。
十二、第三方依赖
| 依赖 | 位置 | 用途 |
|---|---|---|
| libmpdec | thirdparty/mpdecimal/ |
decimal 高精度十进制(内置,静态链接) |
| wren-gc | thirdparty/wren-gc/ |
Wren 语言的 GC 实现(用于 Native GC 实验) |
| GMP | 系统库 | bigInt 任意精度整数 |
| MPFR | 系统库 | bigFloat 任意精度浮点 |
十三、与 TypePHP 编译器的协作关系
┌──────────────────────────────────────────────────────────────┐
│ TypePHP 编译器 (src/) │
│ 纯 PHP 实现,负责:解析、语义分析、SSA优化、C++代码生成 │
│ 生成的代码中大量使用 php::Variant、php::Array、php::fn::* 等 │
└──────────────────────────────┬───────────────────────────────┘
│ 生成的 C++ 代码 #include
▼
┌──────────────────────────────────────────────────────────────┐
│ PHPX (phpx/) │
│ 纯 C++17 实现,负责: │
│ - zval/HashTable/zend_object 的类型安全 C++ 封装 │
│ - 嵌入式 PHP 运行时初始化/关闭 │
│ - 60+ 内置函数的直连 C++ 封装(消除 call_function 开销) │
│ - 50+ PHP 扩展的类/函数/常量注册 │
│ - Native GC(C++ 对象参与 PHP GC) │
│ - 高精度数值(GMP/MPFR/libmpdec) │
│ - std 容器 Box(std::vector/map 包装为 PHP 对象) │
│ - Python 桥接、WASI 支持 │
└──────────────────────────────┬───────────────────────────────┘
│ 链接
▼
┌──────────────────────────────────────────────────────────────┐
│ libphp (PHP embed SAPI) │
│ Zend Engine 核心,提供所有 PHP 语义 │
└──────────────────────────────────────────────────────────────┘
关键协作点:
- TypePHP 的
use native_types生成int64_t/double原生变量,不需要 PHPX 封装 - TypePHP 的动态值(
array、object、无类型声明的变量)生成php::Variant,由 PHPX 管理 - TypePHP 的
std::vector/std::map生成StdContainerBox<T>,由 PHPX 的 Box 机制包装 - TypePHP 的内置函数调用优先生成
php::fn::xxx()直连调用,回退到php::call() - TypePHP 的
#[Native]类依赖 PHPX 的 Native GC 和 NativeTypeDescriptor - TypePHP 的二进制模式依赖 PHPX 的
typephp_runtime_start/stop嵌入式运行时 - TypePHP 的
.stub.php和 arginfo 体系直接复用 PHPX 的gen_stub.php
总结
PHPX 不是一个简单的 "C++ 包装 Zend API" 的薄封装,而是一个深度优化的 AOT 运行时库,其设计处处为 TypePHP 编译器的需求服务:
- RAII 类型安全封装消除了手动 zval 引用计数管理
- php::fn 直连层 消除了
zend_call_function的动态派发开销,是 AOT 性能的关键 - 嵌入式运行时让编译产物可以脱离 PHP CLI 独立运行
- Native GC + Box让 C++ 原生对象和容器可以无缝融入 PHP 对象体系
- 高精度数值 + std 容器提供了 PHP 原生不具备的性能类型
- 完整的扩展注册层让编译产物可以作为标准 PHP 扩展加载
PHPX 与 TypePHP 编译器是共生关系:编译器负责将 PHP 语义翻译为 C++,PHPX 负责在 C++ 层面高效实现这些语义并对接 Zend Engine。二者结合,才实现了 "PHP 语法 + 原生性能" 的目标。