From: Marcus Boerger Date: Wed, 7 Jun 2006 09:43:54 +0000 (+0000) Subject: - MFH zend_fcall_info_*() and parameter parsing option 'f' X-Git-Tag: php-5.2.0RC1~350 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=64c353ab79e3a49ae2aba533d353d4a93fe4b099;p=php - MFH zend_fcall_info_*() and parameter parsing option 'f' # Right now i see this as the best option but we might shuffle code around # later if someone comes up with a better solution. --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 31faa25e7a..57892f3b99 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -566,6 +566,22 @@ static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **sp } break; + case 'f': + { + zend_fcall_info *fci = va_arg(*va, zend_fcall_info *); + zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *); + + if (zend_fcall_info_init(*arg, fci, fcc TSRMLS_CC) == SUCCESS) { + break; + } else if (return_null) { + fci->size = 0; + fcc->initialized = 0; + break; + } else { + return "function"; + } + } + case 'z': { zval **p = va_arg(*va, zval **); @@ -2309,6 +2325,96 @@ ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRML } +ZEND_API int zend_fcall_info_init(zval *callable, zend_fcall_info *fci, zend_fcall_info_cache *fcc TSRMLS_DC) +{ + zend_class_entry *ce; + zend_function *func; + zval **obj; + + if (!zend_is_callable_ex(callable, IS_CALLABLE_STRICT, NULL, NULL, &ce, &func, &obj TSRMLS_CC)) { + return FAILURE; + } + + fci->size = sizeof(*fci); + fci->function_table = ce ? &ce->function_table : EG(function_table); + fci->object_pp = obj; + fci->function_name = NULL; + fci->retval_ptr_ptr = NULL; + fci->param_count = 0; + fci->params = NULL; + fci->no_separation = 1; + fci->symbol_table = NULL; + + fcc->initialized = 1; + fcc->function_handler = func; + fcc->calling_scope = ce; + fcc->object_pp = obj; + + return SUCCESS; +} + + +ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args TSRMLS_DC) +{ + HashPosition pos; + zval **arg, ***params; + + if (fci->params) { + while (fci->param_count) { + zval_ptr_dtor(fci->params[--fci->param_count]); + } + efree(fci->params); + } + fci->params = NULL; + fci->param_count = 0; + + if (!args) { + return SUCCESS; + } + + if (Z_TYPE_P(args) != IS_ARRAY) { + return FAILURE; + } + + fci->param_count = zend_hash_num_elements(Z_ARRVAL_P(args)); + fci->params = params = (zval***)safe_emalloc(sizeof(zval**), fci->param_count, 0); + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos); + + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **) &arg, &pos) == SUCCESS) { + *params++ = arg; + (*arg)->refcount++; + zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos); + } + return SUCCESS; +} + + +ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval **retval_ptr_ptr, zval *args TSRMLS_DC) +{ + zval *retval, ***org_params; + int result, org_count; + + fci->retval_ptr_ptr = retval_ptr_ptr ? retval_ptr_ptr : &retval; + if (args) { + org_params = fci->params; + org_count = fci->param_count; + zend_fcall_info_args(fci, args TSRMLS_CC); + } + result = zend_call_function(fci, fcc TSRMLS_CC); + + if (!retval_ptr_ptr && retval) { + zval_ptr_dtor(&retval); + } + if (args) { + zend_fcall_info_args(fci, NULL TSRMLS_CC); + fci->params = org_params; + fci->param_count = org_count; + } + return result; +} + + ZEND_API char *zend_get_module_version(char *module_name) { zend_module_entry *module; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 2669ea216c..89c62e6d26 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -385,6 +385,26 @@ typedef struct _zend_fcall_info_cache { BEGIN_EXTERN_C() ZEND_API extern zend_fcall_info_cache empty_fcall_info_cache; +/** Build zend_call_info/cache from a zval* + * + * Caller is responsible to provide a return value, otherwise the we will crash. + * fci->retval_ptr_ptr = NULL; + * In order to pass parameters the following members need to be set: + * fci->param_count = 0; + * fci->params = NULL; + */ +ZEND_API int zend_fcall_info_init(zval *callable, zend_fcall_info *fci, zend_fcall_info_cache *fcc TSRMLS_DC); + +/** Set or clear the arguments in the zend_call_info struct taking care of + * refcount. If args is NULL and arguments are set then those are cleared. + */ +ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args TSRMLS_DC); + +/** Call a function using information created by zend_fcall_info_init()/args(). + * If args is given then those replace the arguement info in fci is temporarily. + */ +ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval **retval, zval *args TSRMLS_DC); + ZEND_API int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC);