diff options
| author | Aaron Piotrowski <aaron@trowski.com> | 2016-06-10 22:02:23 -0500 |
|---|---|---|
| committer | Aaron Piotrowski <aaron@trowski.com> | 2016-06-10 22:02:23 -0500 |
| commit | e3c681aa5cc71122a8d2fae42e6513fc413ccac8 (patch) | |
| tree | 5f1df62f7b666028edb0ee1adf083a52d63df45a /ext/reflection | |
| parent | fb4e3085cbaa76eb8f28eebf848a81d1c0190067 (diff) | |
| parent | 792e89385ca6fc722a03590722eb7745a2374720 (diff) | |
| download | php-git-e3c681aa5cc71122a8d2fae42e6513fc413ccac8.tar.gz | |
Merge branch 'master' into throw-error-in-extensions
Diffstat (limited to 'ext/reflection')
27 files changed, 1189 insertions, 268 deletions
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 4684954567..3138ee41d7 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2015 The PHP Group | + | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -64,6 +64,7 @@ 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,8 +88,8 @@ ZEND_DECLARE_MODULE_GLOBALS(reflection) /* Method macros */ #define METHOD_NOTSTATIC(ce) \ - if (!Z_OBJ(EX(This)) || !instanceof_function(Z_OBJCE(EX(This)), ce)) { \ - zend_throw_error(zend_ce_error, "%s() cannot be called statically", get_active_function_name()); \ + 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,7 +105,7 @@ ZEND_DECLARE_MODULE_GLOBALS(reflection) #define GET_REFLECTION_OBJECT() \ intern = Z_REFLECTION_P(getThis()); \ - if (intern == NULL || intern->ptr == NULL) { \ + if (intern->ptr == NULL) { \ RETURN_ON_EXCEPTION \ zend_throw_error(zend_ce_error, "Internal error: Failed to retrieve the reflection object"); \ return; \ @@ -216,7 +217,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 */ @@ -334,7 +336,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; } @@ -369,6 +371,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); @@ -384,7 +387,7 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in /* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */ if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) { - string_printf(str, "%s%s", indent, ce->info.user.doc_comment); + string_printf(str, "%s%s", indent, ZSTR_VAL(ce->info.user.doc_comment)); string_write(str, "\n", 1); } @@ -446,102 +449,94 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in } /* Constants */ - if (&ce->constants_table) { - string_printf(str, "\n"); - count = zend_hash_num_elements(&ce->constants_table); - string_printf(str, "%s - Constants [%d] {\n", indent, count); - if (count > 0) { - zend_string *key; - zval *value; - - 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_END(); - } - string_printf(str, "%s }\n", indent); + string_printf(str, "\n"); + count = zend_hash_num_elements(&ce->constants_table); + string_printf(str, "%s - Constants [%d] {\n", indent, count); + if (count > 0) { + zend_string *key; + zend_class_constant *c; + + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { + zval_update_constant_ex(&c->value, c->ce); + _class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent.buf)); + } ZEND_HASH_FOREACH_END(); } + string_printf(str, "%s }\n", indent); /* Static properties */ - if (&ce->properties_info) { - /* counting static properties */ - count = zend_hash_num_elements(&ce->properties_info); - if (count > 0) { - zend_property_info *prop; - - ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { - if(prop->flags & ZEND_ACC_SHADOW) { - count_shadow_props++; - } else if (prop->flags & ZEND_ACC_STATIC) { - count_static_props++; - } - } ZEND_HASH_FOREACH_END(); - } + /* counting static properties */ + count = zend_hash_num_elements(&ce->properties_info); + if (count > 0) { + zend_property_info *prop; + + ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { + if(prop->flags & ZEND_ACC_SHADOW) { + count_shadow_props++; + } else if (prop->flags & ZEND_ACC_STATIC) { + count_static_props++; + } + } ZEND_HASH_FOREACH_END(); + } - /* static properties */ - string_printf(str, "\n%s - Static properties [%d] {\n", indent, count_static_props); - if (count_static_props > 0) { - zend_property_info *prop; + /* static properties */ + string_printf(str, "\n%s - Static properties [%d] {\n", indent, count_static_props); + if (count_static_props > 0) { + zend_property_info *prop; - ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { - if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) { - _property_string(str, prop, NULL, ZSTR_VAL(sub_indent.buf)); - } - } ZEND_HASH_FOREACH_END(); - } - string_printf(str, "%s }\n", indent); + ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { + if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) { + _property_string(str, prop, NULL, ZSTR_VAL(sub_indent.buf)); + } + } ZEND_HASH_FOREACH_END(); } + string_printf(str, "%s }\n", indent); /* Static methods */ - if (&ce->function_table) { - /* counting static methods */ - count = zend_hash_num_elements(&ce->function_table); - if (count > 0) { - zend_function *mptr; - - ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) { - if (mptr->common.fn_flags & ZEND_ACC_STATIC - && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce)) - { - count_static_funcs++; - } - } ZEND_HASH_FOREACH_END(); - } + /* counting static methods */ + count = zend_hash_num_elements(&ce->function_table); + if (count > 0) { + zend_function *mptr; + + ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) { + if (mptr->common.fn_flags & ZEND_ACC_STATIC + && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce)) + { + count_static_funcs++; + } + } ZEND_HASH_FOREACH_END(); + } - /* static methods */ - string_printf(str, "\n%s - Static methods [%d] {", indent, count_static_funcs); - if (count_static_funcs > 0) { - zend_function *mptr; + /* static methods */ + string_printf(str, "\n%s - Static methods [%d] {", indent, count_static_funcs); + if (count_static_funcs > 0) { + zend_function *mptr; - ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) { - if (mptr->common.fn_flags & ZEND_ACC_STATIC - && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce)) - { - string_printf(str, "\n"); - _function_string(str, mptr, ce, ZSTR_VAL(sub_indent.buf)); - } - } ZEND_HASH_FOREACH_END(); - } else { - string_printf(str, "\n"); - } - string_printf(str, "%s }\n", indent); + ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) { + if (mptr->common.fn_flags & ZEND_ACC_STATIC + && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce)) + { + string_printf(str, "\n"); + _function_string(str, mptr, ce, ZSTR_VAL(sub_indent.buf)); + } + } ZEND_HASH_FOREACH_END(); + } else { + string_printf(str, "\n"); } + string_printf(str, "%s }\n", indent); /* Default/Implicit properties */ - if (&ce->properties_info) { - count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props; - string_printf(str, "\n%s - Properties [%d] {\n", indent, count); - if (count > 0) { - zend_property_info *prop; - - ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { - if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) { - _property_string(str, prop, NULL, ZSTR_VAL(sub_indent.buf)); - } - } ZEND_HASH_FOREACH_END(); - } - string_printf(str, "%s }\n", indent); + count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props; + string_printf(str, "\n%s - Properties [%d] {\n", indent, count); + if (count > 0) { + zend_property_info *prop; + + ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { + if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) { + _property_string(str, prop, NULL, ZSTR_VAL(sub_indent.buf)); + } + } ZEND_HASH_FOREACH_END(); } + string_printf(str, "%s }\n", indent); if (obj && Z_TYPE_P(obj) == IS_OBJECT && Z_OBJ_HT_P(obj)->get_properties) { string dyn; @@ -569,56 +564,54 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in } /* Non static methods */ - if (&ce->function_table) { - count = zend_hash_num_elements(&ce->function_table) - count_static_funcs; - if (count > 0) { - zend_function *mptr; - zend_string *key; - string dyn; - - count = 0; - string_init(&dyn); - - ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, key, mptr) { - if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0 - && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce)) - { - size_t len = ZSTR_LEN(mptr->common.function_name); + count = zend_hash_num_elements(&ce->function_table) - count_static_funcs; + if (count > 0) { + zend_function *mptr; + zend_string *key; + string dyn; + + count = 0; + string_init(&dyn); - /* Do not display old-style inherited constructors */ - if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 - || mptr->common.scope == ce - || !key - || zend_binary_strcasecmp(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(mptr->common.function_name), len) == 0) + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, key, mptr) { + if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0 + && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce)) + { + size_t len = ZSTR_LEN(mptr->common.function_name); + + /* Do not display old-style inherited constructors */ + if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 + || mptr->common.scope == ce + || !key + || zend_binary_strcasecmp(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(mptr->common.function_name), len) == 0) + { + zend_function *closure; + /* see if this is a closure */ + if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) + && memcmp(ZSTR_VAL(mptr->common.function_name), ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 + && (closure = zend_get_closure_invoke_method(Z_OBJ_P(obj))) != NULL) { - zend_function *closure; - /* see if this is a closure */ - if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) - && memcmp(ZSTR_VAL(mptr->common.function_name), ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 - && (closure = zend_get_closure_invoke_method(Z_OBJ_P(obj))) != NULL) - { - mptr = closure; - } else { - closure = NULL; - } - string_printf(&dyn, "\n"); - _function_string(&dyn, mptr, ce, ZSTR_VAL(sub_indent.buf)); - count++; - _free_function(closure); + mptr = closure; + } else { + closure = NULL; } + string_printf(&dyn, "\n"); + _function_string(&dyn, mptr, ce, ZSTR_VAL(sub_indent.buf)); + count++; + _free_function(closure); } - } ZEND_HASH_FOREACH_END(); - string_printf(str, "\n%s - Methods [%d] {", indent, count); - if (!count) { - string_printf(str, "\n"); } - string_append(str, &dyn); - string_free(&dyn); - } else { - string_printf(str, "\n%s - Methods [0] {\n", indent); + } ZEND_HASH_FOREACH_END(); + string_printf(str, "\n%s - Methods [%d] {", indent, count); + if (!count) { + string_printf(str, "\n"); } - string_printf(str, "%s }\n", indent); + string_append(str, &dyn); + string_free(&dyn); + } else { + string_printf(str, "\n%s - Methods [0] {\n", indent); } + string_printf(str, "%s }\n", indent); string_printf(str, "%s}\n", indent); string_free(&sub_indent); @@ -638,6 +631,24 @@ 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)); + zend_string *value_str; + char *type; + + zval_update_constant_ex(&c->value, c->ce); + value_str = zval_get_string(&c->value); + type = zend_zval_type_name(&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) { @@ -700,14 +711,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) { @@ -1367,6 +1374,27 @@ 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) { @@ -1401,9 +1429,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; @@ -1435,7 +1461,6 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c ZVAL_COPY_VALUE(¶ms[1], output_ptr); 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; @@ -1470,7 +1495,7 @@ static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTIO parameter_reference *param; intern = Z_REFLECTION_P(getThis()); - if (intern == NULL || intern->ptr == NULL) { + if (intern->ptr == NULL) { if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { return NULL; } @@ -1625,9 +1650,6 @@ ZEND_METHOD(reflection_function, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == SUCCESS) { fptr = (zend_function*)zend_get_closure_method_def(closure); @@ -1764,7 +1786,12 @@ ZEND_METHOD(reflection_function, getClosure) } GET_REFLECTION_OBJECT_PTR(fptr); - zend_create_closure(return_value, fptr, NULL, NULL, NULL); + if (!Z_ISUNDEF(intern->obj)) { + /* Closures are immutable objects */ + ZVAL_COPY(return_value, &intern->obj); + } else { + zend_create_fake_closure(return_value, fptr, NULL, NULL, NULL); + } } /* }}} */ @@ -1906,7 +1933,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(); @@ -1935,9 +1962,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; @@ -1946,7 +1971,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; @@ -1995,9 +2020,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; @@ -2006,7 +2029,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; @@ -2164,9 +2187,6 @@ ZEND_METHOD(reflection_generator, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O", &generator, zend_ce_generator) == FAILURE) { return; @@ -2294,7 +2314,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); @@ -2316,7 +2336,7 @@ ZEND_METHOD(reflection_generator, getExecutingGenerator) REFLECTION_CHECK_VALID_GENERATOR(ex) current = zend_generator_get_current(generator); - ++GC_REFCOUNT(current); + ++GC_REFCOUNT(¤t->std); ZVAL_OBJ(return_value, (zend_object *) current); } @@ -2353,9 +2373,6 @@ ZEND_METHOD(reflection_parameter, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } /* First, find the function */ switch (Z_TYPE_P(reference)) { @@ -2873,15 +2890,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); } } /* }}} */ @@ -3007,6 +3018,7 @@ ZEND_METHOD(reflection_type, __toString) 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); + case IS_VOID: RETURN_STRINGL("void", sizeof("void") - 1); EMPTY_SWITCH_DEFAULT_CASE() } } @@ -3058,9 +3070,6 @@ ZEND_METHOD(reflection_method, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } /* Find the class entry */ switch (Z_TYPE_P(classname)) { @@ -3146,7 +3155,7 @@ ZEND_METHOD(reflection_method, getClosure) GET_REFLECTION_OBJECT_PTR(mptr); if (mptr->common.fn_flags & ZEND_ACC_STATIC) { - zend_create_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL); + zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL); } else { if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) { return; @@ -3163,7 +3172,7 @@ ZEND_METHOD(reflection_method, getClosure) { ZVAL_COPY(return_value, obj); } else { - zend_create_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj); + zend_create_fake_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj); } } } @@ -3235,9 +3244,7 @@ ZEND_METHOD(reflection_method, invoke) } 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; @@ -3342,9 +3349,7 @@ ZEND_METHOD(reflection_method, invokeArgs) } 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; @@ -3667,11 +3672,198 @@ ZEND_METHOD(reflection_method, setAccessible) intern = Z_REFLECTION_P(getThis()); - if (intern == NULL) { + intern->ignore_visibility = visible; +} +/* }}} */ + +/* {{{ 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; } - intern->ignore_visibility = visible; + 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; } /* }}} */ @@ -3704,9 +3896,6 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } if (Z_TYPE_P(argument) == IS_OBJECT) { ZVAL_STR_COPY(&classname, Z_OBJCE_P(argument)->name); @@ -3775,7 +3964,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; } } @@ -3865,6 +4054,7 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) "Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name)); return; } + ZVAL_DEREF(variable_ptr); zval_ptr_dtor(variable_ptr); ZVAL_COPY(variable_ptr, value); } @@ -4420,6 +4610,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) { @@ -4427,12 +4619,36 @@ ZEND_METHOD(reflection_class, getConstants) } GET_REFLECTION_OBJECT_PTR(ce); array_init(return_value); - ZEND_HASH_FOREACH_VAL(&ce->constants_table, 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); } /* }}} */ @@ -4442,7 +4658,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); @@ -4451,15 +4667,36 @@ ZEND_METHOD(reflection_class, getConstant) } GET_REFLECTION_OBJECT_PTR(ce); - ZEND_HASH_FOREACH_VAL(&ce->constants_table, 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); } /* }}} */ @@ -4618,10 +4855,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) { @@ -4646,9 +4883,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; @@ -4657,7 +4892,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); @@ -4723,10 +4958,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) { @@ -4750,9 +4985,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; @@ -4761,7 +4994,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); @@ -4956,7 +5189,7 @@ 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) { + if (argument->ptr == NULL) { zend_throw_error(zend_ce_error, "Internal error: Failed to retrieve the argument's reflection object"); return; } @@ -5000,7 +5233,7 @@ 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) { + if (argument->ptr == NULL) { zend_throw_error(zend_ce_error, "Internal error: Failed to retrieve the argument's reflection object"); return; } @@ -5177,6 +5410,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) @@ -5197,9 +5438,6 @@ ZEND_METHOD(reflection_property, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } /* Find the class entry */ switch (Z_TYPE_P(classname)) { @@ -5400,7 +5638,9 @@ ZEND_METHOD(reflection_property, getValue) zend_throw_error(zend_ce_error, "Internal error: Could not find the property %s::%s", ZSTR_VAL(intern->ce->name), ZSTR_VAL(ref->prop.name)); /* Bails out */ } - 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; @@ -5410,9 +5650,22 @@ 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, 1, &rv); - ZVAL_DUP(return_value, member_p); + 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); + } } } /* }}} */ @@ -5454,31 +5707,16 @@ ZEND_METHOD(reflection_property, setValue) } variable_ptr = &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; if (variable_ptr != value) { - if (Z_ISREF_P(variable_ptr)) { - zval garbage; + zval garbage; - ZVAL_COPY_VALUE(&garbage, variable_ptr); /* old value should be destroyed */ + ZVAL_DEREF(variable_ptr); + ZVAL_DEREF(value); - /* To check: can't *variable_ptr be some system variable like error_zval here? */ - ZVAL_COPY_VALUE(variable_ptr, value); - if (Z_REFCOUNTED_P(value) && Z_REFCOUNT_P(value) > 0) { - zval_copy_ctor(variable_ptr); - } - zval_dtor(&garbage); - } else { - zval garbage; + ZVAL_COPY_VALUE(&garbage, variable_ptr); - ZVAL_COPY_VALUE(&garbage, variable_ptr); - /* if we assign referenced variable, we should separate it */ - if (Z_REFCOUNTED_P(value)) { - Z_ADDREF_P(value); - } - if (Z_ISREF_P(value)) { - SEPARATE_ZVAL(value); - } - ZVAL_COPY_VALUE(variable_ptr, value); - zval_ptr_dtor(&garbage); - } + ZVAL_COPY(variable_ptr, value); + + zval_ptr_dtor(&garbage); } } else { const char *class_name, *prop_name; @@ -5563,10 +5801,6 @@ ZEND_METHOD(reflection_property, setAccessible) intern = Z_REFLECTION_P(getThis()); - if (intern == NULL) { - return; - } - intern->ignore_visibility = visible; } /* }}} */ @@ -5598,9 +5832,6 @@ ZEND_METHOD(reflection_extension, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } 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) { @@ -5966,9 +6197,6 @@ ZEND_METHOD(reflection_zend_extension, __construct) object = getThis(); intern = Z_REFLECTION_P(object); - if (intern == NULL) { - return; - } extension = zend_get_extension(name_str); if (!extension) { @@ -6355,7 +6583,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) @@ -6447,6 +6677,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) @@ -6643,6 +6900,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 b50309d9ff..b4f2cd7bc0 100644 --- a/ext/reflection/php_reflection.h +++ b/ext/reflection/php_reflection.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2015 The PHP Group | + | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | 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_CannotClone_basic.phpt b/ext/reflection/tests/ReflectionClass_CannotClone_basic.phpt index 900ce21d45..bbe5fdbaec 100644 --- a/ext/reflection/tests/ReflectionClass_CannotClone_basic.phpt +++ b/ext/reflection/tests/ReflectionClass_CannotClone_basic.phpt @@ -5,7 +5,7 @@ Stefan Koopmanschap <stefan@phpgg.nl> TestFest PHP|Tek --SKIPIF-- <?php -if (!extension_loaded('reflection)) print 'skip'; +if (!extension_loaded('reflection')) print 'skip'; ?> --FILE-- <?php 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_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..c1f9d99f2b 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(15) { ["ReflectionException"]=> object(ReflectionClass)#2 (1) { ["name"]=> @@ -70,13 +70,18 @@ array(14) { ["name"]=> string(18) "ReflectionProperty" } - ["ReflectionExtension"]=> + ["ReflectionClassConstant"]=> object(ReflectionClass)#14 (1) { ["name"]=> + string(23) "ReflectionClassConstant" + } + ["ReflectionExtension"]=> + object(ReflectionClass)#15 (1) { + ["name"]=> string(19) "ReflectionExtension" } ["ReflectionZendExtension"]=> - object(ReflectionClass)#15 (1) { + object(ReflectionClass)#16 (1) { ["name"]=> string(23) "ReflectionZendExtension" } diff --git a/ext/reflection/tests/ReflectionGenerator_basic.phpt b/ext/reflection/tests/ReflectionGenerator_basic.phpt index 528d2d9ca2..6f35b6c244 100644 --- a/ext/reflection/tests/ReflectionGenerator_basic.phpt +++ b/ext/reflection/tests/ReflectionGenerator_basic.phpt @@ -39,7 +39,11 @@ object(Generator)#2 (0) { } array(1) { [0]=> - array(2) { + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) ["function"]=> string(3) "foo" ["args"]=> diff --git a/ext/reflection/tests/ReflectionGenerator_getTrace.phpt b/ext/reflection/tests/ReflectionGenerator_getTrace.phpt new file mode 100644 index 0000000000..05a46009e8 --- /dev/null +++ b/ext/reflection/tests/ReflectionGenerator_getTrace.phpt @@ -0,0 +1,53 @@ +--TEST-- +ReflectionGenerator::getTrace() over multiple Generators +--FILE-- +<?php + +function foo() { + yield 1; + yield 2; +} + +function bar() +{ + yield from foo(); +} + +function baz() +{ + yield from bar(); +} + +$gen = baz(); +$gen->valid(); + +var_dump((new ReflectionGenerator($gen))->getTrace()); + +?> +--EXPECTF-- +array(2) { + [0]=> + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + ["function"]=> + string(3) "foo" + ["args"]=> + array(0) { + } + } + [1]=> + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + ["function"]=> + string(3) "bar" + ["args"]=> + array(0) { + } + } +} diff --git a/ext/reflection/tests/ReflectionGenerator_in_Generator.phpt b/ext/reflection/tests/ReflectionGenerator_in_Generator.phpt index 9c0098d506..a227e1a213 100644 --- a/ext/reflection/tests/ReflectionGenerator_in_Generator.phpt +++ b/ext/reflection/tests/ReflectionGenerator_in_Generator.phpt @@ -46,7 +46,11 @@ object(ReflectionFunction)#4 (1) { NULL array(1) { [0]=> - array(2) { + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) ["function"]=> string(9) "{closure}" ["args"]=> diff --git a/ext/reflection/tests/ReflectionMethod_defaultArg.phpt b/ext/reflection/tests/ReflectionMethod_defaultArg.phpt new file mode 100644 index 0000000000..1c04cade5f --- /dev/null +++ b/ext/reflection/tests/ReflectionMethod_defaultArg.phpt @@ -0,0 +1,44 @@ +--TEST-- +ReflectionMethod and RECV_INIT (bug #70957 and #70958) +--FILE-- +<?php +Abstract class F { + private function bar($a = self::class) {} +} + +Trait T +{ + private function bar($a = self::class) {} +} + + +class B { + use T; +} + +echo new \ReflectionMethod('F', 'bar'); +echo new \ReflectionMethod('T', 'bar'); +echo new \ReflectionMethod('B', 'bar'); +?> +--EXPECTF-- +Method [ <user> private method bar ] { + @@ %s + + - Parameters [1] { + Parameter #0 [ <optional> $a = 'F' ] + } +} +Method [ <user> private method bar ] { + @@ %s + + - Parameters [1] { + Parameter #0 [ <optional> $a = 'T' ] + } +} +Method [ <user> private method bar ] { + @@ %s + + - Parameters [1] { + Parameter #0 [ <optional> $a = 'B' ] + } +} diff --git a/ext/reflection/tests/ReflectionMethod_getDocComment_property_list.phpt b/ext/reflection/tests/ReflectionMethod_getDocComment_property_list.phpt new file mode 100644 index 0000000000..4719571124 --- /dev/null +++ b/ext/reflection/tests/ReflectionMethod_getDocComment_property_list.phpt @@ -0,0 +1,41 @@ +--TEST-- +ReflectionMethod::getDocComment() +--INI-- +opcache.save_comments=1 +--FILE-- +<?php + +class X { + /** + * doc 1 + */ + // Some comment + public + $x = "x", + $y = 'y', + /** doc 2 */ + $z = 'z' + ; +} + +$reflection = new ReflectionProperty('\X', 'x'); +echo 'X::x', PHP_EOL; +var_dump($reflection->getDocComment()); + +$reflection = new ReflectionProperty('\X', 'y'); +echo 'X::y', PHP_EOL; +var_dump($reflection->getDocComment()); + +$reflection = new ReflectionProperty('\X', 'z'); +echo 'X::z', PHP_EOL; +var_dump($reflection->getDocComment()); +?> +--EXPECTF-- +X::x +string(24) "/** + * doc 1 + */" +X::y +bool(false) +X::z +string(12) "/** doc 2 */" diff --git a/ext/reflection/tests/ReflectionMethod_getPrototype_basic.phpt b/ext/reflection/tests/ReflectionMethod_getPrototype_basic.phpt new file mode 100644 index 0000000000..c57a529d7b --- /dev/null +++ b/ext/reflection/tests/ReflectionMethod_getPrototype_basic.phpt @@ -0,0 +1,29 @@ +--TEST-- +public ReflectionMethod ReflectionMethod::getPrototype ( void ); +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> +--FILE-- +<?php +class Hello { + public function sayHelloTo($name) { + return 'Hello ' . $name; + } +} + +class HelloWorld extends Hello { + public function sayHelloTo($name) { + return 'Hello world: ' . $name; + } +} + +$reflectionMethod = new ReflectionMethod('HelloWorld', 'sayHelloTo'); +var_dump($reflectionMethod->getPrototype()); + +?> +--EXPECT-- +object(ReflectionMethod)#2 (2) { + ["name"]=> + string(10) "sayHelloTo" + ["class"]=> + string(5) "Hello" +} diff --git a/ext/reflection/tests/ReflectionProperty_getValue_error.phpt b/ext/reflection/tests/ReflectionProperty_getValue_error.phpt index c2152e9f87..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,5 +77,10 @@ string(15) "static property" Protected property: Cannot access non-public member TestClass::prot -Instance without property: -NULL +Invalid instance: + +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/ReflectionProperty_setAccessible.phpt b/ext/reflection/tests/ReflectionProperty_setAccessible.phpt index 1e829b3a6c..cc184c1920 100644 --- a/ext/reflection/tests/ReflectionProperty_setAccessible.phpt +++ b/ext/reflection/tests/ReflectionProperty_setAccessible.phpt @@ -132,7 +132,7 @@ string(44) "Cannot access non-public member B::protected" string(50) "Cannot access non-public member B::protectedStatic" string(42) "Cannot access non-public member A::private" string(1) "a" -string(1) "b" +string(1) "f" string(1) "c" string(1) "e" string(1) "f" diff --git a/ext/reflection/tests/ReflectionType_possible_types.phpt b/ext/reflection/tests/ReflectionType_possible_types.phpt new file mode 100644 index 0000000000..81e08550f2 --- /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(8) "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/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/bug70674.phpt b/ext/reflection/tests/bug70674.phpt new file mode 100644 index 0000000000..82cfc53f1e --- /dev/null +++ b/ext/reflection/tests/bug70674.phpt @@ -0,0 +1,8 @@ +--TEST-- +Bug #70674 (ReflectionFunction::getClosure() leaks memory when used for internal functions) +--FILE-- +<?php +var_dump(((new ReflectionFunction("strlen"))->getClosure())("hello")); +?> +--EXPECT-- +int(5) diff --git a/ext/reflection/tests/bug70960.phpt b/ext/reflection/tests/bug70960.phpt new file mode 100644 index 0000000000..30885cd1fa --- /dev/null +++ b/ext/reflection/tests/bug70960.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #70960 (ReflectionFunction for array_unique returns wrong number of parameters) +--FILE-- +<?php + +$ref = new ReflectionFunction('array_unique'); +var_dump(count($ref->getParameters())); +?> +--EXPECT-- +int(2) diff --git a/ext/reflection/tests/bug70982.phpt b/ext/reflection/tests/bug70982.phpt new file mode 100644 index 0000000000..d530846f64 --- /dev/null +++ b/ext/reflection/tests/bug70982.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #70982 (setStaticPropertyValue behaviors inconsistently with 5.6) +--FILE-- +<?php +class Foo { + static $abc; + function __construct() + { + var_dump(self::$abc); + } +} + +class Bar extends Foo { + +} + +$rf = new ReflectionClass('Bar'); +$rf->setStaticPropertyValue('abc', 'hi'); +$foo = $rf->newInstance(); +?> +--EXPECT-- +string(2) "hi" diff --git a/ext/reflection/tests/bug71018.phpt b/ext/reflection/tests/bug71018.phpt new file mode 100644 index 0000000000..00baa31d3c --- /dev/null +++ b/ext/reflection/tests/bug71018.phpt @@ -0,0 +1,43 @@ +--TEST-- +Bug #71018 (ReflectionProperty::setValue() behavior changed) +--FILE-- +<?php +class T1 { + public static $data; + + public static function getDataBySelf() + { + return self::$data; + } + + public static function getDataByStatic() + { + return static::$data; + } +} + +class T2 extends T1 {} + +$Prop1 = new ReflectionProperty(T1::class, 'data'); +$Prop2 = new ReflectionProperty(T2::class, 'data'); + +// #1 +// prints: hello, hello in PHP5, but world, hello in PHP7 - not OK +$Prop1->setValue(\T1::class, "world"); +$Prop2->setValue(\T2::class, 'hello'); +var_dump("T2::self = " . T2::getDataBySelf()); +var_dump("T2::static = " . T2::getDataByStatic()); + +// #2 +// prints: hello, hello in both PHP5 and PHP7 - OK +T1::$data = "world"; +T2::$data = 'hello'; + +var_dump("T2::self = " . T2::getDataBySelf()); +var_dump("T2::static = " . T2::getDataByStatic()); +?> +--EXPECT-- +string(16) "T2::self = hello" +string(18) "T2::static = hello" +string(16) "T2::self = hello" +string(18) "T2::static = hello" diff --git a/ext/reflection/tests/bug71767.phpt b/ext/reflection/tests/bug71767.phpt new file mode 100644 index 0000000000..8c4059abf4 --- /dev/null +++ b/ext/reflection/tests/bug71767.phpt @@ -0,0 +1,44 @@ +--TEST-- +Bug #71767 (ReflectionMethod::getDocComment returns the wrong comment) +--FILE-- +<?php + +/** Correct docblock */ +function foo( + /** wrong docblock */ + $arg +) { +} + +class Foo { + /** Correct docblock */ + public function bar( + /** wrong docblock */ + $arg + ) { + + } +} + +/** Correct docblock */ +$func = function( + /** wrong docblock */ + $arg +) { +}; + +$reflectionFunction = new ReflectionFunction('foo'); +$reflectionClass = new ReflectionClass(Foo::class); +$reflectionClosure = new ReflectionFunction($func); + +echo $reflectionFunction->getDocComment() . PHP_EOL; +echo $reflectionClass->getMethod('bar')->getDocComment() . PHP_EOL; +echo $reflectionClosure->getDocComment() . PHP_EOL; + +echo "Done\n"; +?> +--EXPECTF-- +/** Correct docblock */ +/** Correct docblock */ +/** Correct docblock */ +Done diff --git a/ext/reflection/tests/bug72174.phpt b/ext/reflection/tests/bug72174.phpt new file mode 100644 index 0000000000..94416d6153 --- /dev/null +++ b/ext/reflection/tests/bug72174.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #72174: ReflectionProperty#getValue() causes __isset call +--FILE-- +<?php + +class Foo +{ + private $bar; + + public function __construct() + { + unset($this->bar); + } + + public function __isset($name) + { + var_dump(__METHOD__); + return true; + } + + public function __get($name) + { + var_dump(__METHOD__); + return $name; + } +} + +$instance = new Foo(); +$reflectionBar = (new ReflectionProperty(Foo::class, 'bar')); +$reflectionBar->setAccessible(true); +var_dump($reflectionBar->getValue($instance)); + +?> +--EXPECT-- +string(10) "Foo::__get" +string(3) "bar" diff --git a/ext/reflection/reflectionclass_for_traits.phpt b/ext/reflection/tests/reflectionclass_for_traits.phpt index 526310a8b9..526310a8b9 100644 --- a/ext/reflection/reflectionclass_for_traits.phpt +++ b/ext/reflection/tests/reflectionclass_for_traits.phpt |
