需通过Zend API在C代码中注册类:一、用zend_class_entry声明类,INIT_CLASS_ENTRY初始化并zend_register_internal_class注册;二、用zend_declare_property_*添加属性;三、按PHP_METHOD宏定义方法函数并验证参数;四、构造/析构函数分别用ZEND_ACC_CTOR/DTOR标志注册;五、config.m4和头文件需启用Zend类支持。

如果您正在开发PHP扩展并希望在其中添加自定义类定义,则需要通过Zend API在扩展的C代码中注册类结构、方法及属性。以下是实现该目标的具体方法:
一、使用 zend_class_entry 定义类结构
在PHP扩展中,类定义必须通过 zend_class_entry 类型变量声明,并在模块初始化阶段注册到Zend引擎。该结构承载类名、方法表、属性信息等元数据。
1、在扩展源码的头文件或 .c 文件顶部声明全局 zend_class_entry 变量:
zend_class_entry *my_class_entry;
2、定义类方法列表,使用 ZEND_FE_END 终止:
zend_function_entry my_class_methods[] = {
ZEND_ME(MyClass, __construct, arginfo_myclass_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
ZEND_ME(MyClass, sayHello, arginfo_myclass_sayhello, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
立即学习“PHP免费学习笔记(深入)”;
3、在 MINIT 函数中完成类注册:
INIT_CLASS_ENTRY(ce, "MyClass", my_class_methods);
my_class_entry = zend_register_internal_class(&ce);
二、为类添加属性(成员变量)
类属性需在类注册后通过 zend_declare_property_* 系列函数显式声明,否则无法在PHP用户空间访问或初始化。
1、在 MINIT 函数中类注册语句之后添加:
zend_declare_property_null(my_class_entry, "name", sizeof("name") - 1, ZEND_ACC_PUBLIC);
2、若需设置默认值,可使用 zend_declare_property_string:
zend_declare_property_string(my_class_entry, "version", sizeof("version") - 1, "1.0", ZEND_ACC_PUBLIC);
3、声明受保护或私有属性时,将 ZEND_ACC_PUBLIC 替换为 ZEND_ACC_PROTECTED 或 ZEND_ACC_PRIVATE。
三、实现类方法的C函数回调
每个类方法对应一个 C 函数,其签名必须符合 Zend 的调用约定:接受两个 zend_execute_data* 和 zval* 返回值参数,并通过 ZEND_PARSE_PARAMETERS_NONE 或 ZEND_PARSE_PARAMETERS_START 验证参数。
1、定义方法函数,例如 sayHello:
PHP_METHOD(MyClass, sayHello) {
zval *obj = getThis();
if (obj == NULL) { RETURN_NULL(); }
RETURN_STR(zend_string_init("Hello from C!", sizeof("Hello from C!") - 1, 0));
}
2、确保函数名与 zend_function_entry 中声明的名称严格一致(区分大小写)。
3、在方法内部使用 Z_OBJ_P(obj) 获取对象指针,配合 zend_read_property 获取属性值。
四、添加构造函数与析构函数
构造函数(__construct)和析构函数(__destruct)需分别通过 ZEND_ACC_CTOR 和 ZEND_ACC_DTOR 标志注册,并在对应 C 函数中处理对象初始化与资源清理逻辑。
1、定义构造函数 C 实现:
PHP_METHOD(MyClass, __construct) {
zval *name;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(name)
ZEND_PARSE_PARAMETERS_END();
zend_update_property_string(my_class_entry, getThis(), "name", sizeof("name") - 1, Z_STRVAL_P(name));
}
2、注册时在 zend_function_entry 中指定 ZEND_ACC_PUBLIC | ZEND_ACC_CTOR 标志。
3、析构函数需定义为 static void PHP_METHOD(MyClass, __destruct),并在 MINIT 中注册为 ZEND_ACC_PUBLIC | ZEND_ACC_DTOR。
五、编译时启用类定义支持
扩展的 config.m4 文件需确保启用 Zend 内部类机制,避免因宏未定义导致 zend_register_internal_class 失败。
1、在 config.m4 中确认包含以下检查:
PHP_CHECK_LIBRARY(zend, zend_register_internal_class, [
PHP_ADD_LIBRARY_WITH_PATH(zend, $PHP_ZEND_DIR/lib, ZEND_SHARED_LIBADD)
])
2、在 php_myext.h 中包含必要头文件:
#include "zend_interfaces.h"
#include "zend_exceptions.h"
3、在扩展的 module_entry 结构中,确保 ZEND_MODULE_STARTUP_D 所指向的 MINIT 函数已正确定义并导出。











