From: Marcus Boerger Date: Thu, 28 Jul 2005 20:55:50 +0000 (+0000) Subject: - Add convenience function zend_is_callable_ex() and base zend_is_callable X-Git-Tag: RELEASE_2_0_0~87 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53e526066202ac612b461bb11b24b5952291824c;p=php - Add convenience function zend_is_callable_ex() and base zend_is_callable and zend_make_callable on it. This functions allows to check if a php variable is a callable function and returns its function pointer as well as object if possible. # Commit this now so we can use it in 5.1.* series as discussed with Andi. --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 109c5f3223..752ca290b8 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1905,23 +1905,38 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_ return 1; } -ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name) +ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC) { char *lcname; - zend_bool retval = 0; - TSRMLS_FETCH(); + zend_bool retval = 0; + int callable_name_len_local; + zend_function *fptr_local; + zval **zobj_ptr_local; + + if (callable_name_len == NULL) { + callable_name_len = &callable_name_len_local; + } + if (fptr_ptr == NULL) { + fptr_ptr = &fptr_local; + } + if (zobj_ptr_ptr == NULL) { + zobj_ptr_ptr = &zobj_ptr_local; + } + *fptr_ptr = NULL; + *zobj_ptr_ptr = NULL; switch (Z_TYPE_P(callable)) { case IS_STRING: if (callable_name) { *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); + *callable_name_len = Z_STRLEN_P(callable); } if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) { return 1; } lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); - if (zend_hash_exists(EG(function_table), lcname, Z_STRLEN_P(callable)+1)) { + if (zend_hash_find(EG(function_table), lcname, Z_STRLEN_P(callable)+1, (void**)fptr_ptr) == SUCCESS) { retval = 1; } efree(lcname); @@ -1932,7 +1947,6 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal zval **method; zval **obj; zend_class_entry *ce = NULL, **pce; - zend_uint callable_name_len; if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2 && zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj) == SUCCESS && @@ -1944,14 +1958,14 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal if (callable_name) { char *ptr; - callable_name_len = Z_STRLEN_PP(obj) + Z_STRLEN_PP(method) + sizeof("::"); - ptr = *callable_name = emalloc(callable_name_len); + *callable_name_len = Z_STRLEN_PP(obj) + Z_STRLEN_PP(method) + sizeof("::") - 1; + ptr = *callable_name = emalloc(*callable_name_len + 1); memcpy(ptr, Z_STRVAL_PP(obj), Z_STRLEN_PP(obj)); ptr += Z_STRLEN_PP(obj); memcpy(ptr, "::", sizeof("::") - 1); ptr += sizeof("::") - 1; memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1); - } + } if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) return 1; @@ -1969,12 +1983,14 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal efree(lcname); } else { ce = Z_OBJCE_PP(obj); /* TBFixed: what if it's overloaded? */ + + *zobj_ptr_ptr = obj; if (callable_name) { char *ptr; - callable_name_len = ce->name_length + Z_STRLEN_PP(method) + sizeof("::"); - ptr = *callable_name = emalloc(callable_name_len); + *callable_name_len = ce->name_length + Z_STRLEN_PP(method) + sizeof("::") - 1; + ptr = *callable_name = emalloc(*callable_name_len + 1); memcpy(ptr, ce->name, ce->name_length); ptr += ce->name_length; memcpy(ptr, "::", sizeof("::") - 1); @@ -2003,6 +2019,13 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal } } } + if (retval) { + if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0 && (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0) { + retval = 0; + } else { + *fptr_ptr = fbc; + } + } } /* check for __call too */ if (retval == 0 && ce->__call != 0) { @@ -2012,6 +2035,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal } } else if (callable_name) { *callable_name = estrndup("Array", sizeof("Array")-1); + *callable_name_len = sizeof("Array") - 1; } } break; @@ -2023,6 +2047,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal zend_make_printable_zval(callable, &expr_copy, &use_copy); *callable_name = estrndup(Z_STRVAL(expr_copy), Z_STRLEN(expr_copy)); + *callable_name_len = Z_STRLEN(expr_copy); zval_dtor(&expr_copy); } break; @@ -2032,6 +2057,14 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal } +ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name) +{ + TSRMLS_FETCH(); + + return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC); +} + + ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC) { char *lcname, *func, *class_name; @@ -2039,7 +2072,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRML zend_class_entry **pce; int class_name_len; - if (zend_is_callable(callable, 0, callable_name)) { + if (zend_is_callable_ex(callable, 0, callable_name, NULL, NULL, NULL TSRMLS_CC)) { return 1; } switch (Z_TYPE_P(callable)) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index e28fa1b7c6..8e914d80b3 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -196,7 +196,9 @@ ZEND_API void zend_wrong_param_count(TSRMLS_D); #define IS_CALLABLE_CHECK_SYNTAX_ONLY (1<<0) #define IS_CALLABLE_CHECK_NO_ACCESS (1<<1) +#define IS_CALLABLE_CHECK_IS_STATIC (1<<2) +ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC); ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name); ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC); ZEND_API char *zend_get_module_version(char *module_name);