如何用PHP扩展覆盖Zend内部函数?实现遇阻求助
修复PHP7.3下var_dump钩子不生效的问题
我刚帮你排查了代码里的问题,主要有两个核心原因导致你的hook逻辑没生效,咱们一步步来修复:
1. 模块入口未注册MINIT初始化函数
你的zend_module_entry结构体里,把模块初始化(MINIT)的回调参数设成了NULL,PHP根本不会执行你写的PHP_MINIT_FUNCTION(hook_php)函数,自然也就没完成var_dump的替换逻辑。
修改后的模块入口结构体:
zend_module_entry hook_php_module_entry = { STANDARD_MODULE_HEADER, PHP_HOOK_EXTNAME, hook_php_functions, PHP_MINIT(hook_php), // 替换原来的NULL,指定MINIT回调 NULL, NULL, NULL, NULL, PHP_HOOK_VERSION, STANDARD_MODULE_PROPERTIES };
2. MINIT阶段误用请求级函数表查找全局内置函数
EG(function_table)是请求级别的执行环境函数表,在模块初始化(MINIT)阶段,请求还未启动,这个表是未初始化的状态。你需要使用全局的内置函数表zend_global_function_table来查找var_dump。
同时别忘了在MINIT函数末尾返回SUCCESS,符合PHP扩展的规范:
PHP_MINIT_FUNCTION(hook_php) { zend_function *original; // 替换EG(function_table)为全局函数表指针 original = zend_hash_str_find_ptr(&zend_global_function_table, "var_dump", sizeof("var_dump")-1); if (original != NULL) { original_handler_var_dump = original->internal_function.handler; original->internal_function.handler = my_overwrite_var_dump; } return SUCCESS; }
3. 优化函数指针类型定义(可选但推荐)
你代码里针对PHP版本的zif_handlertypedef可以替换成官方定义的ZEND_FUNCTION_HANDLER类型,不用自己维护版本判断:
// 替换原来的#if PHP_VERSION_ID <70200那段代码 ZEND_FUNCTION_HANDLER original_handler_var_dump;
完整修复后的php_hook.c代码
// include the PHP API itself #include <php.h> // then include the header of your extension #include "php_hook.h" // register our function to the PHP API // so that PHP knows, which functions are in this module zend_function_entry hook_php_functions[] = { ZEND_NAMED_FE(my_overwrite_var_dump, my_overwrite_var_dump, NULL) {NULL, NULL, NULL} }; // some pieces of information about our module zend_module_entry hook_php_module_entry = { STANDARD_MODULE_HEADER, PHP_HOOK_EXTNAME, hook_php_functions, PHP_MINIT(hook_php), NULL, NULL, NULL, NULL, PHP_HOOK_VERSION, STANDARD_MODULE_PROPERTIES }; // use a macro to output additional C code, to make ext dynamically loadable ZEND_GET_MODULE(hook_php) // 使用官方定义的函数句柄类型 ZEND_FUNCTION_HANDLER original_handler_var_dump; ZEND_NAMED_FUNCTION(my_overwrite_var_dump) { php_printf("hooked (var_dump))\n"); // if we want to call the original function original_handler_var_dump(INTERNAL_FUNCTION_PARAM_PASSTHRU); } PHP_MINIT_FUNCTION(hook_php) { zend_function *original; original = zend_hash_str_find_ptr(&zend_global_function_table, "var_dump", sizeof("var_dump")-1); if (original != NULL) { original_handler_var_dump = original->internal_function.handler; original->internal_function.handler = my_overwrite_var_dump; } return SUCCESS; }
测试验证
重新编译安装你的扩展后,调用var_dump(1),应该会先输出hooked (var_dump)),然后再输出int(1),说明钩子已经生效了。
内容的提问来源于stack exchange,提问作者fufyayokku




