diff options
Diffstat (limited to 'ext/reflection')
29 files changed, 1012 insertions, 378 deletions
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 08acc7e5d2..df15efd077 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -60,10 +60,12 @@ PHPAPI zend_class_entry *reflection_function_ptr; PHPAPI zend_class_entry *reflection_generator_ptr; PHPAPI zend_class_entry *reflection_parameter_ptr; PHPAPI zend_class_entry *reflection_type_ptr; +PHPAPI zend_class_entry *reflection_named_type_ptr; PHPAPI zend_class_entry *reflection_class_ptr; PHPAPI zend_class_entry *reflection_object_ptr; PHPAPI zend_class_entry *reflection_method_ptr; PHPAPI zend_class_entry *reflection_property_ptr; +PHPAPI zend_class_entry *reflection_class_constant_ptr; PHPAPI zend_class_entry *reflection_extension_ptr; PHPAPI zend_class_entry *reflection_zend_extension_ptr; @@ -87,7 +89,7 @@ ZEND_DECLARE_MODULE_GLOBALS(reflection) /* Method macros */ #define METHOD_NOTSTATIC(ce) \ - if (!Z_OBJ(EX(This)) || !instanceof_function(Z_OBJCE(EX(This)), ce)) { \ + if ((Z_TYPE(EX(This)) != IS_OBJECT) || !instanceof_function(Z_OBJCE(EX(This)), ce)) { \ php_error_docref(NULL, E_ERROR, "%s() cannot be called statically", get_active_function_name()); \ return; \ } \ @@ -104,9 +106,10 @@ ZEND_DECLARE_MODULE_GLOBALS(reflection) #define GET_REFLECTION_OBJECT() \ intern = Z_REFLECTION_P(getThis()); \ - if (intern->ptr == NULL) { \ + if (intern->ptr == NULL) { \ RETURN_ON_EXCEPTION \ - php_error_docref(NULL, E_ERROR, "Internal error: Failed to retrieve the reflection object"); \ + zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); \ + return; \ } \ #define GET_REFLECTION_OBJECT_PTR(target) \ @@ -215,7 +218,8 @@ typedef enum { REF_TYPE_PARAMETER, REF_TYPE_TYPE, REF_TYPE_PROPERTY, - REF_TYPE_DYNAMIC_PROPERTY + REF_TYPE_DYNAMIC_PROPERTY, + REF_TYPE_CLASS_CONSTANT } reflection_type_t; /* Struct for reflection objects */ @@ -333,7 +337,7 @@ static void reflection_free_objects_storage(zend_object *object) /* {{{ */ efree(intern->ptr); break; case REF_TYPE_GENERATOR: - break; + case REF_TYPE_CLASS_CONSTANT: case REF_TYPE_OTHER: break; } @@ -368,6 +372,7 @@ static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{ static void _const_string(string *str, char *name, zval *value, char *indent); static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char* indent); static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent); +static void _class_const_string(string *str, char *name, zend_class_constant *c, char* indent); static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent); static void _extension_string(string *str, zend_module_entry *module, char *indent); static void _zend_extension_string(string *str, zend_extension *extension, char *indent); @@ -450,11 +455,10 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in string_printf(str, "%s - Constants [%d] {\n", indent, count); if (count > 0) { zend_string *key; - zval *value; + zend_class_constant *c; - ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, value) { - zval_update_constant_ex(value, 1, NULL); - _const_string(str, ZSTR_VAL(key), value, indent); + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { + _class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent.buf)); } ZEND_HASH_FOREACH_END(); } string_printf(str, "%s }\n", indent); @@ -631,6 +635,29 @@ static void _const_string(string *str, char *name, zval *value, char *indent) } /* }}} */ +/* {{{ _class_const_string */ +static void _class_const_string(string *str, char *name, zend_class_constant *c, char *indent) +{ + char *visibility = zend_visibility_string(Z_ACCESS_FLAGS(c->value)); + char *type; + + zval_update_constant_ex(&c->value, c->ce); + type = zend_zval_type_name(&c->value); + + if (Z_TYPE(c->value) == IS_ARRAY) { + string_printf(str, "%sConstant [ %s %s %s ] { Array }\n", + indent, visibility, type, name); + } else { + zend_string *value_str = zval_get_string(&c->value); + + string_printf(str, "%sConstant [ %s %s %s ] { %s }\n", + indent, visibility, type, name, ZSTR_VAL(value_str)); + + zend_string_release(value_str); + } +} +/* }}} */ + /* {{{ _get_recv_opcode */ static zend_op* _get_recv_op(zend_op_array *op_array, uint32_t offset) { @@ -640,7 +667,7 @@ static zend_op* _get_recv_op(zend_op_array *op_array, uint32_t offset) ++offset; while (op < end) { if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT - || op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == (zend_long)offset) + || op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == offset) { return op; } @@ -693,14 +720,10 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset); if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { zval zv; - zend_class_entry *old_scope; string_write(str, " = ", sizeof(" = ")-1); ZVAL_DUP(&zv, RT_CONSTANT(&fptr->op_array, precv->op2)); - old_scope = EG(scope); - EG(scope) = fptr->common.scope; - zval_update_constant_ex(&zv, 1, NULL); - EG(scope) = old_scope; + zval_update_constant_ex(&zv, fptr->common.scope); if (Z_TYPE(zv) == IS_TRUE) { string_write(str, "true", sizeof("true")-1); } else if (Z_TYPE(zv) == IS_FALSE) { @@ -1254,7 +1277,7 @@ static void reflection_type_factory(zend_function *fptr, zval *closure_object, s reflection_object *intern; type_reference *reference; - reflection_instantiate(reflection_type_ptr, object); + reflection_instantiate(reflection_named_type_ptr, object); intern = Z_REFLECTION_P(object); reference = (type_reference*) emalloc(sizeof(type_reference)); reference->arg_info = arg_info; @@ -1360,11 +1383,31 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info } /* }}} */ +/* {{{ reflection_class_constant_factory */ +static void reflection_class_constant_factory(zend_class_entry *ce, zend_string *name_str, zend_class_constant *constant, zval *object) +{ + reflection_object *intern; + zval name; + zval classname; + + ZVAL_STR_COPY(&name, name_str); + ZVAL_STR_COPY(&classname, ce->name); + + reflection_instantiate(reflection_class_constant_ptr, object); + intern = Z_REFLECTION_P(object); + intern->ptr = constant; + intern->ref_type = REF_TYPE_CLASS_CONSTANT; + intern->ce = constant->ce; + intern->ignore_visibility = 0; + reflection_update_property(object, "name", &name); + reflection_update_property(object, "class", &classname); +} +/* }}} */ + /* {{{ _reflection_export */ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_ptr, int ctor_argc) { zval reflector; - zval output, *output_ptr = &output; zval *argument_ptr, *argument2_ptr; zval retval, params[2]; int result; @@ -1394,9 +1437,7 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c /* Call __construct() */ fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); - fci.symbol_table = NULL; fci.object = Z_OBJ(reflector); fci.retval = &retval; fci.param_count = ctor_argc; @@ -1423,12 +1464,10 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c } /* Call static reflection::export */ - ZVAL_BOOL(&output, return_output); ZVAL_COPY_VALUE(¶ms[0], &reflector); - ZVAL_COPY_VALUE(¶ms[1], output_ptr); + ZVAL_BOOL(¶ms[1], return_output); ZVAL_STRINGL(&fci.function_name, "reflection::export", sizeof("reflection::export") - 1); - fci.function_table = &reflection_ptr->function_table; fci.object = NULL; fci.retval = &retval; fci.param_count = 2; @@ -1467,7 +1506,8 @@ static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTIO if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { return NULL; } - php_error_docref(NULL, E_ERROR, "Internal error: Failed to retrieve the reflection object"); + zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); + return NULL; } param = intern->ptr; @@ -1900,7 +1940,7 @@ ZEND_METHOD(reflection_function, getStaticVariables) fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables); } ZEND_HASH_FOREACH_VAL(fptr->op_array.static_variables, val) { - if (UNEXPECTED(zval_update_constant_ex(val, 1, fptr->common.scope) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(val, fptr->common.scope) != SUCCESS)) { return; } } ZEND_HASH_FOREACH_END(); @@ -1929,9 +1969,7 @@ ZEND_METHOD(reflection_function, invoke) } fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); - fci.symbol_table = NULL; fci.object = NULL; fci.retval = &retval; fci.param_count = num_args; @@ -1940,7 +1978,7 @@ ZEND_METHOD(reflection_function, invoke) fcc.initialized = 1; fcc.function_handler = fptr; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = NULL; fcc.object = NULL; @@ -1989,9 +2027,7 @@ ZEND_METHOD(reflection_function, invokeArgs) } ZEND_HASH_FOREACH_END(); fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); - fci.symbol_table = NULL; fci.object = NULL; fci.retval = &retval; fci.param_count = argc; @@ -2000,7 +2036,7 @@ ZEND_METHOD(reflection_function, invokeArgs) fcc.initialized = 1; fcc.function_handler = fptr; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = NULL; fcc.object = NULL; @@ -2285,7 +2321,7 @@ ZEND_METHOD(reflection_generator, getThis) REFLECTION_CHECK_VALID_GENERATOR(ex) - if (Z_OBJ(ex->This)) { + if (Z_TYPE(ex->This) == IS_OBJECT) { ZVAL_COPY(return_value, &ex->This); } else { ZVAL_NULL(return_value); @@ -2861,15 +2897,9 @@ ZEND_METHOD(reflection_parameter, getDefaultValue) return; } - ZVAL_COPY_VALUE(return_value, RT_CONSTANT(¶m->fptr->op_array, precv->op2)); + ZVAL_DUP(return_value, RT_CONSTANT(¶m->fptr->op_array, precv->op2)); if (Z_CONSTANT_P(return_value)) { - zend_class_entry *old_scope = EG(scope); - - EG(scope) = param->fptr->common.scope; - zval_update_constant_ex(return_value, 0, NULL); - EG(scope) = old_scope; - } else { - zval_copy_ctor(return_value); + zval_update_constant_ex(return_value, param->fptr->common.scope); } } /* }}} */ @@ -2970,33 +3000,74 @@ ZEND_METHOD(reflection_type, isBuiltin) } /* }}} */ +/* {{{ reflection_type_name */ +static zend_string *reflection_type_name(type_reference *param) { + switch (param->arg_info->type_hint) { + case IS_ARRAY: return zend_string_init("array", sizeof("array") - 1, 0); + case IS_CALLABLE: return zend_string_init("callable", sizeof("callable") - 1, 0); + case IS_OBJECT: + if (param->fptr->type == ZEND_INTERNAL_FUNCTION && + !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { + return zend_string_init(((zend_internal_arg_info*)param->arg_info)->class_name, strlen(((zend_internal_arg_info*)param->arg_info)->class_name), 0); + } + return zend_string_copy(param->arg_info->class_name); + case IS_STRING: return zend_string_init("string", sizeof("string") - 1, 0); + case _IS_BOOL: return zend_string_init("bool", sizeof("bool") - 1, 0); + case IS_LONG: return zend_string_init("int", sizeof("int") - 1, 0); + case IS_DOUBLE: return zend_string_init("float", sizeof("float") - 1, 0); + case IS_VOID: return zend_string_init("void", sizeof("void") - 1, 0); + case IS_ITERABLE: return zend_string_init("iterable", sizeof("iterable") - 1, 0); + EMPTY_SWITCH_DEFAULT_CASE() + } +} +/* }}} */ + /* {{{ proto public string ReflectionType::__toString() Return the text of the type hint */ ZEND_METHOD(reflection_type, __toString) { reflection_object *intern; type_reference *param; + zend_string *str; if (zend_parse_parameters_none() == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(param); + + str = reflection_type_name(param); + + if (param->arg_info->type_hint == IS_OBJECT + && !zend_string_equals_literal_ci(param->arg_info->class_name, "self") + && !zend_string_equals_literal_ci(param->arg_info->class_name, "parent")) { + str = zend_string_extend(str, ZSTR_LEN(str) + 1, 0); + memmove(ZSTR_VAL(str) + 1, ZSTR_VAL(str), ZSTR_LEN(str) + 1); + ZSTR_VAL(str)[0] = '\\'; + } + + if (param->arg_info->allow_null) { + str = zend_string_extend(str, ZSTR_LEN(str) + 1, 0); + memmove(ZSTR_VAL(str) + 1, ZSTR_VAL(str), ZSTR_LEN(str) + 1); + ZSTR_VAL(str)[0] = '?'; + } + + RETURN_STR(str); +} +/* }}} */ - switch (param->arg_info->type_hint) { - case IS_ARRAY: RETURN_STRINGL("array", sizeof("array") - 1); - case IS_CALLABLE: RETURN_STRINGL("callable", sizeof("callable") - 1); - case IS_OBJECT: - if (param->fptr->type == ZEND_INTERNAL_FUNCTION && - !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { - RETURN_STRING(((zend_internal_arg_info*)param->arg_info)->class_name); - } - RETURN_STR_COPY(param->arg_info->class_name); - case IS_STRING: RETURN_STRINGL("string", sizeof("string") - 1); - case _IS_BOOL: RETURN_STRINGL("bool", sizeof("bool") - 1); - case IS_LONG: RETURN_STRINGL("int", sizeof("int") - 1); - case IS_DOUBLE: RETURN_STRINGL("float", sizeof("float") - 1); - EMPTY_SWITCH_DEFAULT_CASE() +/* {{{ proto public string ReflectionNamedType::getName() + Return the text of the type hint */ +ZEND_METHOD(reflection_named_type, getName) +{ + reflection_object *intern; + type_reference *param; + + if (zend_parse_parameters_none() == FAILURE) { + return; } + GET_REFLECTION_OBJECT_PTR(param); + + RETURN_STR(reflection_type_name(param)); } /* }}} */ @@ -3154,19 +3225,18 @@ ZEND_METHOD(reflection_method, getClosure) } /* }}} */ -/* {{{ proto public mixed ReflectionMethod::invoke(mixed object, mixed* args) - Invokes the method. */ -ZEND_METHOD(reflection_method, invoke) +/* {{{ reflection_method_invoke */ +static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic) { zval retval; - zval *params = NULL; - zend_object *object; + zval *params = NULL, *val, *object; reflection_object *intern; zend_function *mptr; - int result, num_args = 0; + int i, argc = 0, result; zend_fcall_info fci; zend_fcall_info_cache fcc; zend_class_entry *obj_ce; + zval *param_array; METHOD_NOTSTATIC(reflection_method_ptr); @@ -3190,115 +3260,25 @@ ZEND_METHOD(reflection_method, invoke) return; } - if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", ¶ms, &num_args) == FAILURE) { - return; - } - - /* In case this is a static method, we should'nt pass an object_ptr - * (which is used as calling context aka $this). We can thus ignore the - * first parameter. - * - * Else, we verify that the given object is an instance of the class. - */ - if (mptr->common.fn_flags & ZEND_ACC_STATIC) { - object = NULL; - obj_ce = mptr->common.scope; - } else { - if (Z_TYPE(params[0]) != IS_OBJECT) { - _DO_THROW("Non-object passed to Invoke()"); - /* Returns from this function */ + if (variadic) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!*", &object, ¶ms, &argc) == FAILURE) { + return; } - - obj_ce = Z_OBJCE(params[0]); - - if (!instanceof_function(obj_ce, mptr->common.scope)) { - _DO_THROW("Given object is not an instance of the class this method was declared in"); - /* Returns from this function */ + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a", &object, ¶m_array) == FAILURE) { + return; } - object = Z_OBJ(params[0]); - } - - fci.size = sizeof(fci); - fci.function_table = NULL; - ZVAL_UNDEF(&fci.function_name); - fci.symbol_table = NULL; - fci.object = object; - fci.retval = &retval; - fci.param_count = num_args - 1; - fci.params = params + 1; - fci.no_separation = 1; - - fcc.initialized = 1; - fcc.function_handler = mptr; - fcc.calling_scope = obj_ce; - fcc.called_scope = intern->ce; - fcc.object = object; - - result = zend_call_function(&fci, &fcc); - - if (result == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Invocation of method %s::%s() failed", ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name)); - return; - } - - if (Z_TYPE(retval) != IS_UNDEF) { - ZVAL_COPY_VALUE(return_value, &retval); - } -} -/* }}} */ + argc = zend_hash_num_elements(Z_ARRVAL_P(param_array)); -/* {{{ proto public mixed ReflectionMethod::invokeArgs(mixed object, array args) - Invokes the function and pass its arguments as array. */ -ZEND_METHOD(reflection_method, invokeArgs) -{ - zval retval; - zval *params, *val, *object; - reflection_object *intern; - zend_function *mptr; - int i, argc; - int result; - zend_fcall_info fci; - zend_fcall_info_cache fcc; - zend_class_entry *obj_ce; - zval *param_array; - - METHOD_NOTSTATIC(reflection_method_ptr); - - GET_REFLECTION_OBJECT_PTR(mptr); - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a", &object, ¶m_array) == FAILURE) { - return; - } - - if ((!(mptr->common.fn_flags & ZEND_ACC_PUBLIC) - || (mptr->common.fn_flags & ZEND_ACC_ABSTRACT)) - && intern->ignore_visibility == 0) - { - if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Trying to invoke abstract method %s::%s()", - ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name)); - } else { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Trying to invoke %s method %s::%s() from scope %s", - mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private", - ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name), - ZSTR_VAL(Z_OBJCE_P(getThis())->name)); - } - return; + params = safe_emalloc(sizeof(zval), argc, 0); + argc = 0; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(param_array), val) { + ZVAL_COPY(¶ms[argc], val); + argc++; + } ZEND_HASH_FOREACH_END(); } - argc = zend_hash_num_elements(Z_ARRVAL_P(param_array)); - - params = safe_emalloc(sizeof(zval), argc, 0); - argc = 0; - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(param_array), val) { - ZVAL_COPY(¶ms[argc], val); - argc++; - } ZEND_HASH_FOREACH_END(); - /* In case this is a static method, we should'nt pass an object_ptr * (which is used as calling context aka $this). We can thus ignore the * first parameter. @@ -3310,7 +3290,6 @@ ZEND_METHOD(reflection_method, invokeArgs) obj_ce = mptr->common.scope; } else { if (!object) { - efree(params); zend_throw_exception_ex(reflection_exception_ptr, 0, "Trying to invoke non static method %s::%s() without an object", ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name)); @@ -3320,16 +3299,16 @@ ZEND_METHOD(reflection_method, invokeArgs) obj_ce = Z_OBJCE_P(object); if (!instanceof_function(obj_ce, mptr->common.scope)) { - efree(params); + if (!variadic) { + efree(params); + } _DO_THROW("Given object is not an instance of the class this method was declared in"); /* Returns from this function */ } } fci.size = sizeof(fci); - fci.function_table = NULL; ZVAL_UNDEF(&fci.function_name); - fci.symbol_table = NULL; fci.object = object ? Z_OBJ_P(object) : NULL; fci.retval = &retval; fci.param_count = argc; @@ -3340,21 +3319,25 @@ ZEND_METHOD(reflection_method, invokeArgs) fcc.function_handler = mptr; fcc.calling_scope = obj_ce; fcc.called_scope = intern->ce; - fcc.object = (object) ? Z_OBJ_P(object) : NULL; + fcc.object = object ? Z_OBJ_P(object) : NULL; - /* - * Copy the zend_function when calling via handler (e.g. Closure::__invoke()) - */ - if ((mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - fcc.function_handler = _copy_function(mptr); + if (!variadic) { + /* + * Copy the zend_function when calling via handler (e.g. Closure::__invoke()) + */ + if ((mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + fcc.function_handler = _copy_function(mptr); + } } result = zend_call_function(&fci, &fcc); - for (i = 0; i < argc; i++) { - zval_ptr_dtor(¶ms[i]); + if (!variadic) { + for (i = 0; i < argc; i++) { + zval_ptr_dtor(¶ms[i]); + } + efree(params); } - efree(params); if (result == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0, @@ -3368,6 +3351,22 @@ ZEND_METHOD(reflection_method, invokeArgs) } /* }}} */ +/* {{{ proto public mixed ReflectionMethod::invoke(mixed object, mixed* args) + Invokes the method. */ +ZEND_METHOD(reflection_method, invoke) +{ + reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + +/* {{{ proto public mixed ReflectionMethod::invokeArgs(mixed object, array args) + Invokes the function and pass its arguments as array. */ +ZEND_METHOD(reflection_method, invokeArgs) +{ + reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + /* {{{ proto public bool ReflectionMethod::isFinal() Returns whether this method is final */ ZEND_METHOD(reflection_method, isFinal) @@ -3656,6 +3655,197 @@ ZEND_METHOD(reflection_method, setAccessible) } /* }}} */ +/* {{{ proto public void ReflectionClassConstant::__construct(mixed class, string name) + Constructor. Throws an Exception in case the given class constant does not exist */ +ZEND_METHOD(reflection_class_constant, __construct) +{ + zval *classname, *object, name, cname; + zend_string *constname; + reflection_object *intern; + zend_class_entry *ce; + zend_class_constant *constant = NULL; + + if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zS", &classname, &constname) == FAILURE) { + return; + } + + object = getThis(); + intern = Z_REFLECTION_P(object); + + /* Find the class entry */ + switch (Z_TYPE_P(classname)) { + case IS_STRING: + if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) { + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Class %s does not exist", Z_STRVAL_P(classname)); + return; + } + break; + + case IS_OBJECT: + ce = Z_OBJCE_P(classname); + break; + + default: + _DO_THROW("The parameter class is expected to be either a string or an object"); + /* returns out of this function */ + } + + if ((constant = zend_hash_find_ptr(&ce->constants_table, constname)) == NULL) { + zend_throw_exception_ex(reflection_exception_ptr, 0, "Class Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname)); + return; + } + + ZVAL_STR_COPY(&name, constname); + ZVAL_STR_COPY(&cname, ce->name); + + intern->ptr = constant; + intern->ref_type = REF_TYPE_CLASS_CONSTANT; + intern->ce = constant->ce; + intern->ignore_visibility = 0; + reflection_update_property(object, "name", &name); + reflection_update_property(object, "class", &cname); +} +/* }}} */ + +/* {{{ proto public string ReflectionClassConstant::__toString() + Returns a string representation */ +ZEND_METHOD(reflection_class_constant, __toString) +{ + reflection_object *intern; + zend_class_constant *ref; + string str; + zval name; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ref); + string_init(&str); + _default_get_entry(getThis(), "name", sizeof("name")-1, &name); + _class_const_string(&str, Z_STRVAL(name), ref, ""); + zval_ptr_dtor(&name); + RETURN_NEW_STR(str.buf); +} +/* }}} */ + +/* {{{ proto public string ReflectionClassConstant::getName() + Returns the constant' name */ +ZEND_METHOD(reflection_class_constant, getName) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + _default_get_entry(getThis(), "name", sizeof("name")-1, return_value); +} +/* }}} */ + +static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */ +{ + reflection_object *intern; + zend_class_constant *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ref); + RETURN_BOOL(Z_ACCESS_FLAGS(ref->value) & mask); +} +/* }}} */ + +/* {{{ proto public bool ReflectionClassConstant::isPublic() + Returns whether this constant is public */ +ZEND_METHOD(reflection_class_constant, isPublic) +{ + _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC); +} +/* }}} */ + +/* {{{ proto public bool ReflectionClassConstant::isPrivate() + Returns whether this constant is private */ +ZEND_METHOD(reflection_class_constant, isPrivate) +{ + _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE); +} +/* }}} */ + +/* {{{ proto public bool ReflectionClassConstant::isProtected() + Returns whether this constant is protected */ +ZEND_METHOD(reflection_class_constant, isProtected) +{ + _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED); +} +/* }}} */ + +/* {{{ proto public int ReflectionClassConstant::getModifiers() + Returns a bitfield of the access modifiers for this constant */ +ZEND_METHOD(reflection_class_constant, getModifiers) +{ + reflection_object *intern; + zend_class_constant *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ref); + + RETURN_LONG(Z_ACCESS_FLAGS(ref->value)); +} +/* }}} */ + +/* {{{ proto public mixed ReflectionClassConstant::getValue() + Returns this constant's value */ +ZEND_METHOD(reflection_class_constant, getValue) +{ + reflection_object *intern; + zend_class_constant *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ref); + + ZVAL_DUP(return_value, &ref->value); + if (Z_CONSTANT_P(return_value)) { + zval_update_constant_ex(return_value, ref->ce); + } +} +/* }}} */ + +/* {{{ proto public ReflectionClass ReflectionClassConstant::getDeclaringClass() + Get the declaring class */ +ZEND_METHOD(reflection_class_constant, getDeclaringClass) +{ + reflection_object *intern; + zend_class_constant *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ref); + + zend_reflection_class_factory(ref->ce, return_value); +} +/* }}} */ + +/* {{{ proto public string ReflectionClassConstant::getDocComment() + Returns the doc comment for this constant */ +ZEND_METHOD(reflection_class_constant, getDocComment) +{ + reflection_object *intern; + zend_class_constant *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ref); + if (ref->doc_comment) { + RETURN_STR_COPY(ref->doc_comment); + } + RETURN_FALSE; +} +/* }}} */ + /* {{{ proto public static mixed ReflectionClass::export(mixed argument [, bool return]) throws ReflectionException Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */ ZEND_METHOD(reflection_class, export) @@ -3753,7 +3943,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value /* this is necessary to make it able to work with default array * properties, returned to user */ if (Z_CONSTANT(prop_copy)) { - if (UNEXPECTED(zval_update_constant_ex(&prop_copy, 1, NULL) != SUCCESS)) { + if (UNEXPECTED(zval_update_constant_ex(&prop_copy, NULL) != SUCCESS)) { return; } } @@ -4399,6 +4589,8 @@ ZEND_METHOD(reflection_class, getConstants) { reflection_object *intern; zend_class_entry *ce; + zend_string *key; + zend_class_constant *c; zval *val; if (zend_parse_parameters_none() == FAILURE) { @@ -4406,13 +4598,36 @@ ZEND_METHOD(reflection_class, getConstants) } GET_REFLECTION_OBJECT_PTR(ce); array_init(return_value); - ZEND_HASH_FOREACH_VAL(&ce->constants_table, val) { - ZVAL_DEREF(val); - if (UNEXPECTED(zval_update_constant_ex(val, 1, ce) != SUCCESS)) { + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { + if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) { + zend_array_destroy(Z_ARRVAL_P(return_value)); return; } + val = zend_hash_add_new(Z_ARRVAL_P(return_value), key, &c->value); + Z_TRY_ADDREF_P(val); + } ZEND_HASH_FOREACH_END(); +} +/* }}} */ + +/* {{{ proto public array ReflectionClass::getReflectionConstants() + Returns an associative array containing this class' constants as ReflectionClassConstant objects */ +ZEND_METHOD(reflection_class, getReflectionConstants) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_string *name; + zend_class_constant *constant; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ce); + array_init(return_value); + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, name, constant) { + zval class_const; + reflection_class_constant_factory(ce, name, constant, &class_const); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &class_const); } ZEND_HASH_FOREACH_END(); - zend_hash_copy(Z_ARRVAL_P(return_value), &ce->constants_table, zval_add_ref_unref); } /* }}} */ @@ -4422,7 +4637,7 @@ ZEND_METHOD(reflection_class, getConstant) { reflection_object *intern; zend_class_entry *ce; - zval *value; + zend_class_constant *c; zend_string *name; METHOD_NOTSTATIC(reflection_class_ptr); @@ -4431,16 +4646,36 @@ ZEND_METHOD(reflection_class, getConstant) } GET_REFLECTION_OBJECT_PTR(ce); - ZEND_HASH_FOREACH_VAL(&ce->constants_table, value) { - ZVAL_DEREF(value); - if (UNEXPECTED(zval_update_constant_ex(value, 1, ce) != SUCCESS)) { + ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) { + if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) { return; } } ZEND_HASH_FOREACH_END(); - if ((value = zend_hash_find(&ce->constants_table, name)) == NULL) { + if ((c = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) { RETURN_FALSE; } - ZVAL_DUP(return_value, value); + ZVAL_DUP(return_value, &c->value); +} +/* }}} */ + +/* {{{ proto public mixed ReflectionClass::getReflectionConstant(string name) + Returns the class' constant as ReflectionClassConstant objects */ +ZEND_METHOD(reflection_class, getReflectionConstant) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_class_constant *constant; + zend_string *name; + + GET_REFLECTION_OBJECT_PTR(ce); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) { + return; + } + + if ((constant = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) { + RETURN_FALSE; + } + reflection_class_constant_factory(ce, name, constant, return_value); } /* }}} */ @@ -4599,10 +4834,10 @@ ZEND_METHOD(reflection_class, newInstance) return; } - old_scope = EG(scope); - EG(scope) = ce; + old_scope = EG(fake_scope); + EG(fake_scope) = ce; constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value)); - EG(scope) = old_scope; + EG(fake_scope) = old_scope; /* Run the constructor if there is one */ if (constructor) { @@ -4627,9 +4862,7 @@ ZEND_METHOD(reflection_class, newInstance) } fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_UNDEF(&fci.function_name); - fci.symbol_table = NULL; fci.object = Z_OBJ_P(return_value); fci.retval = &retval; fci.param_count = num_args; @@ -4638,7 +4871,7 @@ ZEND_METHOD(reflection_class, newInstance) fcc.initialized = 1; fcc.function_handler = constructor; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope();; fcc.called_scope = Z_OBJCE_P(return_value); fcc.object = Z_OBJ_P(return_value); @@ -4704,10 +4937,10 @@ ZEND_METHOD(reflection_class, newInstanceArgs) return; } - old_scope = EG(scope); - EG(scope) = ce; + old_scope = EG(fake_scope); + EG(fake_scope) = ce; constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value)); - EG(scope) = old_scope; + EG(fake_scope) = old_scope; /* Run the constructor if there is one */ if (constructor) { @@ -4731,9 +4964,7 @@ ZEND_METHOD(reflection_class, newInstanceArgs) } fci.size = sizeof(fci); - fci.function_table = EG(function_table); ZVAL_UNDEF(&fci.function_name); - fci.symbol_table = NULL; fci.object = Z_OBJ_P(return_value); fci.retval = &retval; fci.param_count = argc; @@ -4742,7 +4973,7 @@ ZEND_METHOD(reflection_class, newInstanceArgs) fcc.initialized = 1; fcc.function_handler = constructor; - fcc.calling_scope = EG(scope); + fcc.calling_scope = zend_get_executed_scope(); fcc.called_scope = Z_OBJCE_P(return_value); fcc.object = Z_OBJ_P(return_value); @@ -4937,9 +5168,9 @@ ZEND_METHOD(reflection_class, isSubclassOf) case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(class_name), reflection_class_ptr)) { argument = Z_REFLECTION_P(class_name); - if (argument == NULL || argument->ptr == NULL) { - php_error_docref(NULL, E_ERROR, "Internal error: Failed to retrieve the argument's reflection object"); - /* Bails out */ + if (argument->ptr == NULL) { + zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object"); + return; } class_ce = argument->ptr; break; @@ -4981,9 +5212,9 @@ ZEND_METHOD(reflection_class, implementsInterface) case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(interface), reflection_class_ptr)) { argument = Z_REFLECTION_P(interface); - if (argument == NULL || argument->ptr == NULL) { - php_error_docref(NULL, E_ERROR, "Internal error: Failed to retrieve the argument's reflection object"); - /* Bails out */ + if (argument->ptr == NULL) { + zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object"); + return; } interface_ce = argument->ptr; break; @@ -5158,6 +5389,14 @@ ZEND_METHOD(reflection_property, export) } /* }}} */ +/* {{{ proto public static mixed ReflectionClassConstant::export(mixed class, string name [, bool return]) throws ReflectionException + Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */ +ZEND_METHOD(reflection_class_constant, export) +{ + _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_class_constant_ptr, 2); +} +/* }}} */ + /* {{{ proto public void ReflectionProperty::__construct(mixed class, string name) Constructor. Throws an Exception in case the given property does not exist */ ZEND_METHOD(reflection_property, __construct) @@ -5375,10 +5614,12 @@ ZEND_METHOD(reflection_property, getValue) return; } if (Z_TYPE(CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]) == IS_UNDEF) { - php_error_docref(NULL, E_ERROR, "Internal error: Could not find the property %s::%s", ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->prop.name)); - /* Bails out */ + zend_throw_error(NULL, "Internal error: Could not find the property %s::%s", ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->prop.name)); + return; } - ZVAL_DUP(return_value, &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]); + member_p = &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; + ZVAL_DEREF(member_p); + ZVAL_COPY(return_value, member_p); } else { const char *class_name, *prop_name; size_t prop_name_len; @@ -5388,11 +5629,20 @@ ZEND_METHOD(reflection_property, getValue) return; } + if (!instanceof_function(Z_OBJCE_P(object), ref->ce)) { + _DO_THROW("Given object is not an instance of the class this property was declared in"); + /* Returns from this function */ + } + zend_unmangle_property_name_ex(ref->prop.name, &class_name, &prop_name, &prop_name_len); member_p = zend_read_property(ref->ce, object, prop_name, prop_name_len, 0, &rv); if (member_p != &rv) { + ZVAL_DEREF(member_p); ZVAL_COPY(return_value, member_p); } else { + if (Z_ISREF_P(member_p)) { + zend_unwrap_reference(member_p); + } ZVAL_COPY_VALUE(return_value, member_p); } } @@ -5431,8 +5681,8 @@ ZEND_METHOD(reflection_property, setValue) } if (Z_TYPE(CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]) == IS_UNDEF) { - php_error_docref(NULL, E_ERROR, "Internal error: Could not find the property %s::%s", ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->prop.name)); - /* Bails out */ + zend_throw_error(NULL, "Internal error: Could not find the property %s::%s", ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->prop.name)); + return; } variable_ptr = &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; if (variable_ptr != value) { @@ -5561,7 +5811,6 @@ ZEND_METHOD(reflection_extension, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - lcname = do_alloca(name_len + 1, use_heap); zend_str_tolower_copy(lcname, name_str, name_len); if ((module = zend_hash_str_find_ptr(&module_registry, lcname, name_len)) == NULL) { @@ -6313,7 +6562,9 @@ static const zend_function_entry reflection_class_functions[] = { ZEND_ME(reflection_class, getProperties, arginfo_reflection_class_getProperties, 0) ZEND_ME(reflection_class, hasConstant, arginfo_reflection_class_hasConstant, 0) ZEND_ME(reflection_class, getConstants, arginfo_reflection__void, 0) + ZEND_ME(reflection_class, getReflectionConstants, arginfo_reflection__void, 0) ZEND_ME(reflection_class, getConstant, arginfo_reflection_class_getConstant, 0) + ZEND_ME(reflection_class, getReflectionConstant, arginfo_reflection_class_getConstant, 0) ZEND_ME(reflection_class, getInterfaces, arginfo_reflection__void, 0) ZEND_ME(reflection_class, getInterfaceNames, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isInterface, arginfo_reflection__void, 0) @@ -6405,6 +6656,33 @@ static const zend_function_entry reflection_property_functions[] = { PHP_FE_END }; +ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_class_constant_export, 0, 0, 2) + ZEND_ARG_INFO(0, class) + ZEND_ARG_INFO(0, name) + ZEND_ARG_INFO(0, return) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_class_constant___construct, 0, 0, 2) + ZEND_ARG_INFO(0, class) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO() + +static const zend_function_entry reflection_class_constant_functions[] = { + ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) + ZEND_ME(reflection_class_constant, export, arginfo_reflection_class_constant_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) + ZEND_ME(reflection_class_constant, __construct, arginfo_reflection_class_constant___construct, 0) + ZEND_ME(reflection_class_constant, __toString, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, getName, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, getValue, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, isPublic, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, isPrivate, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, isProtected, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, getModifiers, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, getDeclaringClass, arginfo_reflection__void, 0) + ZEND_ME(reflection_class_constant, getDocComment, arginfo_reflection__void, 0) + PHP_FE_END +}; + ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_parameter_export, 0, 0, 2) ZEND_ARG_INFO(0, function) ZEND_ARG_INFO(0, parameter) @@ -6450,6 +6728,11 @@ static const zend_function_entry reflection_type_functions[] = { PHP_FE_END }; +static const zend_function_entry reflection_named_type_functions[] = { + ZEND_ME(reflection_named_type, getName, arginfo_reflection__void, 0) + PHP_FE_END +}; + ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_extension_export, 0, 0, 1) ZEND_ARG_INFO(0, name) ZEND_ARG_INFO(0, return) @@ -6566,6 +6849,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ INIT_CLASS_ENTRY(_reflection_entry, "ReflectionType", reflection_type_functions); _reflection_entry.create_object = reflection_objects_new; reflection_type_ptr = zend_register_internal_class(&_reflection_entry); + + INIT_CLASS_ENTRY(_reflection_entry, "ReflectionNamedType", reflection_named_type_functions); + _reflection_entry.create_object = reflection_objects_new; + reflection_named_type_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_type_ptr); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionMethod", reflection_method_functions); _reflection_entry.create_object = reflection_objects_new; @@ -6601,6 +6888,13 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ zend_declare_property_string(reflection_property_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); zend_declare_property_string(reflection_property_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC); + INIT_CLASS_ENTRY(_reflection_entry, "ReflectionClassConstant", reflection_class_constant_functions); + _reflection_entry.create_object = reflection_objects_new; + reflection_class_constant_ptr = zend_register_internal_class(&_reflection_entry); + zend_class_implements(reflection_class_constant_ptr, 1, reflector_ptr); + zend_declare_property_string(reflection_class_constant_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); + zend_declare_property_string(reflection_class_constant_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC); + REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_STATIC", ZEND_ACC_STATIC); REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PUBLIC", ZEND_ACC_PUBLIC); REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PROTECTED", ZEND_ACC_PROTECTED); diff --git a/ext/reflection/php_reflection.h b/ext/reflection/php_reflection.h index b4f2cd7bc0..e89e13a151 100644 --- a/ext/reflection/php_reflection.h +++ b/ext/reflection/php_reflection.h @@ -38,6 +38,7 @@ extern PHPAPI zend_class_entry *reflection_function_abstract_ptr; extern PHPAPI zend_class_entry *reflection_function_ptr; extern PHPAPI zend_class_entry *reflection_parameter_ptr; extern PHPAPI zend_class_entry *reflection_type_ptr; +extern PHPAPI zend_class_entry *reflection_named_type_ptr; extern PHPAPI zend_class_entry *reflection_class_ptr; extern PHPAPI zend_class_entry *reflection_object_ptr; extern PHPAPI zend_class_entry *reflection_method_ptr; diff --git a/ext/reflection/tests/004.phpt b/ext/reflection/tests/004.phpt index 41632aa3ba..36ae406b43 100644 --- a/ext/reflection/tests/004.phpt +++ b/ext/reflection/tests/004.phpt @@ -38,6 +38,6 @@ try { echo "===DONE===\n";?> --EXPECTF-- Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; a has a deprecated constructor in %s on line %d -Non-object passed to Invoke() +Trying to invoke non static method a::a() without an object Given object is not an instance of the class this method was declared in ===DONE=== diff --git a/ext/reflection/tests/007.phpt b/ext/reflection/tests/007.phpt index 004158ccff..d9204171b5 100644 --- a/ext/reflection/tests/007.phpt +++ b/ext/reflection/tests/007.phpt @@ -25,6 +25,10 @@ function test($class) { var_dump($e->getMessage()); } + catch (Throwable $e) + { + echo "Exception: " . $e->getMessage() . "\n"; + } echo "====>newInstance(25)\n"; try @@ -129,15 +133,7 @@ object(WithCtor)#%d (0) { ====>WithCtorWithArgs ====>newInstance() - -Warning: Missing argument 1 for WithCtorWithArgs::__construct() in %s007.php on line %d - -Notice: Undefined variable: arg in %s007.php on line %d -WithCtorWithArgs::__construct() -array(0) { -} -object(WithCtorWithArgs)#%d (0) { -} +Exception: Too few arguments to function WithCtorWithArgs::__construct(), 0 passed and exactly 1 expected ====>newInstance(25) WithCtorWithArgs::__construct(25) array(1) { diff --git a/ext/reflection/tests/017.phpt b/ext/reflection/tests/017.phpt index d40c4d83f9..1d9275d21b 100644 --- a/ext/reflection/tests/017.phpt +++ b/ext/reflection/tests/017.phpt @@ -10,12 +10,12 @@ class Foo { $class = new ReflectionClass("Foo"); echo $class; ?> ---EXPECTF-- +--EXPECTF-- Class [ <user> class Foo ] { @@ %s017.php 2-4 - Constants [1] { - Constant [ string test ] { ok } + Constant [ public string test ] { ok } } - Static properties [0] { diff --git a/ext/reflection/tests/ReflectionClassConstant_basic1.phpt b/ext/reflection/tests/ReflectionClassConstant_basic1.phpt new file mode 100644 index 0000000000..fd8118650f --- /dev/null +++ b/ext/reflection/tests/ReflectionClassConstant_basic1.phpt @@ -0,0 +1,194 @@ +--TEST-- +Test usage of ReflectionClassConstant methods __toString(), export(), getName(), getValue(), isPublic(), isPrivate(), isProtected(), getModifiers(), getDeclaringClass() and getDocComment(). +--FILE-- +<?php + +function reflectClassConstant($base, $constant) { + $constInfo = new ReflectionClassConstant($base, $constant); + echo "**********************************\n"; + $class = is_object($base) ? get_class($base) : $base; + echo "Reflecting on class constant $class::$constant\n\n"; + echo "__toString():\n"; + var_dump($constInfo->__toString()); + echo "export():\n"; + var_dump(ReflectionClassConstant::export($base, $constant, true)); + echo "export():\n"; + var_dump(ReflectionClassConstant::export($base, $constant, false)); + echo "getName():\n"; + var_dump($constInfo->getName()); + echo "getValue():\n"; + var_dump($constInfo->getValue()); + echo "isPublic():\n"; + var_dump($constInfo->isPublic()); + echo "isPrivate():\n"; + var_dump($constInfo->isPrivate()); + echo "isProtected():\n"; + var_dump($constInfo->isProtected()); + echo "getModifiers():\n"; + var_dump($constInfo->getModifiers()); + echo "getDeclaringClass():\n"; + var_dump($constInfo->getDeclaringClass()); + echo "getDocComment():\n"; + var_dump($constInfo->getDocComment()); + echo "\n**********************************\n"; +} + +class TestClass { + public const /** My Doc comment */ PUB = true; + /** Another doc comment */ + protected const PROT = 4; + private const PRIV = "keepOut"; +} +$instance = new TestClass(); + +reflectClassConstant("TestClass", "PUB"); +reflectClassConstant("TestClass", "PROT"); +reflectClassConstant("TestClass", "PRIV"); +reflectClassConstant($instance, "PRIV"); +reflectClassConstant($instance, "BAD_CONST"); + +?> +--EXPECTF-- +********************************** +Reflecting on class constant TestClass::PUB + +__toString(): +string(38) "Constant [ public boolean PUB ] { 1 } +" +export(): +string(38) "Constant [ public boolean PUB ] { 1 } +" +export(): +Constant [ public boolean PUB ] { 1 } + +NULL +getName(): +string(3) "PUB" +getValue(): +bool(true) +isPublic(): +bool(true) +isPrivate(): +bool(false) +isProtected(): +bool(false) +getModifiers(): +int(256) +getDeclaringClass(): +object(ReflectionClass)#3 (1) { + ["name"]=> + string(9) "TestClass" +} +getDocComment(): +string(21) "/** My Doc comment */" + +********************************** +********************************** +Reflecting on class constant TestClass::PROT + +__toString(): +string(42) "Constant [ protected integer PROT ] { 4 } +" +export(): +string(42) "Constant [ protected integer PROT ] { 4 } +" +export(): +Constant [ protected integer PROT ] { 4 } + +NULL +getName(): +string(4) "PROT" +getValue(): +int(4) +isPublic(): +bool(false) +isPrivate(): +bool(false) +isProtected(): +bool(true) +getModifiers(): +int(512) +getDeclaringClass(): +object(ReflectionClass)#3 (1) { + ["name"]=> + string(9) "TestClass" +} +getDocComment(): +string(26) "/** Another doc comment */" + +********************************** +********************************** +Reflecting on class constant TestClass::PRIV + +__toString(): +string(45) "Constant [ private string PRIV ] { keepOut } +" +export(): +string(45) "Constant [ private string PRIV ] { keepOut } +" +export(): +Constant [ private string PRIV ] { keepOut } + +NULL +getName(): +string(4) "PRIV" +getValue(): +string(7) "keepOut" +isPublic(): +bool(false) +isPrivate(): +bool(true) +isProtected(): +bool(false) +getModifiers(): +int(1024) +getDeclaringClass(): +object(ReflectionClass)#3 (1) { + ["name"]=> + string(9) "TestClass" +} +getDocComment(): +bool(false) + +********************************** +********************************** +Reflecting on class constant TestClass::PRIV + +__toString(): +string(45) "Constant [ private string PRIV ] { keepOut } +" +export(): +string(45) "Constant [ private string PRIV ] { keepOut } +" +export(): +Constant [ private string PRIV ] { keepOut } + +NULL +getName(): +string(4) "PRIV" +getValue(): +string(7) "keepOut" +isPublic(): +bool(false) +isPrivate(): +bool(true) +isProtected(): +bool(false) +getModifiers(): +int(1024) +getDeclaringClass(): +object(ReflectionClass)#3 (1) { + ["name"]=> + string(9) "TestClass" +} +getDocComment(): +bool(false) + +********************************** + +Fatal error: Uncaught ReflectionException: Class Constant TestClass::BAD_CONST does not exist in %s:%d +Stack trace: +#0 %s(%d): ReflectionClassConstant->__construct(Object(TestClass), 'BAD_CONST') +#1 %s(%d): reflectClassConstant(Object(TestClass), 'BAD_CONST') +#2 {main} + thrown in %s on line %d diff --git a/ext/reflection/tests/ReflectionClassConstant_getValue.phpt b/ext/reflection/tests/ReflectionClassConstant_getValue.phpt new file mode 100644 index 0000000000..e447d15357 --- /dev/null +++ b/ext/reflection/tests/ReflectionClassConstant_getValue.phpt @@ -0,0 +1,47 @@ +--TEST-- +Test variations of getting constant values +--FILE-- +<?php + +/* Use separate classes to make sure that in-place constant updates don't interfere */ +class A { + const X = self::Y * 2; + const Y = 1; +} +class B { + const X = self::Y * 2; + const Y = 1; +} +class C { + const X = self::Y * 2; + const Y = 1; +} + +var_dump((new ReflectionClassConstant('A', 'X'))->getValue()); +echo new ReflectionClassConstant('B', 'X'); +echo new ReflectionClass('C'); + +?> +--EXPECTF-- +int(2) +Constant [ public integer X ] { 2 } +Class [ <user> class C ] { + @@ %s 12-15 + + - Constants [2] { + Constant [ public integer X ] { 2 } + Constant [ public integer Y ] { 1 } + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} diff --git a/ext/reflection/tests/ReflectionClass_export_array_bug72222.phpt b/ext/reflection/tests/ReflectionClass_export_array_bug72222.phpt index e64dc97109..9ccc285433 100644 --- a/ext/reflection/tests/ReflectionClass_export_array_bug72222.phpt +++ b/ext/reflection/tests/ReflectionClass_export_array_bug72222.phpt @@ -13,8 +13,8 @@ Class [ <user> class A ] { @@ %s 2-5 - Constants [2] { - Constant [ integer A ] { 8 } - Constant [ array B ] { Array } + Constant [ public integer A ] { 8 } + Constant [ public array B ] { Array } } - Static properties [0] { diff --git a/ext/reflection/tests/ReflectionClass_isArray.phpt b/ext/reflection/tests/ReflectionClass_isArray.phpt new file mode 100644 index 0000000000..3eec0dac54 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_isArray.phpt @@ -0,0 +1,24 @@ +--TEST-- +public bool ReflectionParameter::isArray ( void ); +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> - @phpsp - sao paulo - br +--FILE-- +<?php +function testReflectionIsArray($a = null, $b = 0, array $c, $d=true, array $e, $f=1.5, $g="", array $h, $i="#F989898") {} + +$reflection = new ReflectionFunction('testReflectionIsArray'); + +foreach ($reflection->getParameters() as $parameter) { + var_dump($parameter->isArray()); +} +?> +--EXPECT-- +bool(false) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +bool(false) diff --git a/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt b/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt index d3a426de4c..3ad654dd84 100644 --- a/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt +++ b/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt @@ -38,13 +38,27 @@ $rcC = new ReflectionClass('C'); $rcD = new ReflectionClass('D'); $rcE = new ReflectionClass('E'); -$a1 = $rcA->newInstanceArgs(); -$a2 = $rcA->newInstanceArgs(array('x')); -var_dump($a1, $a2); +try { + var_dump($rcA->newInstanceArgs()); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} +try { + var_dump($rcA->newInstanceArgs(array('x'))); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} -$b1 = $rcB->newInstanceArgs(); -$b2 = $rcB->newInstanceArgs(array('x', 123)); -var_dump($b1, $b2); +try { + var_dump($rcB->newInstanceArgs()); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} +try { + var_dump($rcB->newInstanceArgs(array('x', 123))); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} try { $rcC->newInstanceArgs(); @@ -73,25 +87,15 @@ try { --EXPECTF-- Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; A has a deprecated constructor in %s on line %d In constructor of class A -In constructor of class A object(A)#%d (0) { } +In constructor of class A object(A)#%d (0) { } - -Warning: Missing argument 1 for B::__construct() in %s on line 9 - -Warning: Missing argument 2 for B::__construct() in %s on line 9 - -Notice: Undefined variable: a in %s on line 10 - -Notice: Undefined variable: b in %s on line 10 -In constructor of class B with args , +Exception: Too few arguments to function B::__construct(), 0 passed and exactly 2 expected In constructor of class B with args x, 123 object(B)#%d (0) { } -object(B)#%d (0) { -} Access to non-public constructor of class C Access to non-public constructor of class D object(E)#%d (0) { diff --git a/ext/reflection/tests/ReflectionClass_newInstance_001.phpt b/ext/reflection/tests/ReflectionClass_newInstance_001.phpt index afa278a9a1..e29cc8734f 100644 --- a/ext/reflection/tests/ReflectionClass_newInstance_001.phpt +++ b/ext/reflection/tests/ReflectionClass_newInstance_001.phpt @@ -42,9 +42,16 @@ $a1 = $rcA->newInstance(); $a2 = $rcA->newInstance('x'); var_dump($a1, $a2); -$b1 = $rcB->newInstance(); -$b2 = $rcB->newInstance('x', 123); -var_dump($b1, $b2); +try { + var_dump($rcB->newInstance()); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} +try { + var_dump($rcB->newInstance('x', 123)); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} try { $rcC->newInstance(); @@ -78,20 +85,10 @@ object(A)#%d (0) { } object(A)#%d (0) { } - -Warning: Missing argument 1 for B::__construct() in %s on line 9 - -Warning: Missing argument 2 for B::__construct() in %s on line 9 - -Notice: Undefined variable: a in %s on line 10 - -Notice: Undefined variable: b in %s on line 10 -In constructor of class B with args , +Exception: Too few arguments to function B::__construct(), 0 passed and exactly 2 expected In constructor of class B with args x, 123 object(B)#%d (0) { } -object(B)#%d (0) { -} Access to non-public constructor of class C Access to non-public constructor of class D object(E)#%d (0) { diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index b9a9b0d559..29d58420e3 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -12,9 +12,9 @@ echo $rc; Class [ <internal:Reflection> class ReflectionClass implements Reflector ] { - Constants [3] { - Constant [ integer IS_IMPLICIT_ABSTRACT ] { 16 } - Constant [ integer IS_EXPLICIT_ABSTRACT ] { 32 } - Constant [ integer IS_FINAL ] { 4 } + Constant [ public integer IS_IMPLICIT_ABSTRACT ] { 16 } + Constant [ public integer IS_EXPLICIT_ABSTRACT ] { 32 } + Constant [ public integer IS_FINAL ] { 4 } } - Static properties [0] { @@ -34,7 +34,7 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] { Property [ <default> public $name ] } - - Methods [50] { + - Methods [52] { Method [ <internal:Reflection> final private method __clone ] { - Parameters [0] { @@ -175,6 +175,12 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] { } } + Method [ <internal:Reflection> public method getReflectionConstants ] { + + - Parameters [0] { + } + } + Method [ <internal:Reflection> public method getConstant ] { - Parameters [1] { @@ -182,6 +188,13 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] { } } + Method [ <internal:Reflection> public method getReflectionConstant ] { + + - Parameters [1] { + Parameter #0 [ <required> $name ] + } + } + Method [ <internal:Reflection> public method getInterfaces ] { - Parameters [0] { diff --git a/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt index 4eda22a3f9..9b2122d1b9 100644 --- a/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt @@ -9,7 +9,7 @@ var_dump($ext->getClasses()); ?> ==DONE== --EXPECT-- -array(14) { +array(16) { ["ReflectionException"]=> object(ReflectionClass)#2 (1) { ["name"]=> @@ -50,33 +50,43 @@ array(14) { ["name"]=> string(14) "ReflectionType" } - ["ReflectionMethod"]=> + ["ReflectionNamedType"]=> object(ReflectionClass)#10 (1) { ["name"]=> + string(19) "ReflectionNamedType" + } + ["ReflectionMethod"]=> + object(ReflectionClass)#11 (1) { + ["name"]=> string(16) "ReflectionMethod" } ["ReflectionClass"]=> - object(ReflectionClass)#11 (1) { + object(ReflectionClass)#12 (1) { ["name"]=> string(15) "ReflectionClass" } ["ReflectionObject"]=> - object(ReflectionClass)#12 (1) { + object(ReflectionClass)#13 (1) { ["name"]=> string(16) "ReflectionObject" } ["ReflectionProperty"]=> - object(ReflectionClass)#13 (1) { + object(ReflectionClass)#14 (1) { ["name"]=> string(18) "ReflectionProperty" } + ["ReflectionClassConstant"]=> + object(ReflectionClass)#15 (1) { + ["name"]=> + string(23) "ReflectionClassConstant" + } ["ReflectionExtension"]=> - object(ReflectionClass)#14 (1) { + object(ReflectionClass)#16 (1) { ["name"]=> string(19) "ReflectionExtension" } ["ReflectionZendExtension"]=> - object(ReflectionClass)#15 (1) { + object(ReflectionClass)#17 (1) { ["name"]=> string(23) "ReflectionZendExtension" } diff --git a/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt b/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt index ac97e3ed2a..c9d1e6379a 100644 --- a/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt +++ b/ext/reflection/tests/ReflectionMethod_invokeArgs_error1.phpt @@ -25,12 +25,9 @@ var_dump($methodWithArgs->invokeArgs($testClassInstance, array())); --EXPECTF-- Method with args: -Warning: Missing argument 1 for TestClass::methodWithArgs() in %s on line %d - -Warning: Missing argument 2 for TestClass::methodWithArgs() in %s on line %d - -Notice: Undefined variable: a in %s on line %d - -Notice: Undefined variable: b in %s on line %d -Called methodWithArgs(, ) -NULL +Fatal error: Uncaught Error: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invokeArgs_error1.php:5 +Stack trace: +#0 [internal function]: TestClass->methodWithArgs() +#1 %sReflectionMethod_invokeArgs_error1.php(19): ReflectionMethod->invokeArgs(Object(TestClass), Array) +#2 {main} + thrown in %sReflectionMethod_invokeArgs_error1.php on line 5 diff --git a/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt b/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt index 513cc1845f..1222467a6b 100644 --- a/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt +++ b/ext/reflection/tests/ReflectionMethod_invokeArgs_error3.phpt @@ -14,7 +14,11 @@ class TestClass { public static function staticMethod() { echo "Called staticMethod()\n"; - var_dump($this); + try { + var_dump($this); + } catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; + } } private static function privateMethod() { @@ -103,9 +107,7 @@ NULL Warning: ReflectionMethod::invokeArgs() expects parameter 1 to be object, boolean given in %s on line %d NULL Called staticMethod() - -Notice: Undefined variable: this in %s on line %d -NULL +Exception: Using $this when not in object context NULL Private method: @@ -113,5 +115,4 @@ string(86) "Trying to invoke private method TestClass::privateMethod() from scop Abstract method: string(53) "Trying to invoke abstract method AbstractClass::foo()" - -Warning: ReflectionMethod::invokeArgs() expects exactly 2 parameters, 1 given in %s on line %d +string(53) "Trying to invoke abstract method AbstractClass::foo()" diff --git a/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt b/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt index cbf358c062..7bfe245f82 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt @@ -22,7 +22,11 @@ class TestClass { public static function staticMethod() { echo "Called staticMethod()\n"; - var_dump($this); + try { + var_dump($this); + } catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; + } } private static function privateMethod() { @@ -93,15 +97,11 @@ Static method: Warning: ReflectionMethod::invoke() expects at least 1 parameter, 0 given in %s on line %d NULL -Called staticMethod() -Notice: Undefined variable: this in %s on line %d -NULL +Warning: ReflectionMethod::invoke() expects parameter 1 to be object, boolean given in %s on line %d NULL Called staticMethod() - -Notice: Undefined variable: this in %s on line %d -NULL +Exception: Using $this when not in object context NULL Method that throws an exception: diff --git a/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt b/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt index 758f1acd13..ef5621e7e5 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt @@ -59,7 +59,9 @@ try { ?> --EXPECTF-- invoke() on a non-object: -string(29) "Non-object passed to Invoke()" + +Warning: ReflectionMethod::invoke() expects parameter 1 to be object, boolean given in %s%eReflectionMethod_invoke_error1.php on line %d +NULL invoke() on a non-instance: string(72) "Given object is not an instance of the class this method was declared in" diff --git a/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt b/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt index a070c8f583..60a9ebae97 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_error2.phpt @@ -21,12 +21,9 @@ var_dump($methodWithArgs->invoke($testClassInstance)); --EXPECTF-- Method with args: -Warning: Missing argument 1 for TestClass::methodWithArgs() in %s on line %d - -Warning: Missing argument 2 for TestClass::methodWithArgs() in %s on line %d - -Notice: Undefined variable: a in %s on line %d - -Notice: Undefined variable: b in %s on line %d -Called methodWithArgs(, ) -NULL +Fatal error: Uncaught Error: Too few arguments to function TestClass::methodWithArgs(), 0 passed and exactly 2 expected in %sReflectionMethod_invoke_error2.php:5 +Stack trace: +#0 [internal function]: TestClass->methodWithArgs() +#1 %sReflectionMethod_invoke_error2.php(15): ReflectionMethod->invoke(Object(TestClass)) +#2 {main} + thrown in %sReflectionMethod_invoke_error2.php on line 5 diff --git a/ext/reflection/tests/ReflectionNamedType.phpt b/ext/reflection/tests/ReflectionNamedType.phpt new file mode 100644 index 0000000000..1ce1222216 --- /dev/null +++ b/ext/reflection/tests/ReflectionNamedType.phpt @@ -0,0 +1,41 @@ +--TEST-- +ReflectionNamedType::getName() and ReflectionNamedType::__toString() +--FILE-- +<?php + +function testInternalTypes(?Traversable $traversable): ?string { + return 'test'; +} + +function testUserDefinedTypes(?Test $traversable): ?Test { + return new Test; +} + +$function = new ReflectionFunction('testInternalTypes'); +$type = $function->getParameters()[0]->getType(); +$return = $function->getReturnType(); + +var_dump($type->getName()); +var_dump((string) $type); +var_dump($return->getName()); +var_dump((string) $return); + +$function = new ReflectionFunction('testUserDefinedTypes'); +$type = $function->getParameters()[0]->getType(); +$return = $function->getReturnType(); + +var_dump($type->getName()); +var_dump((string) $type); +var_dump($return->getName()); +var_dump((string) $return); + +?> +--EXPECTF-- +string(11) "Traversable" +string(13) "?\Traversable" +string(6) "string" +string(7) "?string" +string(4) "Test" +string(6) "?\Test" +string(4) "Test" +string(6) "?\Test"
\ No newline at end of file diff --git a/ext/reflection/tests/ReflectionProperty_getValue_error.phpt b/ext/reflection/tests/ReflectionProperty_getValue_error.phpt index 62009d8bb9..c9bf0b0f25 100644 --- a/ext/reflection/tests/ReflectionProperty_getValue_error.phpt +++ b/ext/reflection/tests/ReflectionProperty_getValue_error.phpt @@ -15,7 +15,7 @@ class AnotherClass { } $instance = new TestClass(); -$instanceWithNoProperties = new AnotherClass(); +$invalidInstance = new AnotherClass(); $propInfo = new ReflectionProperty('TestClass', 'pub2'); echo "Too few args:\n"; @@ -45,9 +45,9 @@ catch(Exception $exc) { echo $exc->getMessage(); } -echo "\n\nInstance without property:\n"; +echo "\n\nInvalid instance:\n"; $propInfo = new ReflectionProperty('TestClass', 'pub2'); -var_dump($propInfo->getValue($instanceWithNoProperties)); +var_dump($propInfo->getValue($invalidInstance)); ?> --EXPECTF-- @@ -77,7 +77,10 @@ string(15) "static property" Protected property: Cannot access non-public member TestClass::prot -Instance without property: +Invalid instance: -Notice: Undefined property: AnotherClass::$pub2 in %s on line %d -NULL +Fatal error: Uncaught ReflectionException: Given object is not an instance of the class this property was declared in in %s:47 +Stack trace: +#0 %s(47): ReflectionProperty->getValue(Object(AnotherClass)) +#1 {main} + thrown in %s on line 47 diff --git a/ext/reflection/tests/ReflectionType_001.phpt b/ext/reflection/tests/ReflectionType_001.phpt index f764cf1519..c0ae24490c 100644 --- a/ext/reflection/tests/ReflectionType_001.phpt +++ b/ext/reflection/tests/ReflectionType_001.phpt @@ -79,7 +79,7 @@ foreach ([ bool(true) bool(false) bool(false) -string(8) "stdClass" +string(9) "\stdClass" ** Function 0 - Parameter 1 bool(true) bool(false) @@ -94,7 +94,7 @@ string(8) "callable" bool(true) bool(true) bool(false) -string(8) "stdClass" +string(10) "?\stdClass" ** Function 0 - Parameter 4 bool(false) ** Function 0 - Parameter 5 @@ -121,19 +121,19 @@ string(5) "float" bool(true) bool(false) bool(false) -string(11) "NotExisting" +string(12) "\NotExisting" ** Function 1 - Parameter 0 bool(true) bool(false) bool(false) -string(4) "Test" +string(5) "\Test" *** methods ** Method 0 - parameter 0 bool(true) bool(false) bool(false) -string(10) "SplSubject" +string(11) "\SplSubject" ** Method 1 - parameter 0 bool(true) bool(false) @@ -148,7 +148,7 @@ string(6) "parent" bool(true) bool(false) bool(false) -string(4) "Test" +string(5) "\Test" *** return types ** Function/method return type 0 @@ -157,7 +157,7 @@ bool(false) bool(true) bool(false) bool(false) -string(8) "stdClass" +string(9) "\stdClass" ** Function/method return type 2 bool(true) bool(false) @@ -177,9 +177,9 @@ string(6) "parent" bool(true) bool(false) bool(false) -string(4) "Test" +string(5) "\Test" ** Function/method return type 6 bool(true) bool(false) bool(false) -string(4) "Test" +string(5) "\Test" diff --git a/ext/reflection/tests/ReflectionType_002.phpt b/ext/reflection/tests/ReflectionType_002.phpt index 8313862ec5..9c9c77b76b 100644 --- a/ext/reflection/tests/ReflectionType_002.phpt +++ b/ext/reflection/tests/ReflectionType_002.phpt @@ -12,6 +12,6 @@ unset($rm, $rp); var_dump((string) $rt, (string) $rrt); --EXPECT-- -string(4) "Test" -string(5) "Test2" +string(5) "\Test" +string(6) "\Test2" diff --git a/ext/reflection/tests/ReflectionType_possible_types.phpt b/ext/reflection/tests/ReflectionType_possible_types.phpt new file mode 100644 index 0000000000..0db5b7c3f0 --- /dev/null +++ b/ext/reflection/tests/ReflectionType_possible_types.phpt @@ -0,0 +1,31 @@ +--TEST-- +ReflectionType possible types +--FILE-- +<?php + +$functions = [ + function(): void {}, + function(): int {}, + function(): float {}, + function(): string {}, + function(): bool {}, + function(): array {}, + function(): callable {}, + function(): StdClass {} +]; + +foreach ($functions as $function) { + $reflectionFunc = new ReflectionFunction($function); + $returnType = $reflectionFunc->getReturnType(); + var_dump($returnType->__toString()); +} +?> +--EXPECTF-- +string(4) "void" +string(3) "int" +string(5) "float" +string(6) "string" +string(4) "bool" +string(5) "array" +string(8) "callable" +string(9) "\StdClass" diff --git a/ext/reflection/tests/bug29986.phpt b/ext/reflection/tests/bug29986.phpt index 4c4d629f39..f5aa62a00b 100644 --- a/ext/reflection/tests/bug29986.phpt +++ b/ext/reflection/tests/bug29986.phpt @@ -20,11 +20,11 @@ Class [ <user> class just_constants ] { @@ %s %d-%d - Constants [5] { - Constant [ boolean BOOLEAN_CONSTANT ] { 1 } - Constant [ null NULL_CONSTANT ] { } - Constant [ string STRING_CONSTANT ] { This is a string } - Constant [ integer INTEGER_CONSTANT ] { 1000 } - Constant [ float FLOAT_CONSTANT ] { 3.14159265 } + Constant [ public boolean BOOLEAN_CONSTANT ] { 1 } + Constant [ public null NULL_CONSTANT ] { } + Constant [ public string STRING_CONSTANT ] { This is a string } + Constant [ public integer INTEGER_CONSTANT ] { 1000 } + Constant [ public float FLOAT_CONSTANT ] { 3.14159265 } } - Static properties [0] { diff --git a/ext/reflection/tests/bug38217.phpt b/ext/reflection/tests/bug38217.phpt index cf007d9547..988f1c8953 100644 --- a/ext/reflection/tests/bug38217.phpt +++ b/ext/reflection/tests/bug38217.phpt @@ -18,7 +18,11 @@ class Object1 { } $class= new ReflectionClass('Object1'); -var_dump($class->newInstanceArgs()); +try { + var_dump($class->newInstanceArgs()); +} catch (Throwable $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} var_dump($class->newInstanceArgs(array('test'))); @@ -27,13 +31,7 @@ echo "Done\n"; --EXPECTF-- object(Object)#%d (0) { } - -Warning: Missing argument 1 for Object1::__construct() in %s on line %d - -Notice: Undefined variable: var in %s on line %d -NULL -object(Object1)#%d (0) { -} +Exception: Too few arguments to function Object1::__construct(), 0 passed and exactly 1 expected string(4) "test" object(Object1)#%d (0) { } diff --git a/ext/reflection/tests/bug45765.phpt b/ext/reflection/tests/bug45765.phpt index b0c1be2c4c..7963a03eea 100644 --- a/ext/reflection/tests/bug45765.phpt +++ b/ext/reflection/tests/bug45765.phpt @@ -31,7 +31,7 @@ Object of class [ <user> class foo extends foo2 ] { @@ %s 7-21 - Constants [1] { - Constant [ string BAR ] { foo's bar } + Constant [ public string BAR ] { foo's bar } } - Static properties [0] { diff --git a/ext/reflection/tests/bug72661.phpt b/ext/reflection/tests/bug72661.phpt new file mode 100644 index 0000000000..40d14922b8 --- /dev/null +++ b/ext/reflection/tests/bug72661.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #72661 (ReflectionType::__toString crashes with iterable) +--FILE-- +<?php +function test(iterable $arg) { } + +var_dump((string)(new ReflectionParameter("test", 0))->getType()); +?> +--EXPECT-- +string(8) "iterable" diff --git a/ext/reflection/tests/bug72846.phpt b/ext/reflection/tests/bug72846.phpt deleted file mode 100644 index ab8b6cac79..0000000000 --- a/ext/reflection/tests/bug72846.phpt +++ /dev/null @@ -1,48 +0,0 @@ ---TEST-- -Bug #72846 (getConstant for a array constant with constant values returns NULL/NFC/UKNOWN) ---FILE-- -<?php - -namespace Some { - - abstract class A - { - const ONE = '1'; - const TWO = '2'; - - const CONST_NUMBERS = [ - self::ONE, - self::TWO, - ]; - - const NUMBERS = [ - '1', - '2', - ]; - } - - class B extends A - { - } - - $ref = new \ReflectionClass('Some\B'); - - var_dump($ref->getConstant('ONE')); - var_dump($ref->getConstant('CONST_NUMBERS')); - var_dump($ref->getConstant('NUMBERS')); -} -?> ---EXPECT-- -string(1) "1" -array(2) { - [0]=> - string(1) "1" - [1]=> - string(1) "2" -} -array(2) { - [0]=> - string(1) "1" - [1]=> - string(1) "2" -} diff --git a/ext/reflection/tests/request38992.phpt b/ext/reflection/tests/request38992.phpt new file mode 100644 index 0000000000..8c0052fd85 --- /dev/null +++ b/ext/reflection/tests/request38992.phpt @@ -0,0 +1,22 @@ +--TEST-- +Request #38992 (invoke() and invokeArgs() static method calls should match) +--FILE-- +<?php +class MyClass +{ + public static function doSomething() + { + echo "Did it!\n"; + } +} + +$r = new ReflectionMethod('MyClass', 'doSomething'); +$r->invoke('WTF?'); +$r->invokeArgs('WTF?', array()); +?> +===DONE=== +--EXPECTF-- +Warning: ReflectionMethod::invoke() expects parameter 1 to be object, string given in %s%erequest38992.php on line %d + +Warning: ReflectionMethod::invokeArgs() expects parameter 1 to be object, string given in %s%erequest38992.php on line %d +===DONE=== |