}
/* }}} */
-ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */
+static zend_string *zend_create_method_string(zend_string *class_name, zend_string *method_name) {
+ zend_string *callable_name = zend_string_alloc(
+ ZSTR_LEN(class_name) + ZSTR_LEN(method_name) + sizeof("::") - 1, 0);
+ char *ptr = ZSTR_VAL(callable_name);
+ memcpy(ptr, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
+ ptr += ZSTR_LEN(class_name);
+ memcpy(ptr, "::", sizeof("::") - 1);
+ ptr += sizeof("::") - 1;
+ memcpy(ptr, ZSTR_VAL(method_name), ZSTR_LEN(method_name) + 1);
+ return callable_name;
+}
+
+ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *object) /* {{{ */
+{
+try_again:
+ switch (Z_TYPE_P(callable)) {
+ case IS_STRING:
+ if (object) {
+ return zend_create_method_string(object->ce->name, Z_STR_P(callable));
+ }
+ return zend_string_copy(Z_STR_P(callable));
+
+ case IS_ARRAY:
+ {
+ zval *method = NULL;
+ zval *obj = NULL;
+
+ if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
+ obj = zend_hash_index_find_deref(Z_ARRVAL_P(callable), 0);
+ method = zend_hash_index_find_deref(Z_ARRVAL_P(callable), 1);
+ }
+
+ if (obj == NULL || method == NULL || Z_TYPE_P(method) != IS_STRING) {
+ return zend_string_init("Array", sizeof("Array")-1, 0);
+ }
+
+ if (Z_TYPE_P(obj) == IS_STRING) {
+ return zend_create_method_string(Z_STR_P(obj), Z_STR_P(method));
+ } else if (Z_TYPE_P(obj) == IS_OBJECT) {
+ return zend_create_method_string(Z_OBJCE_P(obj)->name, Z_STR_P(method));
+ } else {
+ return zend_string_init("Array", sizeof("Array")-1, 0);
+ }
+ }
+ case IS_OBJECT:
+ {
+ zend_class_entry *calling_scope;
+ zend_function *fptr;
+ zend_object *object;
+ if (Z_OBJ_HANDLER_P(callable, get_closure)
+ && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &calling_scope, &fptr, &object) == SUCCESS) {
+ zend_class_entry *ce = Z_OBJCE_P(callable);
+ zend_string *callable_name = zend_string_alloc(
+ ZSTR_LEN(ce->name) + sizeof("::__invoke") - 1, 0);
+ memcpy(ZSTR_VAL(callable_name), ZSTR_VAL(ce->name), ZSTR_LEN(ce->name));
+ memcpy(ZSTR_VAL(callable_name) + ZSTR_LEN(ce->name), "::__invoke", sizeof("::__invoke"));
+ return callable_name;
+ }
+ return zval_get_string(callable);
+ }
+ case IS_REFERENCE:
+ callable = Z_REFVAL_P(callable);
+ goto try_again;
+ default:
+ return zval_get_string(callable);
+ }
+}
+/* }}} */
+
+ZEND_API zend_string *zend_get_callable_name(zval *callable) /* {{{ */
+{
+ return zend_get_callable_name_ex(callable, NULL);
+}
+/* }}} */
+
+static zend_bool zend_is_callable_impl(zval *callable, zend_object *object, uint32_t check_flags, zend_fcall_info_cache *fcc, char **error) /* {{{ */
{
zend_bool ret;
zend_fcall_info_cache fcc_local;
- if (callable_name) {
- *callable_name = NULL;
- }
if (fcc == NULL) {
fcc = &fcc_local;
}
if (object) {
fcc->object = object;
fcc->calling_scope = object->ce;
- if (callable_name) {
- char *ptr;
-
- *callable_name = zend_string_alloc(ZSTR_LEN(fcc->calling_scope->name) + Z_STRLEN_P(callable) + sizeof("::") - 1, 0);
- ptr = ZSTR_VAL(*callable_name);
- memcpy(ptr, ZSTR_VAL(fcc->calling_scope->name), ZSTR_LEN(fcc->calling_scope->name));
- ptr += ZSTR_LEN(fcc->calling_scope->name);
- memcpy(ptr, "::", sizeof("::") - 1);
- ptr += sizeof("::") - 1;
- memcpy(ptr, Z_STRVAL_P(callable), Z_STRLEN_P(callable) + 1);
- }
- } else if (callable_name) {
- *callable_name = zend_string_copy(Z_STR_P(callable));
}
+
if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
fcc->called_scope = fcc->calling_scope;
return 1;
ZVAL_DEREF(obj);
if (Z_TYPE_P(obj) == IS_STRING) {
- if (callable_name) {
- char *ptr;
-
-
- *callable_name = zend_string_alloc(Z_STRLEN_P(obj) + Z_STRLEN_P(method) + sizeof("::") - 1, 0);
- ptr = ZSTR_VAL(*callable_name);
- memcpy(ptr, Z_STRVAL_P(obj), Z_STRLEN_P(obj));
- ptr += Z_STRLEN_P(obj);
- memcpy(ptr, "::", sizeof("::") - 1);
- ptr += sizeof("::") - 1;
- memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1);
- }
-
if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
return 1;
}
fcc->object = Z_OBJ_P(obj);
- if (callable_name) {
- char *ptr;
-
- *callable_name = zend_string_alloc(ZSTR_LEN(fcc->calling_scope->name) + Z_STRLEN_P(method) + sizeof("::") - 1, 0);
- ptr = ZSTR_VAL(*callable_name);
- memcpy(ptr, ZSTR_VAL(fcc->calling_scope->name), ZSTR_LEN(fcc->calling_scope->name));
- ptr += ZSTR_LEN(fcc->calling_scope->name);
- memcpy(ptr, "::", sizeof("::") - 1);
- ptr += sizeof("::") - 1;
- memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1);
- }
-
if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
fcc->called_scope = fcc->calling_scope;
return 1;
} else {
if (error) zend_spprintf(error, 0, "array must have exactly two members");
}
- if (callable_name) {
- *callable_name = zend_string_init("Array", sizeof("Array")-1, 0);
- }
}
return 0;
case IS_OBJECT:
if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &fcc->calling_scope, &fcc->function_handler, &fcc->object) == SUCCESS) {
fcc->called_scope = fcc->calling_scope;
- if (callable_name) {
- zend_class_entry *ce = Z_OBJCE_P(callable); /* TBFixed: what if it's overloaded? */
-
- *callable_name = zend_string_alloc(ZSTR_LEN(ce->name) + sizeof("::__invoke") - 1, 0);
- memcpy(ZSTR_VAL(*callable_name), ZSTR_VAL(ce->name), ZSTR_LEN(ce->name));
- memcpy(ZSTR_VAL(*callable_name) + ZSTR_LEN(ce->name), "::__invoke", sizeof("::__invoke"));
- }
fcc->initialized = 1;
return 1;
}
- if (callable_name) {
- *callable_name = zval_get_string(callable);
- }
if (error) zend_spprintf(error, 0, "no array or string given");
return 0;
case IS_REFERENCE:
callable = Z_REFVAL_P(callable);
goto again;
default:
- if (callable_name) {
- *callable_name = zval_get_string(callable);
- }
if (error) zend_spprintf(error, 0, "no array or string given");
return 0;
}
}
/* }}} */
+ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */
+{
+ zend_bool ret = zend_is_callable_impl(callable, object, check_flags, fcc, error);
+ if (callable_name) {
+ *callable_name = zend_get_callable_name_ex(callable, object);
+ }
+ return ret;
+}
+
ZEND_API zend_bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name) /* {{{ */
{
return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL);