php扩展实践zend_execute_ex层获取实参
其实在实现的 php 函数里面是很容易获取到的,参考 php 的 builtin 函数 func_get_args()
就可以知道了。
void **p;
int arg_count;
int i;
zend_execute_data *ex = EG(current_execute_data);
if (!ex || !ex->function_state.arguments) {
RETURN_FALSE;
}
p = ex->function_state.arguments;
arg_count = (int)(zend_uintptr_t) *p;
for (i = 0; i < arg_count; i++) {
zval *element, *arg;
arg = *((zval **) (p - (arg_count - i)));
php_var_dump(&arg, 1 TSRMLS_CC);
}
但是在 zend_execute_ex 中,是不能使用 function_state.arguments
来获取参数的,需要从 argument_stack
中获取调用函数的实参。
static void (*old_zend_execute_ex) (zend_execute_data *execute_data TSRMLS_DC);
ZEND_API void learn_execute_ex (zend_execute_data *execute_data TSRMLS_DC)
{
php_printf("====== extension debug start ======\n");
php_printf("function name: %s\n", get_active_function_name(TSRMLS_C));
old_zend_execute_ex(execute_data TSRMLS_CC);
int stacked = 0;
void **top;
void **bottom;
zval *arguments;
smart_str buf = {0};
array_init(arguments);
top = zend_vm_stack_top(TSRMLS_C) - 1;
if (top) {
stacked = (int)(zend_uintptr_t) *top; // argc
if (stacked) {
bottom = zend_vm_stack_top(TSRMLS_C);
EG(argument_stack)->top = top + 1;
if (zend_copy_parameters_array(stacked, arguments TSRMLS_CC) == SUCCESS) {
php_json_encode(&buf, arguments, 0 TSRMLS_CC);
}
EG(argument_stack)->top = bottom;
}
}
smart_str_0(&buf);
php_printf("%s\n", buf.c);
smart_str_free(&buf);
zval_dtor(arguments);
php_printf("====== extension debug end ======\n");
}
PHP_MINIT_FUNCTION(learn)
{
old_zend_execute_ex = zend_execute_ex;
zend_execute_ex = learn_execute_ex;
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(learn)
{
zend_execute_ex = old_zend_execute_ex;
return SUCCESS;
}
2015-11-04 00:38 更新
后来看到,其实不用上面这中方法就可以实现, php 5.5之后要从 prev 里面去取
/**
* php_var_dump defined in this head file.
*/
#include "ext/standard/php_var.h"
zend_execute_data *real_execute_data = execute_data->prev_execute_data;
void **p = real_execute_data->function_state.arguments;
int arg_count = (int) (zend_uintptr_t) * p;
zval *argument_element;
int i;
// zval *obj = real_execute_data->object;
unsigned long start = mach_absolute_time();
for (i = 0; i < arg_count; i++) {
argument_element = *(p - (arg_count - i));
php_var_dump(&argument_element, 1);
}
强悍..想请教一下,有办法能获取函数的参数名或者函数参数列表吗?目前能想到的,只有注释,然后反射获取.
execute_data 里面就有