diff options
Diffstat (limited to 'ext/reflection/php_reflection.c')
-rw-r--r-- | ext/reflection/php_reflection.c | 905 |
1 files changed, 538 insertions, 367 deletions
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 748f5b3f08..20c23f1a2e 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2018 The PHP Group | + | Copyright (c) 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 | @@ -28,6 +28,8 @@ #include "php_ini.h" #include "php_reflection.h" #include "ext/standard/info.h" +#include "ext/standard/sha1.h" +#include "ext/standard/php_random.h" #include "zend.h" #include "zend_API.h" @@ -42,6 +44,16 @@ #include "zend_builtin_functions.h" #include "zend_smart_str.h" +/* Key used to avoid leaking addresses in ReflectionProperty::getId() */ +#define REFLECTION_KEY_LEN 16 +ZEND_BEGIN_MODULE_GLOBALS(reflection) + zend_bool key_initialized; + unsigned char key[REFLECTION_KEY_LEN]; +ZEND_END_MODULE_GLOBALS(reflection) +ZEND_DECLARE_MODULE_GLOBALS(reflection) + +#define REFLECTION_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(reflection, v) + #define reflection_update_property(object, name, value) do { \ zval member; \ ZVAL_STR(&member, name); \ @@ -73,40 +85,40 @@ 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; +PHPAPI zend_class_entry *reflection_reference_ptr; /* Exception throwing macro */ -#define _DO_THROW(msg) \ - zend_throw_exception(reflection_exception_ptr, msg, 0); \ - return; \ - -#define RETURN_ON_EXCEPTION \ - if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { \ - return; \ - } - -#define GET_REFLECTION_OBJECT() \ - intern = Z_REFLECTION_P(getThis()); \ - if (intern->ptr == NULL) { \ - RETURN_ON_EXCEPTION \ - zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); \ - return; \ - } \ +#define _DO_THROW(msg) \ + zend_throw_exception(reflection_exception_ptr, msg, 0); \ + return; + +#define GET_REFLECTION_OBJECT() do { \ + intern = Z_REFLECTION_P(ZEND_THIS); \ + if (intern->ptr == NULL) { \ + if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { \ + return; \ + } \ + zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); \ + return; \ + } \ +} while (0) -#define GET_REFLECTION_OBJECT_PTR(target) \ - GET_REFLECTION_OBJECT() \ - target = intern->ptr; \ +#define GET_REFLECTION_OBJECT_PTR(target) do { \ + GET_REFLECTION_OBJECT(); \ + target = intern->ptr; \ +} while (0) /* Class constants */ -#define REGISTER_REFLECTION_CLASS_CONST_LONG(class_name, const_name, value) \ +#define REGISTER_REFLECTION_CLASS_CONST_LONG(class_name, const_name, value) \ zend_declare_class_constant_long(reflection_ ## class_name ## _ptr, const_name, sizeof(const_name)-1, (zend_long)value); /* {{{ Object structure */ /* Struct for properties */ typedef struct _property_reference { - zend_class_entry *ce; zend_property_info prop; zend_string *unmangled_name; + zend_bool dynamic; } property_reference; /* Struct for parameters */ @@ -119,8 +131,7 @@ typedef struct _parameter_reference { /* Struct for type hints */ typedef struct _type_reference { - struct _zend_arg_info *arg_info; - zend_function *fptr; + zend_type type; } type_reference; typedef enum { @@ -135,7 +146,6 @@ typedef enum { /* Struct for reflection objects */ typedef struct { - zval dummy; /* holder for the second property */ zval obj; void *ptr; zend_class_entry *ce; @@ -153,6 +163,11 @@ static inline reflection_object *reflection_object_from_obj(zend_object *obj) { static zend_object_handlers reflection_object_handlers; +static inline zend_bool is_closure_invoke(zend_class_entry *ce, zend_string *lcname) { + return ce == zend_ce_closure + && zend_string_equals_literal(lcname, ZEND_INVOKE_FUNC_NAME); +} + static zval *_default_load_name(zval *object) /* {{{ */ { return zend_hash_find_ex_ind(Z_OBJPROP_P(object), ZSTR_KNOWN(ZEND_STR_NAME), 1); @@ -203,7 +218,6 @@ static void reflection_free_objects_storage(zend_object *object) /* {{{ */ reflection_object *intern = reflection_object_from_obj(object); parameter_reference *reference; property_reference *prop_reference; - type_reference *typ_reference; if (intern->ptr) { switch (intern->ref_type) { @@ -213,8 +227,6 @@ static void reflection_free_objects_storage(zend_object *object) /* {{{ */ efree(intern->ptr); break; case REF_TYPE_TYPE: - typ_reference = (type_reference*)intern->ptr; - _free_function(typ_reference->fptr); efree(intern->ptr); break; case REF_TYPE_FUNCTION: @@ -266,7 +278,7 @@ static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{ static void _const_string(smart_str *str, char *name, zval *value, char *indent); static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent); -static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent); +static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent, zend_bool dynamic); static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char* indent); static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent); static void _extension_string(smart_str *str, zend_module_entry *module, char *indent); @@ -324,6 +336,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char if (ce->num_interfaces) { uint32_t i; + ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED); if (ce->ce_flags & ZEND_ACC_INTERFACE) { smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->interfaces[0]->name)); } else { @@ -365,7 +378,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char zend_property_info *prop; ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { - if(prop->flags & ZEND_ACC_SHADOW) { + if ((prop->flags & ZEND_ACC_PRIVATE) && prop->ce != ce) { count_shadow_props++; } else if (prop->flags & ZEND_ACC_STATIC) { count_static_props++; @@ -379,8 +392,8 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char 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)); + if ((prop->flags & ZEND_ACC_STATIC) && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) { + _property_string(str, prop, NULL, ZSTR_VAL(sub_indent), 0); } } ZEND_HASH_FOREACH_END(); } @@ -426,14 +439,15 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char 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)); + if (!(prop->flags & ZEND_ACC_STATIC) + && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) { + _property_string(str, prop, NULL, ZSTR_VAL(sub_indent), 0); } } ZEND_HASH_FOREACH_END(); } smart_str_append_printf(str, "%s }\n", indent); - if (obj && Z_TYPE_P(obj) == IS_OBJECT && Z_OBJ_HT_P(obj)->get_properties) { + if (obj && Z_TYPE_P(obj) == IS_OBJECT) { HashTable *properties = Z_OBJ_HT_P(obj)->get_properties(obj); zend_string *prop_name; smart_str prop_str = {0}; @@ -444,7 +458,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char if (prop_name && ZSTR_LEN(prop_name) && ZSTR_VAL(prop_name)[0]) { /* skip all private and protected properties */ if (!zend_hash_exists(&ce->properties_info, prop_name)) { count++; - _property_string(&prop_str, NULL, ZSTR_VAL(prop_name), ZSTR_VAL(sub_indent)); + _property_string(&prop_str, NULL, ZSTR_VAL(prop_name), ZSTR_VAL(sub_indent), 0); } } } ZEND_HASH_FOREACH_END(); @@ -460,37 +474,26 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char count = zend_hash_num_elements(&ce->function_table) - count_static_funcs; if (count > 0) { zend_function *mptr; - zend_string *key; smart_str method_str = {0}; count = 0; - ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, key, mptr) { + ZEND_HASH_FOREACH_PTR(&ce->function_table, 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 (obj && is_closure_invoke(ce, mptr->common.function_name) + && (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; - } - smart_str_appendc(&method_str, '\n'); - _function_string(&method_str, mptr, ce, ZSTR_VAL(sub_indent)); - count++; - _free_function(closure); + mptr = closure; + } else { + closure = NULL; } + smart_str_appendc(&method_str, '\n'); + _function_string(&method_str, mptr, ce, ZSTR_VAL(sub_indent)); + count++; + _free_function(closure); } } ZEND_HASH_FOREACH_END(); smart_str_append_printf(str, "\n%s - Methods [%d] {", indent, count); @@ -685,7 +688,7 @@ static void _function_closure_string(smart_str *str, zend_function *fptr, char* return; } - static_variables = fptr->op_array.static_variables; + static_variables = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr); count = zend_hash_num_elements(static_variables); if (!count) { @@ -821,14 +824,14 @@ static void _function_string(smart_str *str, zend_function *fptr, zend_class_ent /* }}} */ /* {{{ _property_string */ -static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent) +static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent, zend_bool dynamic) { smart_str_append_printf(str, "%sProperty [ ", indent); if (!prop) { smart_str_append_printf(str, "<dynamic> public $%s", prop_name); } else { if (!(prop->flags & ZEND_ACC_STATIC)) { - if (prop->flags & ZEND_ACC_IMPLICIT_PUBLIC) { + if (dynamic) { smart_str_appends(str, "<implicit> "); } else { smart_str_appends(str, "<default> "); @@ -861,12 +864,8 @@ static void _property_string(smart_str *str, zend_property_info *prop, const cha } /* }}} */ -static int _extension_ini_string(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ +static void _extension_ini_string(zend_ini_entry *ini_entry, smart_str *str, char *indent, int number) /* {{{ */ { - zend_ini_entry *ini_entry = (zend_ini_entry*)Z_PTR_P(el); - smart_str *str = va_arg(args, smart_str *); - char *indent = va_arg(args, char *); - int number = va_arg(args, int); char *comma = ""; if (number == ini_entry->module_number) { @@ -894,43 +893,19 @@ static int _extension_ini_string(zval *el, int num_args, va_list args, zend_hash } smart_str_append_printf(str, " %s}\n", indent); } - return ZEND_HASH_APPLY_KEEP; } /* }}} */ -static int _extension_class_string(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ +static void _extension_class_string(zend_class_entry *ce, zend_string *key, smart_str *str, char *indent, zend_module_entry *module, int *num_classes) /* {{{ */ { - zend_class_entry *ce = (zend_class_entry*)Z_PTR_P(el); - smart_str *str = va_arg(args, smart_str *); - char *indent = va_arg(args, char *); - struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*); - int *num_classes = va_arg(args, int*); - - if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) { + if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) { /* dump class if it is not an alias */ - if (!zend_binary_strcasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(hash_key->key), ZSTR_LEN(hash_key->key))) { + if (zend_string_equals_ci(ce->name, key)) { smart_str_append_printf(str, "\n"); _class_string(str, ce, NULL, indent); (*num_classes)++; } } - return ZEND_HASH_APPLY_KEEP; -} -/* }}} */ - -static int _extension_const_string(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ -{ - zend_constant *constant = (zend_constant*)Z_PTR_P(el); - smart_str *str = va_arg(args, smart_str *); - char *indent = va_arg(args, char *); - struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*); - int *num_classes = va_arg(args, int*); - - if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) { - _const_string(str, ZSTR_VAL(constant->name), &constant->value, indent); - (*num_classes)++; - } - return ZEND_HASH_APPLY_KEEP; } /* }}} */ @@ -984,7 +959,10 @@ static void _extension_string(smart_str *str, zend_module_entry *module, char *i { smart_str str_ini = {0}; - zend_hash_apply_with_arguments(EG(ini_directives), (apply_func_args_t) _extension_ini_string, 3, &str_ini, indent, module->module_number); + zend_ini_entry *ini_entry; + ZEND_HASH_FOREACH_PTR(EG(ini_directives), ini_entry) { + _extension_ini_string(ini_entry, &str_ini, indent, module->module_number); + } ZEND_HASH_FOREACH_END(); if (smart_str_get_len(&str_ini) > 0) { smart_str_append_printf(str, "\n - INI {\n"); smart_str_append_smart_str(str, &str_ini); @@ -995,9 +973,16 @@ static void _extension_string(smart_str *str, zend_module_entry *module, char *i { smart_str str_constants = {0}; + zend_constant *constant; int num_constants = 0; - zend_hash_apply_with_arguments(EG(zend_constants), (apply_func_args_t) _extension_const_string, 4, &str_constants, indent, module, &num_constants); + ZEND_HASH_FOREACH_PTR(EG(zend_constants), constant) { + if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) { + _const_string(&str_constants, ZSTR_VAL(constant->name), &constant->value, indent); + num_constants++; + } + } ZEND_HASH_FOREACH_END(); + if (num_constants) { smart_str_append_printf(str, "\n - Constants [%d] {\n", num_constants); smart_str_append_smart_str(str, &str_constants); @@ -1028,9 +1013,13 @@ static void _extension_string(smart_str *str, zend_module_entry *module, char *i { zend_string *sub_indent = strpprintf(0, "%s ", indent); smart_str str_classes = {0}; + zend_string *key; + zend_class_entry *ce; int num_classes = 0; - zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) _extension_class_string, 4, &str_classes, ZSTR_VAL(sub_indent), module, &num_classes); + ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) { + _extension_class_string(ce, key, &str_classes, ZSTR_VAL(sub_indent), module, &num_classes); + } ZEND_HASH_FOREACH_END(); if (num_classes) { smart_str_append_printf(str, "\n - Classes [%d] {", num_classes); smart_str_append_smart_str(str, &str_classes); @@ -1158,7 +1147,7 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje /* }}} */ /* {{{ reflection_type_factory */ -static void reflection_type_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, zval *object) +static void reflection_type_factory(zend_type type, zval *object) { reflection_object *intern; type_reference *reference; @@ -1166,15 +1155,9 @@ static void reflection_type_factory(zend_function *fptr, zval *closure_object, s reflection_instantiate(reflection_named_type_ptr, object); intern = Z_REFLECTION_P(object); reference = (type_reference*) emalloc(sizeof(type_reference)); - reference->arg_info = arg_info; - reference->fptr = fptr; + reference->type = type; intern->ptr = reference; intern->ref_type = REF_TYPE_TYPE; - intern->ce = fptr->common.scope; - if (closure_object) { - Z_ADDREF_P(closure_object); - ZVAL_COPY_VALUE(&intern->obj, closure_object); - } } /* }}} */ @@ -1224,7 +1207,7 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho /* }}} */ /* {{{ reflection_property_factory */ -static void reflection_property_factory(zend_class_entry *ce, zend_string *name, zend_property_info *prop, zval *object) +static void reflection_property_factory(zend_class_entry *ce, zend_string *name, zend_property_info *prop, zval *object, zend_bool dynamic) { reflection_object *intern; zval propname; @@ -1241,7 +1224,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_string *name, tmp_ce = tmp_ce->parent; } - if (tmp_info && !(tmp_info->flags & ZEND_ACC_SHADOW)) { /* found something and it's not a parent's private */ + if (tmp_info && (!(tmp_info->flags & ZEND_ACC_PRIVATE) || tmp_info->ce == tmp_ce)) { /* found something and it's not a parent's private */ prop = tmp_info; } else { /* not found, use initial value */ ce = store_ce; @@ -1254,9 +1237,9 @@ static void reflection_property_factory(zend_class_entry *ce, zend_string *name, reflection_instantiate(reflection_property_ptr, object); intern = Z_REFLECTION_P(object); reference = (property_reference*) emalloc(sizeof(property_reference)); - reference->ce = ce; reference->prop = *prop; reference->unmangled_name = zend_string_copy(name); + reference->dynamic = dynamic; intern->ptr = reference; intern->ref_type = REF_TYPE_PROPERTY; intern->ce = ce; @@ -1269,7 +1252,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_string *name, static void reflection_property_factory_str(zend_class_entry *ce, const char *name_str, size_t name_len, zend_property_info *prop, zval *object) { zend_string *name = zend_string_init(name_str, name_len, 0); - reflection_property_factory(ce, name, prop, object); + reflection_property_factory(ce, name, prop, object, 0); zend_string_release(name); } @@ -1320,7 +1303,7 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c } /* Create object */ - if (object_and_properties_init(&reflector, ce_ptr, NULL) == FAILURE) { + if (object_init_ex(&reflector, ce_ptr) == FAILURE) { _DO_THROW("Could not create reflector"); } @@ -1389,7 +1372,7 @@ static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTIO reflection_object *intern; parameter_reference *param; - intern = Z_REFLECTION_P(getThis()); + intern = Z_REFLECTION_P(ZEND_THIS); if (intern->ptr == NULL) { if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { return NULL; @@ -1493,9 +1476,6 @@ ZEND_METHOD(reflection, getModifierNames) if (modifiers & ZEND_ACC_FINAL) { add_next_index_stringl(return_value, "final", sizeof("final")-1); } - if (modifiers & ZEND_ACC_IMPLICIT_PUBLIC) { - add_next_index_stringl(return_value, "public", sizeof("public")-1); - } /* These are mutually exclusive */ switch (modifiers & ZEND_ACC_PPP_MASK) { @@ -1535,7 +1515,7 @@ ZEND_METHOD(reflection_function, __construct) zend_function *fptr; zend_string *fname, *lcname; - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == SUCCESS) { @@ -1604,7 +1584,7 @@ ZEND_METHOD(reflection_function, getName) if (zend_parse_parameters_none() == FAILURE) { return; } - _default_get_name(getThis(), return_value); + _default_get_name(ZEND_THIS, return_value); } /* }}} */ @@ -1813,19 +1793,21 @@ ZEND_METHOD(reflection_function, getStaticVariables) /* Return an empty array in case no static variables exist */ if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) { + HashTable *ht; + array_init(return_value); - if (GC_REFCOUNT(fptr->op_array.static_variables) > 1) { - if (!(GC_FLAGS(fptr->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_DELREF(fptr->op_array.static_variables); - } - fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables); + ht = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr); + if (!ht) { + ZEND_ASSERT(fptr->op_array.fn_flags & ZEND_ACC_IMMUTABLE); + ht = zend_array_dup(fptr->op_array.static_variables); + ZEND_MAP_PTR_SET(fptr->op_array.static_variables_ptr, ht); } - ZEND_HASH_FOREACH_VAL(fptr->op_array.static_variables, val) { + ZEND_HASH_FOREACH_VAL(ht, val) { if (UNEXPECTED(zval_update_constant_ex(val, fptr->common.scope) != SUCCESS)) { return; } } ZEND_HASH_FOREACH_END(); - zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, zval_add_ref); + zend_hash_copy(Z_ARRVAL_P(return_value), ht, zval_add_ref); } else { ZVAL_EMPTY_ARRAY(return_value); } @@ -2091,7 +2073,7 @@ ZEND_METHOD(reflection_generator, __construct) reflection_object *intern; zend_execute_data *ex; - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O", &generator, zend_ce_generator) == FAILURE) { @@ -2120,7 +2102,7 @@ ZEND_METHOD(reflection_generator, __construct) ZEND_METHOD(reflection_generator, getTrace) { zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT; - zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj); + zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj); zend_generator *root_generator; zend_execute_data *ex_backup = EG(current_execute_data); zend_execute_data *ex = generator->execute_data; @@ -2155,7 +2137,7 @@ ZEND_METHOD(reflection_generator, getTrace) /* {{{ proto public int ReflectionGenerator::getExecutingLine() */ ZEND_METHOD(reflection_generator, getExecutingLine) { - zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj); + zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj); zend_execute_data *ex = generator->execute_data; if (zend_parse_parameters_none() == FAILURE) { @@ -2171,7 +2153,7 @@ ZEND_METHOD(reflection_generator, getExecutingLine) /* {{{ proto public string ReflectionGenerator::getExecutingFile() */ ZEND_METHOD(reflection_generator, getExecutingFile) { - zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj); + zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj); zend_execute_data *ex = generator->execute_data; if (zend_parse_parameters_none() == FAILURE) { @@ -2187,7 +2169,7 @@ ZEND_METHOD(reflection_generator, getExecutingFile) /* {{{ proto public ReflectionFunctionAbstract ReflectionGenerator::getFunction() */ ZEND_METHOD(reflection_generator, getFunction) { - zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj); + zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj); zend_execute_data *ex = generator->execute_data; if (zend_parse_parameters_none() == FAILURE) { @@ -2211,7 +2193,7 @@ ZEND_METHOD(reflection_generator, getFunction) /* {{{ proto public object ReflectionGenerator::getThis() */ ZEND_METHOD(reflection_generator, getThis) { - zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj); + zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj); zend_execute_data *ex = generator->execute_data; if (zend_parse_parameters_none() == FAILURE) { @@ -2231,7 +2213,7 @@ ZEND_METHOD(reflection_generator, getThis) /* {{{ proto public Generator ReflectionGenerator::getExecutingGenerator() */ ZEND_METHOD(reflection_generator, getExecutingGenerator) { - zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj); + zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj); zend_execute_data *ex = generator->execute_data; zend_generator *current; @@ -2276,35 +2258,31 @@ ZEND_METHOD(reflection_parameter, __construct) return; } - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); /* First, find the function */ switch (Z_TYPE_P(reference)) { - case IS_STRING: { - size_t lcname_len; - char *lcname; - - lcname_len = Z_STRLEN_P(reference); - lcname = zend_str_tolower_dup(Z_STRVAL_P(reference), lcname_len); - if ((fptr = zend_hash_str_find_ptr(EG(function_table), lcname, lcname_len)) == NULL) { - efree(lcname); + case IS_STRING: + { + zend_string *lcname = zend_string_tolower(Z_STR_P(reference)); + fptr = zend_hash_find_ptr(EG(function_table), lcname); + zend_string_release(lcname); + if (!fptr) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Function %s() does not exist", Z_STRVAL_P(reference)); return; } - efree(lcname); + ce = fptr->common.scope; } - ce = fptr->common.scope; break; case IS_ARRAY: { zval *classref; zval *method; - size_t lcname_len; - char *lcname; + zend_string *lcname; - if (((classref =zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL) + if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL) || ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL)) { _DO_THROW("Expected array($object, $method) or array($classname, $method)"); @@ -2323,22 +2301,19 @@ ZEND_METHOD(reflection_parameter, __construct) } convert_to_string_ex(method); - lcname_len = Z_STRLEN_P(method); - lcname = zend_str_tolower_dup(Z_STRVAL_P(method), lcname_len); - if (ce == zend_ce_closure && Z_TYPE_P(classref) == IS_OBJECT - && (lcname_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) - && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 + lcname = zend_string_tolower(Z_STR_P(method)); + if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname) && (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL) { /* nothing to do. don't set is_closure since is the invoke handler, not the closure itself */ - } else if ((fptr = zend_hash_str_find_ptr(&ce->function_table, lcname, lcname_len)) == NULL) { - efree(lcname); + } else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) { + zend_string_release(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0, "Method %s::%s() does not exist", ZSTR_VAL(ce->name), Z_STRVAL_P(method)); return; } - efree(lcname); + zend_string_release(lcname); } break; @@ -2349,7 +2324,7 @@ ZEND_METHOD(reflection_parameter, __construct) fptr = (zend_function *)zend_get_closure_method_def(reference); Z_ADDREF_P(reference); is_closure = 1; - } else if ((fptr = zend_hash_str_find_ptr(&ce->function_table, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME))) == NULL) { + } else if ((fptr = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZEND_INVOKE_FUNC_NAME); return; @@ -2439,7 +2414,7 @@ ZEND_METHOD(reflection_parameter, __construct) ref = (parameter_reference*) emalloc(sizeof(parameter_reference)); ref->arg_info = &arg_info[position]; ref->offset = (uint32_t)position; - ref->required = position < fptr->common.required_num_args; + ref->required = (uint32_t)position < fptr->common.required_num_args; ref->fptr = fptr; /* TODO: copy fptr */ intern->ptr = ref; @@ -2476,7 +2451,7 @@ ZEND_METHOD(reflection_parameter, getName) if (zend_parse_parameters_none() == FAILURE) { return; } - _default_get_name(getThis(), return_value); + _default_get_name(ZEND_THIS, return_value); } /* }}} */ @@ -2611,7 +2586,7 @@ ZEND_METHOD(reflection_parameter, getType) if (!ZEND_TYPE_IS_SET(param->arg_info->type)) { RETURN_NULL(); } - reflection_type_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, param->arg_info, return_value); + reflection_type_factory(param->arg_info->type, return_value); } /* }}} */ @@ -2869,7 +2844,7 @@ ZEND_METHOD(reflection_type, allowsNull) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->arg_info->type)); + RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->type)); } /* }}} */ @@ -2885,16 +2860,18 @@ ZEND_METHOD(reflection_type, isBuiltin) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(ZEND_TYPE_IS_CODE(param->arg_info->type)); + RETVAL_BOOL(ZEND_TYPE_IS_CODE(param->type)); } /* }}} */ /* {{{ reflection_type_name */ static zend_string *reflection_type_name(type_reference *param) { - if (ZEND_TYPE_IS_CLASS(param->arg_info->type)) { - return zend_string_copy(ZEND_TYPE_NAME(param->arg_info->type)); + if (ZEND_TYPE_IS_NAME(param->type)) { + return zend_string_copy(ZEND_TYPE_NAME(param->type)); + } else if (ZEND_TYPE_IS_CE(param->type)) { + return zend_string_copy(ZEND_TYPE_CE(param->type)->name); } else { - char *name = zend_get_type_by_const(ZEND_TYPE_CODE(param->arg_info->type)); + char *name = zend_get_type_by_const(ZEND_TYPE_CODE(param->type)); return zend_string_init(name, strlen(name), 0); } } @@ -2976,7 +2953,7 @@ ZEND_METHOD(reflection_method, __construct) orig_obj = NULL; } - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); /* Find the class entry */ @@ -3113,7 +3090,7 @@ static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic) "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)); + ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); return; } @@ -3136,7 +3113,7 @@ static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic) } ZEND_HASH_FOREACH_END(); } - /* In case this is a static method, we should'nt pass an object_ptr + /* In case this is a static method, we shouldn't pass an object_ptr * (which is used as calling context aka $this). We can thus ignore the * first parameter. * @@ -3305,7 +3282,7 @@ ZEND_METHOD(reflection_function, inNamespace) if (zend_parse_parameters_none() == FAILURE) { return; } - if ((name = _default_load_name(getThis())) == NULL) { + if ((name = _default_load_name(ZEND_THIS)) == NULL) { RETURN_FALSE; } if (Z_TYPE_P(name) == IS_STRING @@ -3328,7 +3305,7 @@ ZEND_METHOD(reflection_function, getNamespaceName) if (zend_parse_parameters_none() == FAILURE) { return; } - if ((name = _default_load_name(getThis())) == NULL) { + if ((name = _default_load_name(ZEND_THIS)) == NULL) { RETURN_FALSE; } if (Z_TYPE_P(name) == IS_STRING @@ -3351,7 +3328,7 @@ ZEND_METHOD(reflection_function, getShortName) if (zend_parse_parameters_none() == FAILURE) { return; } - if ((name = _default_load_name(getThis())) == NULL) { + if ((name = _default_load_name(ZEND_THIS)) == NULL) { RETURN_FALSE; } if (Z_TYPE_P(name) == IS_STRING @@ -3398,7 +3375,7 @@ ZEND_METHOD(reflection_function, getReturnType) RETURN_NULL(); } - reflection_type_factory(_copy_function(fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, &fptr->common.arg_info[-1], return_value); + reflection_type_factory(fptr->common.arg_info[-1].type, return_value); } /* }}} */ @@ -3441,7 +3418,7 @@ ZEND_METHOD(reflection_method, getModifiers) { reflection_object *intern; zend_function *mptr; - uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_IMPLICIT_PUBLIC + uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL; if (zend_parse_parameters_none() == FAILURE) { @@ -3504,7 +3481,7 @@ ZEND_METHOD(reflection_method, setAccessible) return; } - intern = Z_REFLECTION_P(getThis()); + intern = Z_REFLECTION_P(ZEND_THIS); intern->ignore_visibility = visible; } @@ -3524,7 +3501,7 @@ ZEND_METHOD(reflection_class_constant, __construct) return; } - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); /* Find the class entry */ @@ -3576,7 +3553,7 @@ ZEND_METHOD(reflection_class_constant, __toString) return; } GET_REFLECTION_OBJECT_PTR(ref); - _default_get_name(getThis(), &name); + _default_get_name(ZEND_THIS, &name); _class_const_string(&str, Z_STRVAL(name), ref, ""); zval_ptr_dtor(&name); RETURN_STR(smart_str_extract(&str)); @@ -3590,7 +3567,7 @@ ZEND_METHOD(reflection_class_constant, getName) if (zend_parse_parameters_none() == FAILURE) { return; } - _default_get_name(getThis(), return_value); + _default_get_name(ZEND_THIS, return_value); } /* }}} */ @@ -3611,7 +3588,7 @@ static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) / 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); + _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC); } /* }}} */ @@ -3727,7 +3704,7 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob } } - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); if (Z_TYPE_P(argument) == IS_OBJECT) { @@ -3771,9 +3748,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value zend_string *key; ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) { - if (((prop_info->flags & ZEND_ACC_SHADOW) && - prop_info->ce != ce) || - ((prop_info->flags & ZEND_ACC_PROTECTED) && + if (((prop_info->flags & ZEND_ACC_PROTECTED) && !zend_check_protected(prop_info->ce, ce)) || ((prop_info->flags & ZEND_ACC_PRIVATE) && prop_info->ce != ce)) { @@ -3786,7 +3761,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value } else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) { prop = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; } - if (!prop) { + if (!prop || (prop_info->type && Z_ISUNDEF_P(prop))) { continue; } @@ -3847,7 +3822,7 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue) if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { return; } - prop = zend_std_get_static_property(ce, name, 1); + prop = zend_std_get_static_property(ce, name, BP_VAR_IS); if (!prop) { if (def_value) { ZVAL_COPY(return_value, def_value); @@ -3868,6 +3843,7 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) { reflection_object *intern; zend_class_entry *ce; + zend_property_info *prop_info; zend_string *name; zval *variable_ptr, *value; @@ -3880,15 +3856,30 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { return; } - variable_ptr = zend_std_get_static_property(ce, name, 1); + variable_ptr = zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info); if (!variable_ptr) { + zend_clear_exception(); zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name)); return; } - ZVAL_DEREF(variable_ptr); + + if (Z_ISREF_P(variable_ptr)) { + zend_reference *ref = Z_REF_P(variable_ptr); + variable_ptr = Z_REFVAL_P(variable_ptr); + + if (!zend_verify_ref_assignable_zval(ref, value, 0)) { + return; + } + } + + if (prop_info->type && !zend_verify_property_type(prop_info, value, 0)) { + return; + } + zval_ptr_dtor(variable_ptr); ZVAL_COPY(variable_ptr, value); + } /* }}} */ @@ -3936,7 +3927,7 @@ ZEND_METHOD(reflection_class, getName) if (zend_parse_parameters_none() == FAILURE) { return; } - _default_get_name(getThis(), return_value); + _default_get_name(ZEND_THIS, return_value); } /* }}} */ @@ -4083,24 +4074,16 @@ ZEND_METHOD(reflection_class, hasMethod) { reflection_object *intern; zend_class_entry *ce; - char *name, *lc_name; - size_t name_len; + zend_string *name, *lc_name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ce); - lc_name = zend_str_tolower_dup(name, name_len); - if ((ce == zend_ce_closure && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) - && memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0) - || zend_hash_str_exists(&ce->function_table, lc_name, name_len)) { - efree(lc_name); - RETURN_TRUE; - } else { - efree(lc_name); - RETURN_FALSE; - } + lc_name = zend_string_tolower(name); + RETVAL_BOOL(zend_hash_exists(&ce->function_table, lc_name) || is_closure_invoke(ce, lc_name)); + zend_string_release(lc_name); } /* }}} */ @@ -4112,40 +4095,33 @@ ZEND_METHOD(reflection_class, getMethod) zend_class_entry *ce; zend_function *mptr; zval obj_tmp; - char *name, *lc_name; - size_t name_len; + zend_string *name, *lc_name; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ce); - lc_name = zend_str_tolower_dup(name, name_len); - if (ce == zend_ce_closure && !Z_ISUNDEF(intern->obj) && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) - && memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 + lc_name = zend_string_tolower(name); + if (!Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name) && (mptr = zend_get_closure_invoke_method(Z_OBJ(intern->obj))) != NULL) { /* don't assign closure_object since we only reflect the invoke handler method and not the closure definition itself */ reflection_method_factory(ce, mptr, NULL, return_value); - efree(lc_name); - } else if (ce == zend_ce_closure && Z_ISUNDEF(intern->obj) && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) - && memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 + } else if (Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name) && object_init_ex(&obj_tmp, ce) == SUCCESS && (mptr = zend_get_closure_invoke_method(Z_OBJ(obj_tmp))) != NULL) { /* don't assign closure_object since we only reflect the invoke handler method and not the closure definition itself */ reflection_method_factory(ce, mptr, NULL, return_value); zval_ptr_dtor(&obj_tmp); - efree(lc_name); - } else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lc_name, name_len)) != NULL) { + } else if ((mptr = zend_hash_find_ptr(&ce->function_table, lc_name)) != NULL) { reflection_method_factory(ce, mptr, NULL, return_value); - efree(lc_name); } else { - efree(lc_name); zend_throw_exception_ex(reflection_exception_ptr, 0, - "Method %s does not exist", name); - return; + "Method %s does not exist", ZSTR_VAL(name)); } + zend_string_release(lc_name); } /* }}} */ @@ -4153,11 +4129,9 @@ ZEND_METHOD(reflection_class, getMethod) static void _addmethod(zend_function *mptr, zend_class_entry *ce, zval *retval, zend_long filter, zval *obj) { zval method; - size_t len = ZSTR_LEN(mptr->common.function_name); zend_function *closure; if (mptr->common.fn_flags & filter) { - 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 + if (obj && is_closure_invoke(ce, mptr->common.function_name) && (closure = zend_get_closure_invoke_method(Z_OBJ_P(obj))) != NULL) { mptr = closure; @@ -4171,26 +4145,13 @@ static void _addmethod(zend_function *mptr, zend_class_entry *ce, zval *retval, } /* }}} */ -/* {{{ _addmethod */ -static int _addmethod_va(zval *el, int num_args, va_list args, zend_hash_key *hash_key) -{ - zend_function *mptr = (zend_function*)Z_PTR_P(el); - zend_class_entry *ce = *va_arg(args, zend_class_entry**); - zval *retval = va_arg(args, zval*); - long filter = va_arg(args, long); - zval *obj = va_arg(args, zval *); - - _addmethod(mptr, ce, retval, filter, obj); - return ZEND_HASH_APPLY_KEEP; -} -/* }}} */ - /* {{{ proto public ReflectionMethod[] ReflectionClass::getMethods([long $filter]) Returns an array of this class' methods */ ZEND_METHOD(reflection_class, getMethods) { reflection_object *intern; zend_class_entry *ce; + zend_function *mptr; zend_long filter = ZEND_ACC_PPP_MASK | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL | ZEND_ACC_STATIC; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &filter) == FAILURE) { @@ -4200,7 +4161,10 @@ ZEND_METHOD(reflection_class, getMethods) GET_REFLECTION_OBJECT_PTR(ce); array_init(return_value); - zend_hash_apply_with_arguments(&ce->function_table, (apply_func_args_t) _addmethod_va, 4, &ce, return_value, filter, intern->obj); + ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) { + _addmethod(mptr, ce, return_value, filter, &intern->obj); + } ZEND_HASH_FOREACH_END(); + if (Z_TYPE(intern->obj) != IS_UNDEF && instanceof_function(ce, zend_ce_closure)) { zend_function *closure = zend_get_closure_invoke_method(Z_OBJ(intern->obj)); if (closure) { @@ -4227,12 +4191,12 @@ ZEND_METHOD(reflection_class, hasProperty) GET_REFLECTION_OBJECT_PTR(ce); if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) { - if (property_info->flags & ZEND_ACC_SHADOW) { + if ((property_info->flags & ZEND_ACC_PRIVATE) && property_info->ce != ce) { RETURN_FALSE; } RETURN_TRUE; } else { - if (Z_TYPE(intern->obj) != IS_UNDEF && Z_OBJ_HANDLER(intern->obj, has_property)) { + if (Z_TYPE(intern->obj) != IS_UNDEF) { ZVAL_STR_COPY(&property, name); if (Z_OBJ_HANDLER(intern->obj, has_property)(&intern->obj, &property, 2, NULL)) { zval_ptr_dtor(&property); @@ -4262,20 +4226,20 @@ ZEND_METHOD(reflection_class, getProperty) GET_REFLECTION_OBJECT_PTR(ce); if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) { - if ((property_info->flags & ZEND_ACC_SHADOW) == 0) { - reflection_property_factory(ce, name, property_info, return_value); + if (!(property_info->flags & ZEND_ACC_PRIVATE) || property_info->ce == ce) { + reflection_property_factory(ce, name, property_info, return_value, 0); return; } } else if (Z_TYPE(intern->obj) != IS_UNDEF) { /* Check for dynamic properties */ if (zend_hash_exists(Z_OBJ_HT(intern->obj)->get_properties(&intern->obj), name)) { zend_property_info property_info_tmp; - property_info_tmp.flags = ZEND_ACC_IMPLICIT_PUBLIC; + property_info_tmp.flags = ZEND_ACC_PUBLIC; property_info_tmp.name = name; property_info_tmp.doc_comment = NULL; property_info_tmp.ce = ce; - reflection_property_factory(ce, name, &property_info_tmp, return_value); + reflection_property_factory(ce, name, &property_info_tmp, return_value, 1); return; } } @@ -4304,7 +4268,10 @@ ZEND_METHOD(reflection_class, getProperty) } ce = ce2; - if ((property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len)) != NULL && (property_info->flags & ZEND_ACC_SHADOW) == 0) { + property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len); + if (property_info != NULL + && (!(property_info->flags & ZEND_ACC_PRIVATE) + || property_info->ce == ce)) { reflection_property_factory_str(ce, str_name, str_name_len, property_info, return_value); return; } @@ -4315,59 +4282,45 @@ ZEND_METHOD(reflection_class, getProperty) /* }}} */ /* {{{ _addproperty */ -static int _addproperty(zval *el, int num_args, va_list args, zend_hash_key *hash_key) +static void _addproperty(zend_property_info *pptr, zend_string *key, zend_class_entry *ce, zval *retval, long filter) { - zval property; - zend_property_info *pptr = (zend_property_info*)Z_PTR_P(el); - zend_class_entry *ce = *va_arg(args, zend_class_entry**); - zval *retval = va_arg(args, zval*); - long filter = va_arg(args, long); - - if (pptr->flags & ZEND_ACC_SHADOW) { - return 0; + if ((pptr->flags & ZEND_ACC_PRIVATE) && pptr->ce != ce) { + return; } if (pptr->flags & filter) { - const char *class_name, *prop_name; - size_t prop_name_len; - zend_unmangle_property_name_ex(pptr->name, &class_name, &prop_name, &prop_name_len); - reflection_property_factory_str(ce, prop_name, prop_name_len, pptr, &property); + zval property; + reflection_property_factory(ce, key, pptr, &property, 0); add_next_index_zval(retval, &property); } - return 0; } /* }}} */ /* {{{ _adddynproperty */ -static int _adddynproperty(zval *ptr, int num_args, va_list args, zend_hash_key *hash_key) +static void _adddynproperty(zval *ptr, zend_string *key, zend_class_entry *ce, zval *retval) { + zend_property_info property_info; zval property; - zend_class_entry *ce = *va_arg(args, zend_class_entry**); - zval *retval = va_arg(args, zval*); /* under some circumstances, the properties hash table may contain numeric - * properties (e.g. when casting from array). This is a WONT FIX bug, at + * properties (e.g. when casting from array). This is a WON'T FIX bug, at * least for the moment. Ignore these */ - if (hash_key->key == NULL) { - return 0; + if (key == NULL) { + return; } - if (ZSTR_VAL(hash_key->key)[0] == '\0') { - return 0; /* non public cannot be dynamic */ + /* Not a dynamic property */ + if (Z_TYPE_P(ptr) == IS_INDIRECT) { + return; } - if (zend_get_property_info(ce, hash_key->key, 1) == NULL) { - zend_property_info property_info; - - property_info.doc_comment = NULL; - property_info.flags = ZEND_ACC_IMPLICIT_PUBLIC; - property_info.name = hash_key->key; - property_info.ce = ce; - property_info.offset = -1; - reflection_property_factory(ce, hash_key->key, &property_info, &property); - add_next_index_zval(retval, &property); - } - return 0; + property_info.doc_comment = NULL; + property_info.flags = ZEND_ACC_PUBLIC; + property_info.name = key; + property_info.ce = ce; + property_info.offset = -1; + reflection_property_factory(ce, key, &property_info, &property, 1); + add_next_index_zval(retval, &property); } /* }}} */ @@ -4377,6 +4330,8 @@ ZEND_METHOD(reflection_class, getProperties) { reflection_object *intern; zend_class_entry *ce; + zend_string *key; + zend_property_info *prop_info; zend_long filter = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &filter) == FAILURE) { @@ -4386,11 +4341,16 @@ ZEND_METHOD(reflection_class, getProperties) GET_REFLECTION_OBJECT_PTR(ce); array_init(return_value); - zend_hash_apply_with_arguments(&ce->properties_info, (apply_func_args_t) _addproperty, 3, &ce, return_value, filter); + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) { + _addproperty(prop_info, key, ce, return_value, filter); + } ZEND_HASH_FOREACH_END(); - if (Z_TYPE(intern->obj) != IS_UNDEF && (filter & ZEND_ACC_PUBLIC) != 0 && Z_OBJ_HT(intern->obj)->get_properties) { + if (Z_TYPE(intern->obj) != IS_UNDEF && (filter & ZEND_ACC_PUBLIC) != 0) { HashTable *properties = Z_OBJ_HT(intern->obj)->get_properties(&intern->obj); - zend_hash_apply_with_arguments(properties, (apply_func_args_t) _adddynproperty, 2, &ce, return_value); + zval *prop; + ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) { + _adddynproperty(prop, key, ce, return_value); + } ZEND_HASH_FOREACH_END(); } } /* }}} */ @@ -4837,6 +4797,7 @@ ZEND_METHOD(reflection_class, getInterfaces) if (ce->num_interfaces) { uint32_t i; + ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED); array_init(return_value); for (i=0; i < ce->num_interfaces; i++) { zval interface; @@ -4868,6 +4829,7 @@ ZEND_METHOD(reflection_class, getInterfaceNames) return; } + ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED); array_init(return_value); for (i=0; i < ce->num_interfaces; i++) { @@ -4898,8 +4860,13 @@ ZEND_METHOD(reflection_class, getTraits) for (i=0; i < ce->num_traits; i++) { zval trait; - zend_reflection_class_factory(ce->traits[i], &trait); - zend_hash_update(Z_ARRVAL_P(return_value), ce->traits[i]->name, &trait); + zend_class_entry *trait_ce; + + trait_ce = zend_fetch_class_by_name(ce->trait_names[i].name, + ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT); + ZEND_ASSERT(trait_ce); + zend_reflection_class_factory(trait_ce, &trait); + zend_hash_update(Z_ARRVAL_P(return_value), ce->trait_names[i].name, &trait); } } /* }}} */ @@ -4925,7 +4892,7 @@ ZEND_METHOD(reflection_class, getTraitNames) array_init(return_value); for (i=0; i < ce->num_traits; i++) { - add_next_index_str(return_value, zend_string_copy(ce->traits[i]->name)); + add_next_index_str(return_value, zend_string_copy(ce->trait_names[i].name)); } } /* }}} */ @@ -5148,7 +5115,7 @@ ZEND_METHOD(reflection_class, inNamespace) if (zend_parse_parameters_none() == FAILURE) { return; } - if ((name = _default_load_name(getThis())) == NULL) { + if ((name = _default_load_name(ZEND_THIS)) == NULL) { RETURN_FALSE; } if (Z_TYPE_P(name) == IS_STRING @@ -5171,7 +5138,7 @@ ZEND_METHOD(reflection_class, getNamespaceName) if (zend_parse_parameters_none() == FAILURE) { return; } - if ((name = _default_load_name(getThis())) == NULL) { + if ((name = _default_load_name(ZEND_THIS)) == NULL) { RETURN_FALSE; } if (Z_TYPE_P(name) == IS_STRING @@ -5194,7 +5161,7 @@ ZEND_METHOD(reflection_class, getShortName) if (zend_parse_parameters_none() == FAILURE) { return; } - if ((name = _default_load_name(getThis())) == NULL) { + if ((name = _default_load_name(ZEND_THIS)) == NULL) { RETURN_FALSE; } if (Z_TYPE_P(name) == IS_STRING @@ -5256,7 +5223,7 @@ ZEND_METHOD(reflection_property, __construct) return; } - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); /* Find the class entry */ @@ -5278,9 +5245,12 @@ ZEND_METHOD(reflection_property, __construct) /* returns out of this function */ } - if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) == NULL || (property_info->flags & ZEND_ACC_SHADOW)) { + property_info = zend_hash_find_ptr(&ce->properties_info, name); + if (property_info == NULL + || ((property_info->flags & ZEND_ACC_PRIVATE) + && property_info->ce != ce)) { /* Check for dynamic properties */ - if (property_info == NULL && Z_TYPE_P(classname) == IS_OBJECT && Z_OBJ_HT_P(classname)->get_properties) { + if (property_info == NULL && Z_TYPE_P(classname) == IS_OBJECT) { if (zend_hash_exists(Z_OBJ_HT_P(classname)->get_properties(classname), name)) { dynam_prop = 1; } @@ -5315,14 +5285,15 @@ ZEND_METHOD(reflection_property, __construct) reference = (property_reference*) emalloc(sizeof(property_reference)); if (dynam_prop) { - reference->prop.flags = ZEND_ACC_IMPLICIT_PUBLIC; + reference->prop.flags = ZEND_ACC_PUBLIC; reference->prop.name = name; reference->prop.doc_comment = NULL; reference->prop.ce = ce; + reference->dynamic = 1; } else { reference->prop = *property_info; + reference->dynamic = 0; } - reference->ce = ce; reference->unmangled_name = zend_string_copy(name); intern->ptr = reference; intern->ref_type = REF_TYPE_PROPERTY; @@ -5343,7 +5314,7 @@ ZEND_METHOD(reflection_property, __toString) return; } GET_REFLECTION_OBJECT_PTR(ref); - _property_string(&str, &ref->prop, ZSTR_VAL(ref->unmangled_name), ""); + _property_string(&str, &ref->prop, ZSTR_VAL(ref->unmangled_name), "", ref->dynamic); RETURN_STR(smart_str_extract(&str)); } /* }}} */ @@ -5355,7 +5326,7 @@ ZEND_METHOD(reflection_property, getName) if (zend_parse_parameters_none() == FAILURE) { return; } - _default_get_name(getThis(), return_value); + _default_get_name(ZEND_THIS, return_value); } /* }}} */ @@ -5376,7 +5347,7 @@ static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ Returns whether this property is public */ ZEND_METHOD(reflection_property, isPublic) { - _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC); + _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC); } /* }}} */ @@ -5408,7 +5379,14 @@ ZEND_METHOD(reflection_property, isStatic) Returns whether this property is default (declared at compilation time). */ ZEND_METHOD(reflection_property, isDefault) { - _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ~ZEND_ACC_IMPLICIT_PUBLIC); + reflection_object *intern; + property_reference *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ref); + RETURN_BOOL(!ref->dynamic); } /* }}} */ @@ -5418,7 +5396,7 @@ ZEND_METHOD(reflection_property, getModifiers) { reflection_object *intern; property_reference *ref; - uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_IMPLICIT_PUBLIC | ZEND_ACC_STATIC; + uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC; if (zend_parse_parameters_none() == FAILURE) { return; @@ -5440,15 +5418,15 @@ ZEND_METHOD(reflection_property, getValue) GET_REFLECTION_OBJECT_PTR(ref); - if (!(ref->prop.flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && intern->ignore_visibility == 0) { - name = _default_load_name(getThis()); + if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) { + name = _default_load_name(ZEND_THIS); zend_throw_exception_ex(reflection_exception_ptr, 0, "Cannot access non-public member %s::$%s", ZSTR_VAL(intern->ce->name), Z_STRVAL_P(name)); return; } if (ref->prop.flags & ZEND_ACC_STATIC) { - member_p = zend_read_static_property_ex(ref->ce, ref->unmangled_name, 0); + member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, 0); if (member_p) { ZVAL_COPY_DEREF(return_value, member_p); } @@ -5464,7 +5442,7 @@ ZEND_METHOD(reflection_property, getValue) /* Returns from this function */ } - member_p = zend_read_property_ex(ref->ce, object, ref->unmangled_name, 0, &rv); + member_p = zend_read_property_ex(intern->ce, object, ref->unmangled_name, 0, &rv); if (member_p != &rv) { ZVAL_COPY_DEREF(return_value, member_p); } else { @@ -5490,7 +5468,7 @@ ZEND_METHOD(reflection_property, setValue) GET_REFLECTION_OBJECT_PTR(ref); if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) { - name = _default_load_name(getThis()); + name = _default_load_name(ZEND_THIS); zend_throw_exception_ex(reflection_exception_ptr, 0, "Cannot access non-public member %s::$%s", ZSTR_VAL(intern->ce->name), Z_STRVAL_P(name)); return; @@ -5503,13 +5481,62 @@ ZEND_METHOD(reflection_property, setValue) } } - zend_update_static_property_ex(ref->ce, ref->unmangled_name, value); + zend_update_static_property_ex(intern->ce, ref->unmangled_name, value); } else { if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) { return; } - zend_update_property_ex(ref->ce, object, ref->unmangled_name, value); + zend_update_property_ex(intern->ce, object, ref->unmangled_name, value); + } +} +/* }}} */ + +/* {{{ proto public mixed ReflectionProperty::isInitialized([stdclass object]) + Returns this property's value */ +ZEND_METHOD(reflection_property, isInitialized) +{ + reflection_object *intern; + property_reference *ref; + zval *object, *name; + zval *member_p = NULL; + + GET_REFLECTION_OBJECT_PTR(ref); + + if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) { + name = _default_load_name(getThis()); + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Cannot access non-public member %s::$%s", ZSTR_VAL(intern->ce->name), Z_STRVAL_P(name)); + return; + } + + if (ref->prop.flags & ZEND_ACC_STATIC) { + member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, 1); + if (member_p) { + RETURN_BOOL(!Z_ISUNDEF_P(member_p)) + } + RETURN_FALSE; + } else { + zval name_zv; + zend_class_entry *old_scope; + int retval; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) { + return; + } + + if (!instanceof_function(Z_OBJCE_P(object), ref->prop.ce)) { + _DO_THROW("Given object is not an instance of the class this property was declared in"); + /* Returns from this function */ + } + + old_scope = EG(fake_scope); + EG(fake_scope) = intern->ce; + ZVAL_STR(&name_zv, ref->unmangled_name); + retval = Z_OBJ_HT_P(object)->has_property(object, &name_zv, ZEND_PROPERTY_EXISTS, NULL); + EG(fake_scope) = old_scope; + + RETVAL_BOOL(retval); } } /* }}} */ @@ -5528,9 +5555,9 @@ ZEND_METHOD(reflection_property, getDeclaringClass) } GET_REFLECTION_OBJECT_PTR(ref); - ce = tmp_ce = ref->ce; + ce = tmp_ce = intern->ce; while (tmp_ce && (tmp_info = zend_hash_find_ptr(&tmp_ce->properties_info, ref->unmangled_name)) != NULL) { - if (tmp_info->flags & ZEND_ACC_PRIVATE || tmp_info->flags & ZEND_ACC_SHADOW) { + if (tmp_info->flags & ZEND_ACC_PRIVATE) { /* it's a private property, so it can't be inherited */ break; } @@ -5575,12 +5602,50 @@ ZEND_METHOD(reflection_property, setAccessible) return; } - intern = Z_REFLECTION_P(getThis()); + intern = Z_REFLECTION_P(ZEND_THIS); intern->ignore_visibility = visible; } /* }}} */ +/* {{{ proto public ReflectionType ReflectionProperty::getType() + Returns the type associated with the property */ +ZEND_METHOD(reflection_property, getType) +{ + reflection_object *intern; + property_reference *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + GET_REFLECTION_OBJECT_PTR(ref); + + if (!ZEND_TYPE_IS_SET(ref->prop.type)) { + RETURN_NULL(); + } + + reflection_type_factory(ref->prop.type, return_value); +} +/* }}} */ + +/* {{{ proto public bool ReflectionProperty::hasType() + Returns whether property has a type */ +ZEND_METHOD(reflection_property, hasType) +{ + reflection_object *intern; + property_reference *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + GET_REFLECTION_OBJECT_PTR(ref); + + RETVAL_BOOL(ZEND_TYPE_IS_SET(ref->prop.type)); +} +/* }}} */ + /* {{{ proto public static mixed ReflectionExtension::export(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_extension, export) @@ -5606,7 +5671,7 @@ ZEND_METHOD(reflection_extension, __construct) return; } - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); lcname = do_alloca(name_len + 1, use_heap); zend_str_tolower_copy(lcname, name_str, name_len); @@ -5649,7 +5714,7 @@ ZEND_METHOD(reflection_extension, getName) if (zend_parse_parameters_none() == FAILURE) { return; } - _default_get_name(getThis(), return_value); + _default_get_name(ZEND_THIS, return_value); } /* }}} */ @@ -5699,27 +5764,13 @@ ZEND_METHOD(reflection_extension, getFunctions) } /* }}} */ -static int _addconstant(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ -{ - zval const_val; - zend_constant *constant = (zend_constant*)Z_PTR_P(el); - zval *retval = va_arg(args, zval*); - int number = va_arg(args, int); - - if (number == ZEND_CONSTANT_MODULE_NUMBER(constant)) { - ZVAL_COPY_OR_DUP(&const_val, &constant->value); - zend_hash_update(Z_ARRVAL_P(retval), constant->name, &const_val); - } - return 0; -} -/* }}} */ - /* {{{ proto public array ReflectionExtension::getConstants() Returns an associative array containing this extension's constants and their values */ ZEND_METHOD(reflection_extension, getConstants) { reflection_object *intern; zend_module_entry *module; + zend_constant *constant; if (zend_parse_parameters_none() == FAILURE) { return; @@ -5727,28 +5778,28 @@ ZEND_METHOD(reflection_extension, getConstants) GET_REFLECTION_OBJECT_PTR(module); array_init(return_value); - zend_hash_apply_with_arguments(EG(zend_constants), (apply_func_args_t) _addconstant, 2, return_value, module->module_number); + ZEND_HASH_FOREACH_PTR(EG(zend_constants), constant) { + if (module->module_number == ZEND_CONSTANT_MODULE_NUMBER(constant)) { + zval const_val; + ZVAL_COPY_OR_DUP(&const_val, &constant->value); + zend_hash_update(Z_ARRVAL_P(return_value), constant->name, &const_val); + } + } ZEND_HASH_FOREACH_END(); } /* }}} */ /* {{{ _addinientry */ -static int _addinientry(zval *el, int num_args, va_list args, zend_hash_key *hash_key) +static void _addinientry(zend_ini_entry *ini_entry, zval *retval, int number) { - zend_ini_entry *ini_entry = (zend_ini_entry*)Z_PTR_P(el); - zval *retval = va_arg(args, zval*); - int number = va_arg(args, int); - if (number == ini_entry->module_number) { + zval zv; if (ini_entry->value) { - zval zv; - ZVAL_STR_COPY(&zv, ini_entry->value); - zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &zv); } else { - zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &EG(uninitialized_zval)); + ZVAL_NULL(&zv); } + zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &zv); } - return ZEND_HASH_APPLY_KEEP; } /* }}} */ @@ -5758,6 +5809,7 @@ ZEND_METHOD(reflection_extension, getINIEntries) { reflection_object *intern; zend_module_entry *module; + zend_ini_entry *ini_entry; if (zend_parse_parameters_none() == FAILURE) { return; @@ -5765,36 +5817,33 @@ ZEND_METHOD(reflection_extension, getINIEntries) GET_REFLECTION_OBJECT_PTR(module); array_init(return_value); - zend_hash_apply_with_arguments(EG(ini_directives), (apply_func_args_t) _addinientry, 2, return_value, module->module_number); + ZEND_HASH_FOREACH_PTR(EG(ini_directives), ini_entry) { + _addinientry(ini_entry, return_value, module->module_number); + } ZEND_HASH_FOREACH_END(); } /* }}} */ /* {{{ add_extension_class */ -static int add_extension_class(zval *zv, int num_args, va_list args, zend_hash_key *hash_key) +static void add_extension_class(zend_class_entry *ce, zend_string *key, zval *class_array, zend_module_entry *module, zend_bool add_reflection_class) { - zend_class_entry *ce = Z_PTR_P(zv); - zval *class_array = va_arg(args, zval*), zclass; - struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*); - int add_reflection_class = va_arg(args, int); - - if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) { + if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) { zend_string *name; - if (zend_binary_strcasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(hash_key->key), ZSTR_LEN(hash_key->key))) { - /* This is an class alias, use alias name */ - name = hash_key->key; + if (!zend_string_equals_ci(ce->name, key)) { + /* This is a class alias, use alias name */ + name = key; } else { /* Use class name */ name = ce->name; } if (add_reflection_class) { + zval zclass; zend_reflection_class_factory(ce, &zclass); zend_hash_update(Z_ARRVAL_P(class_array), name, &zclass); } else { add_next_index_str(class_array, zend_string_copy(name)); } } - return ZEND_HASH_APPLY_KEEP; } /* }}} */ @@ -5804,6 +5853,8 @@ ZEND_METHOD(reflection_extension, getClasses) { reflection_object *intern; zend_module_entry *module; + zend_string *key; + zend_class_entry *ce; if (zend_parse_parameters_none() == FAILURE) { return; @@ -5811,7 +5862,9 @@ ZEND_METHOD(reflection_extension, getClasses) GET_REFLECTION_OBJECT_PTR(module); array_init(return_value); - zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) add_extension_class, 3, return_value, module, 1); + ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) { + add_extension_class(ce, key, return_value, module, 1); + } ZEND_HASH_FOREACH_END(); } /* }}} */ @@ -5821,6 +5874,8 @@ ZEND_METHOD(reflection_extension, getClassNames) { reflection_object *intern; zend_module_entry *module; + zend_string *key; + zend_class_entry *ce; if (zend_parse_parameters_none() == FAILURE) { return; @@ -5828,7 +5883,9 @@ ZEND_METHOD(reflection_extension, getClassNames) GET_REFLECTION_OBJECT_PTR(module); array_init(return_value); - zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) add_extension_class, 3, return_value, module, 0); + ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) { + add_extension_class(ce, key, return_value, module, 0); + } ZEND_HASH_FOREACH_END(); } /* }}} */ @@ -5970,7 +6027,7 @@ ZEND_METHOD(reflection_zend_extension, __construct) return; } - object = getThis(); + object = ZEND_THIS; intern = Z_REFLECTION_P(object); extension = zend_get_extension(name_str); @@ -6100,6 +6157,89 @@ ZEND_METHOD(reflection_zend_extension, getCopyright) } /* }}} */ +/* {{{ proto public ReflectionReference::__construct() + * Dummy constructor -- always throws ReflectionExceptions. */ +ZEND_METHOD(reflection_reference, __construct) +{ + _DO_THROW( + "Cannot directly instantiate ReflectionReference. " + "Use ReflectionReference::fromArrayElement() instead" + ); +} +/* }}} */ + +/* {{{ proto public ReflectionReference|null ReflectionReference::fromArrayElement(array array, mixed key) + * Create ReflectionReference for array item. Returns null if not a reference. */ +ZEND_METHOD(reflection_reference, fromArrayElement) +{ + HashTable *ht; + zval *key, *item; + reflection_object *intern; + + if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "hz", &ht, &key) == FAILURE) { + return; + } + + if (Z_TYPE_P(key) == IS_LONG) { + item = zend_hash_index_find(ht, Z_LVAL_P(key)); + } else if (Z_TYPE_P(key) == IS_STRING) { + item = zend_symtable_find(ht, Z_STR_P(key)); + } else { + zend_type_error("Key must be array or string"); + return; + } + + if (!item) { + _DO_THROW("Array key not found"); + } + + if (Z_TYPE_P(item) != IS_REFERENCE) { + RETURN_NULL(); + } + + object_init_ex(return_value, reflection_reference_ptr); + intern = Z_REFLECTION_P(return_value); + ZVAL_COPY(&intern->obj, item); + intern->ref_type = REF_TYPE_OTHER; +} +/* }}} */ + +/* {{{ proto public int|string ReflectionReference::getId() + * Returns a unique identifier for the reference. + * The format of the return value is unspecified and may change. */ +ZEND_METHOD(reflection_reference, getId) +{ + reflection_object *intern; + unsigned char digest[20]; + PHP_SHA1_CTX context; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + intern = Z_REFLECTION_P(getThis()); + if (Z_TYPE(intern->obj) != IS_REFERENCE) { + _DO_THROW("Corrupted ReflectionReference object"); + } + + if (!REFLECTION_G(key_initialized)) { + if (php_random_bytes_throw(&REFLECTION_G(key_initialized), 16) == FAILURE) { + return; + } + + REFLECTION_G(key_initialized) = 1; + } + + /* SHA1(ref || key) to avoid directly exposing memory addresses. */ + PHP_SHA1Init(&context); + PHP_SHA1Update(&context, (unsigned char *) &Z_REF(intern->obj), sizeof(zend_reference *)); + PHP_SHA1Update(&context, REFLECTION_G(key), REFLECTION_KEY_LEN); + PHP_SHA1Final(digest, &context); + + RETURN_STRINGL((char *) digest, sizeof(digest)); +} +/* }}} */ + /* {{{ method tables */ static const zend_function_entry reflection_exception_functions[] = { PHP_FE_END @@ -6428,6 +6568,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_property_setValue, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_property_isInitialized, 0, 0, 0) + ZEND_ARG_INFO(0, object) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO(arginfo_reflection_property_setAccessible, 0) ZEND_ARG_INFO(0, visible) ZEND_END_ARG_INFO() @@ -6440,6 +6584,7 @@ static const zend_function_entry reflection_property_functions[] = { ZEND_ME(reflection_property, getName, arginfo_reflection__void, 0) ZEND_ME(reflection_property, getValue, arginfo_reflection_property_getValue, 0) ZEND_ME(reflection_property, setValue, arginfo_reflection_property_setValue, 0) + ZEND_ME(reflection_property, isInitialized, arginfo_reflection_property_isInitialized, 0) ZEND_ME(reflection_property, isPublic, arginfo_reflection__void, 0) ZEND_ME(reflection_property, isPrivate, arginfo_reflection__void, 0) ZEND_ME(reflection_property, isProtected, arginfo_reflection__void, 0) @@ -6449,6 +6594,8 @@ static const zend_function_entry reflection_property_functions[] = { ZEND_ME(reflection_property, getDeclaringClass, arginfo_reflection__void, 0) ZEND_ME(reflection_property, getDocComment, arginfo_reflection__void, 0) ZEND_ME(reflection_property, setAccessible, arginfo_reflection_property_setAccessible, 0) + ZEND_ME(reflection_property, getType, arginfo_reflection__void, 0) + ZEND_ME(reflection_property, hasType, arginfo_reflection__void, 0) PHP_FE_END }; @@ -6576,6 +6723,21 @@ static const zend_function_entry reflection_zend_extension_functions[] = { ZEND_ME(reflection_zend_extension, getCopyright, arginfo_reflection__void, 0) PHP_FE_END }; + +ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_reference_fromArrayElement, 0, 0, 2) + ZEND_ARG_INFO(0, array) + ZEND_ARG_INFO(0, key) +ZEND_END_ARG_INFO() + +static const zend_function_entry reflection_reference_functions[] = { + ZEND_ME(reflection_reference, fromArrayElement, arginfo_reflection_reference_fromArrayElement, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(reflection_reference, getId, arginfo_reflection__void, ZEND_ACC_PUBLIC) + + /* Always throwing dummy methods */ + ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE) + ZEND_ME(reflection_reference, __construct, arginfo_reflection__void, ZEND_ACC_PRIVATE) + PHP_FE_END +}; /* }}} */ static const zend_function_entry reflection_ext_functions[] = { /* {{{ */ @@ -6583,7 +6745,7 @@ static const zend_function_entry reflection_ext_functions[] = { /* {{{ */ }; /* }}} */ /* {{{ _reflection_write_property */ -static void _reflection_write_property(zval *object, zval *member, zval *value, void **cache_slot) +static zval *_reflection_write_property(zval *object, zval *member, zval *value, void **cache_slot) { if ((Z_TYPE_P(member) == IS_STRING) && zend_hash_exists(&Z_OBJCE_P(object)->properties_info, Z_STR_P(member)) @@ -6592,14 +6754,21 @@ static void _reflection_write_property(zval *object, zval *member, zval *value, { zend_throw_exception_ex(reflection_exception_ptr, 0, "Cannot set read-only property %s::$%s", ZSTR_VAL(Z_OBJCE_P(object)->name), Z_STRVAL_P(member)); + return &EG(uninitialized_zval); } else { - zend_std_write_property(object, member, value, cache_slot); + return zend_std_write_property(object, member, value, cache_slot); } } /* }}} */ +static void reflection_init_class_handlers(zend_class_entry *ce) { + ce->create_object = reflection_objects_new; + ce->serialize = zend_class_serialize_deny; + ce->unserialize = zend_class_unserialize_deny; +} + PHP_MINIT_FUNCTION(reflection) /* {{{ */ { zend_class_entry _reflection_entry; @@ -6621,38 +6790,38 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflector_ptr = zend_register_internal_interface(&_reflection_entry); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionFunctionAbstract", reflection_function_abstract_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_function_abstract_ptr = zend_register_internal_class(&_reflection_entry); zend_class_implements(reflection_function_abstract_ptr, 1, reflector_ptr); zend_declare_property_string(reflection_function_abstract_ptr, "name", sizeof("name")-1, "", ZEND_ACC_ABSTRACT); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionFunction", reflection_function_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_function_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_function_abstract_ptr); zend_declare_property_string(reflection_function_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); REGISTER_REFLECTION_CLASS_CONST_LONG(function, "IS_DEPRECATED", ZEND_ACC_DEPRECATED); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionGenerator", reflection_generator_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_generator_ptr = zend_register_internal_class(&_reflection_entry); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionParameter", reflection_parameter_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_parameter_ptr = zend_register_internal_class(&_reflection_entry); zend_class_implements(reflection_parameter_ptr, 1, reflector_ptr); zend_declare_property_string(reflection_parameter_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionType", reflection_type_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); 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_init_class_handlers(&_reflection_entry); 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; + reflection_init_class_handlers(&_reflection_entry); reflection_method_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_function_abstract_ptr); zend_declare_property_string(reflection_method_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); zend_declare_property_string(reflection_method_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC); @@ -6665,7 +6834,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ REGISTER_REFLECTION_CLASS_CONST_LONG(method, "IS_FINAL", ZEND_ACC_FINAL); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionClass", reflection_class_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_class_ptr = zend_register_internal_class(&_reflection_entry); zend_class_implements(reflection_class_ptr, 1, reflector_ptr); zend_declare_property_string(reflection_class_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); @@ -6675,18 +6844,18 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ REGISTER_REFLECTION_CLASS_CONST_LONG(class, "IS_FINAL", ZEND_ACC_FINAL); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionObject", reflection_object_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_object_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_class_ptr); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionProperty", reflection_property_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_property_ptr = zend_register_internal_class(&_reflection_entry); zend_class_implements(reflection_property_ptr, 1, reflector_ptr); 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_init_class_handlers(&_reflection_entry); 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); @@ -6698,17 +6867,24 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PRIVATE", ZEND_ACC_PRIVATE); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionExtension", reflection_extension_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_extension_ptr = zend_register_internal_class(&_reflection_entry); zend_class_implements(reflection_extension_ptr, 1, reflector_ptr); zend_declare_property_string(reflection_extension_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionZendExtension", reflection_zend_extension_functions); - _reflection_entry.create_object = reflection_objects_new; + reflection_init_class_handlers(&_reflection_entry); reflection_zend_extension_ptr = zend_register_internal_class(&_reflection_entry); zend_class_implements(reflection_zend_extension_ptr, 1, reflector_ptr); zend_declare_property_string(reflection_zend_extension_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); + INIT_CLASS_ENTRY(_reflection_entry, "ReflectionReference", reflection_reference_functions); + reflection_init_class_handlers(&_reflection_entry); + _reflection_entry.ce_flags |= ZEND_ACC_FINAL; + reflection_reference_ptr = zend_register_internal_class(&_reflection_entry); + + REFLECTION_G(key_initialized) = 0; + return SUCCESS; } /* }}} */ @@ -6729,14 +6905,9 @@ zend_module_entry reflection_module_entry = { /* {{{ */ NULL, PHP_MINFO(reflection), PHP_REFLECTION_VERSION, - STANDARD_MODULE_PROPERTIES + ZEND_MODULE_GLOBALS(reflection), + NULL, + NULL, + NULL, + STANDARD_MODULE_PROPERTIES_EX }; /* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - * vim600: noet sw=4 ts=4 fdm=marker - */ |