在扩展中调用PHP函数是一件很繁琐的事情,这里给大家带来一个现成的函数,可以极大的方便大家在扩展中调用php函数与方法。
函数原型:int walu_call_user_function(zval** retval, zval* obj, char* function_name, char* paras, …);
调用成功返回1,失败返回0.
各个参数的说明:
retval,zval**类型的,代表返回值。如果你需要返回值,请传递一个zval**类型的变量,不需要返回值可以传递NULL。
obj,对象实例对应的zval*,如果是PHP函数此处传递NULL。
function_name,字符串,内容为函数或者方法的名称。
paras,字符串,由一系列转换字符组成,转换字符由:s,b,z,n组成。
其它参数,根据paras里的转换字符,给出具体的数据,每个转换字符对应的数据如下:
s : char* str, int len。
b : int bool, 1代表true,0代表false。
n : 代表NULL,它不需要提供数据。
z : zval *val, 一般是对象、数组、资源。
d : double num;
调用时候需要注意的几点:
对于z型参数,调用过程中walu_call_user_function本身不会修改、释放它。
对于参数中的retval,如果不是NULL,调用者使用完成后不要忘记zval_ptr_dtor(retval一下);
下面准备了几个实例,来解释它的用法。
实例一:调用explode函数,参数为”,”与“1,3,4”;
//调用函数测试:zval *val;walu_call_user_function(&val, NULL, "explode", "ss", ",", 1, "1,3,4", sizeof("1,3,4")-1);php_var_dump(&val); //看下函数调用的结果是多少啊~~zval_ptr_dtor(&val);//千万不要忘了这一步
输出为:
array(3) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "3"}
实例二:调用对象$obj的print_arg方法。
假设有这么一个类:
class demo{ public function print_arg() {
$args = func_get_args();
var_dump($args);
}}
test_call是扩展提供的一个函数,我们通过此函数接收$obj,然后调用它的args方法。
zval* obj;
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &obj) == -1){
php_printf("Wrong!\n");
return;
}//这次尝试一下不是用返回值。
walu_call_user_function(NULL, obj, "print_arg", "snbbd", "hello", sizeof("hello")-1, 1, 0, 1.29292);
输出为:
array(5) { [0]=> string(5) "hello" [1]=> NULL [2]=> bool(true) [3]=> bool(false) [4]=> float(1.29292)}源码:
#include "php.h"#include "php_ini.h"#include "ext/standard/info.h"#include "Zend/zend_list.h"#include "Zend/zend_interfaces.h" int walu_call_user_method(zval** retval, zval* obj, char* function_name, char* paras, ...){ //用于接收参数
short int paras_count=0;
zval*** parameters = NULL;
long long_tmp;
char *string_tmp;
zval *zval_tmp;
double dou_tmp;
int i; //仅与调用有关的变量
int fun_re, retval_is_null=0;
HashTable *function_table; //接收参数
paras_count = strlen(paras);
if(paras_count > 0) {
parameters = (zval***)emalloc(sizeof(zval**) * paras_count);
va_list ap;
va_start(ap,paras);
for(i=0; i<paras_count; i++) {
parameters[i = (zval**)emalloc(sizeof(zval*));
switch(paras[i) {
case 's':
MAKE_STD_ZVAL(*parameters[i);
string_tmp = va_arg(ap, char*);
long_tmp = va_arg(ap, long);
ZVAL_STRINGL(*parameters[i, string_tmp, long_tmp, 1);
break;
case 'l':
MAKE_STD_ZVAL(*parameters[i);
long_tmp = va_arg(ap, long);
ZVAL_LONG(*parameters[i, long_tmp);
break; case 'd':
MAKE_STD_ZVAL(*parameters[i);
dou_tmp = va_arg(ap, double);
ZVAL_DOUBLE(*parameters[i, dou_tmp);
break;
case 'n':
MAKE_STD_ZVAL(*parameters[i);
ZVAL_NULL(*parameters[i);
break;
case 'z':
zval_tmp = va_arg(ap, zval*);
*parameters[i = zval_tmp;
break;
case 'b':
MAKE_STD_ZVAL(*parameters[i);
ZVAL_BOOL(*parameters[i, (int)va_arg(ap, int));
break;
default:
zend_error(E_ERROR, "Unsupported type:%c in walu_call_user_function", paras[i); return 0;
}
}
va_end(ap);
} //构造参数执行call_user_function_ex
zval *_function_name;
MAKE_STD_ZVAL(_function_name);
ZVAL_STRINGL(_function_name, function_name, strlen(function_name), 1);
if(retval == NULL) {
retval_is_null = 1;
retval = (zval**)emalloc(sizeof(zval*));
} //开始函数调用
if(obj) {
function_table = &Z_OBJCE_P(obj)->function_table;
} else {
function_table = (CG(function_table));
}
zend_fcall_info fci;
fci.size = sizeof(fci);
fci.function_table = function_table;
fci.object_ptr = obj ? obj : NULL;
fci.function_name = _function_name;
fci.retval_ptr_ptr = retval;
fci.param_count = paras_count;
fci.params = parameters;
fci.no_separation = 1;
fci.symbol_table = NULL;
fun_re = zend_call_function(&fci, NULL TSRMLS_CC); //函数调用结束。
if(retval_is_null == 1) {
zval_ptr_dtor(retval);
efree(retval);
}
zval_ptr_dtor(&_function_name); //free掉parameter及其里面的每个元素zval**,及每个元素zval**对应的zval* //对于传进来的zval,不进行free,由参数调用者自行free
if(paras_count > 0) {
for(i=0; i<paras_count; i++) {
if(paras[i != 'z') {
zval_ptr_dtor(parameters[i);
}
efree(parameters[i);
}
efree(parameters);
}
return fun_re;
}
来源:walu的破笔头
转载地址:http://www.yezis.cn/thread-299-1-1.html