From 7b7551085b2898ef718ec830fd498681f9bce851 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 1 Sep 2005 10:05:01 +0000 Subject: [PATCH] Support for class constants and static members for internal classes --- NEWS | 2 + Zend/zend.c | 35 +++- Zend/zend.h | 1 + Zend/zend_API.c | 301 +++++++++++++++++++++++++++++++- Zend/zend_API.h | 23 +++ Zend/zend_builtin_functions.c | 1 + Zend/zend_compile.c | 37 ++-- Zend/zend_object_handlers.c | 5 +- Zend/zend_opcode.c | 14 +- Zend/zend_reflection_api.c | 1 + ext/reflection/php_reflection.c | 1 + 11 files changed, 393 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index eb7f6af8423..c881bce6a71 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 6.0 +- Implemented support for class constants and static members for internal + classes (Dmitry, Michael Wallner) - Unicode support. (Andrei, Dmitriy, et al) - Changed "instanceof" operator, is_a() and is_subclass_of() functions to not call __autoload(). (Dmitry) diff --git a/Zend/zend.c b/Zend/zend.c index 644ed615b80..b5ae4e46aa1 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -838,7 +838,6 @@ static void const_to_unicode(zend_constant *c) static void class_to_unicode(zend_class_entry **ce) { zend_class_entry *new_ce = malloc(sizeof(zend_class_entry)); - zend_constant tmp_const; zend_property_info tmp_info; zval* tmp_zval; @@ -884,10 +883,36 @@ static void class_to_unicode(zend_class_entry **ce) zend_u_hash_init_ex(&new_ce->default_properties, (*ce)->default_properties.nNumOfElements, NULL, (*ce)->default_properties.pDestructor, 1, 1, 0); zend_hash_copy(&new_ce->default_properties, &(*ce)->default_properties, (copy_ctor_func_t) zval_ptr_to_unicode, &tmp_zval, sizeof(zval*)); - if (new_ce->static_members) { - new_ce->static_members = (HashTable*)malloc(sizeof(HashTable)); - zend_u_hash_init_ex(new_ce->static_members, (*ce)->static_members->nNumOfElements, NULL, (*ce)->static_members->pDestructor, 1, 1, 0); - zend_hash_copy(new_ce->static_members, (*ce)->static_members, (copy_ctor_func_t) zval_ptr_to_unicode, &tmp_zval, sizeof(zval*)); + zend_u_hash_init_ex(&new_ce->default_static_members, (*ce)->default_static_members.nNumOfElements, NULL, (*ce)->default_static_members.pDestructor, 1, 1, 0); + + { + HashPosition pos; + zval **p; + + zend_hash_internal_pointer_reset_ex(&(*ce)->default_static_members, &pos); + while (zend_hash_get_current_data_ex(&(*ce)->default_static_members, (void**)&p, &pos) == SUCCESS) { + char *str_index; + uint str_length; + ulong num_index; + zval **q; + + zend_hash_get_current_key_ex(&(*ce)->default_static_members, &str_index, &str_length, &num_index, 0, &pos); + if ((*p)->is_ref && + (*ce)->parent && + zend_hash_find(&(*ce)->parent->default_static_members, str_index, str_length, (void**)&q) == SUCCESS && + *p == *q && + zend_hash_find(&new_ce->parent->u_twin->default_static_members, str_index, str_length, (void**)&q) == SUCCESS) { + (*q)->refcount++; + (*q)->is_ref = 1; + zend_hash_add(&new_ce->default_static_members, str_index, str_length, (void**)q, sizeof(zval*), NULL); + } else { + zval *q = *p; + zval_ptr_to_unicode(&q); + q->is_ref = 0; + zend_hash_add(&new_ce->default_static_members, str_index, str_length, (void**)&q, sizeof(zval*), NULL); + } + zend_hash_move_forward_ex(&(*ce)->default_static_members, &pos); + } } *ce = new_ce; diff --git a/Zend/zend.h b/Zend/zend.h index 5d243b12994..2590398467c 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -347,6 +347,7 @@ struct _zend_class_entry { HashTable function_table; HashTable default_properties; HashTable properties_info; + HashTable default_static_members; HashTable *static_members; HashTable constants_table; struct _zend_function_entry *builtin_functions; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 0b54bae3d13..7fd4ba84960 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1076,13 +1076,65 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destro ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) { - if (!class_type->constants_updated) { + if (!class_type->constants_updated || !class_type->static_members) { zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry); zend_class_entry *old_scope = *scope; *scope = class_type; zend_hash_apply_with_argument(&class_type->default_properties, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC); + + if (!class_type->static_members) { + HashPosition pos; + zval **p; + + if (class_type->parent) { + zend_update_class_constants(class_type->parent TSRMLS_CC); + } + ALLOC_HASHTABLE(class_type->static_members); + zend_u_hash_init(class_type->static_members, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); + + zend_hash_internal_pointer_reset_ex(&class_type->default_static_members, &pos); + while (zend_hash_get_current_data_ex(&class_type->default_static_members, (void**)&p, &pos) == SUCCESS) { + char *str_index; + uint str_length; + ulong num_index; + zend_uchar utype; + zval **q; + + switch (zend_hash_get_current_key_ex(&class_type->default_static_members, &str_index, &str_length, &num_index, 0, &pos)) { + case HASH_KEY_IS_UNICODE: + utype = IS_UNICODE; + break; + case HASH_KEY_IS_BINARY: + utype = IS_BINARY; + break; + case HASH_KEY_IS_STRING: + default: + utype = IS_STRING; + break; + } + if ((*p)->is_ref && + class_type->parent && + zend_u_hash_find(&class_type->parent->default_static_members, utype, str_index, str_length, (void**)&q) == SUCCESS && + *p == *q && + zend_u_hash_find(class_type->parent->static_members, utype, str_index, str_length, (void**)&q) == SUCCESS) { + (*q)->refcount++; + (*q)->is_ref = 1; + zend_u_hash_add(class_type->static_members, utype, str_index, str_length, (void**)q, sizeof(zval*), NULL); + } else { + zval *q; + + ALLOC_ZVAL(q); + *q = **p; + INIT_PZVAL(q) + zval_copy_ctor(q); + zend_u_hash_add(class_type->static_members, utype, str_index, str_length, (void**)&q, sizeof(zval*), NULL); + } + zend_hash_move_forward_ex(&class_type->default_static_members, &pos); + } + } zend_hash_apply_with_argument(class_type->static_members, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC); + *scope = old_scope; class_type->constants_updated = 1; } @@ -2749,7 +2801,7 @@ ZEND_API int zend_u_declare_property_ex(zend_class_entry *ce, zend_uchar type, v access_type |= ZEND_ACC_PUBLIC; } if (access_type & ZEND_ACC_STATIC) { - target_symbol_table = ce->static_members; + target_symbol_table = &ce->default_static_members; } else { target_symbol_table = &ce->default_properties; } @@ -2914,6 +2966,73 @@ ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, char *name, int return zend_declare_property(ce, name, name_length, property, access_type TSRMLS_CC); } +ZEND_API int zend_declare_class_constant(zend_class_entry *ce, char *name, size_t name_length, zval *value TSRMLS_DC) +{ + return zend_hash_update(&ce->constants_table, name, name_length+1, &value, sizeof(zval *), NULL); +} + +ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, char *name, size_t name_length, long value TSRMLS_DC) +{ + zval *constant; + + if (ce->type & ZEND_INTERNAL_CLASS) { + constant = malloc(sizeof(zval)); + } else { + ALLOC_ZVAL(constant); + } + ZVAL_LONG(constant, value); + INIT_PZVAL(constant); + return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC); +} + +ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, char *name, size_t name_length, zend_bool value TSRMLS_DC) +{ + zval *constant; + + if (ce->type & ZEND_INTERNAL_CLASS) { + constant = malloc(sizeof(zval)); + } else { + ALLOC_ZVAL(constant); + } + ZVAL_BOOL(constant, value); + INIT_PZVAL(constant); + return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC); +} + +ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, char *name, size_t name_length, double value TSRMLS_DC) +{ + zval *constant; + + if (ce->type & ZEND_INTERNAL_CLASS) { + constant = malloc(sizeof(zval)); + } else { + ALLOC_ZVAL(constant); + } + ZVAL_DOUBLE(constant, value); + INIT_PZVAL(constant); + return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC); +} + +ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, char *name, size_t name_length, char *value, size_t value_length TSRMLS_DC) +{ + zval *constant; + + if (ce->type & ZEND_INTERNAL_CLASS) { + constant = malloc(sizeof(zval)); + ZVAL_STRINGL(constant, zend_strndup(value, value_length), value_length, 0); + } else { + ALLOC_ZVAL(constant); + ZVAL_STRINGL(constant, value, value_length, 1); + } + INIT_PZVAL(constant); + return zend_declare_class_constant(ce, name, name_length, constant TSRMLS_CC); +} + +ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, char *name, size_t name_length, char *value TSRMLS_DC) +{ + return zend_declare_class_constant_stringl(ce, name, name_length, value, strlen(value) TSRMLS_CC); +} + ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, char *name, int name_length, zval *value TSRMLS_DC) { zval property; @@ -3067,6 +3186,172 @@ ZEND_API void zend_update_property_unicodel(zend_class_entry *scope, zval *objec zend_update_property(scope, object, name, name_length, tmp TSRMLS_CC); } +ZEND_API int zend_update_static_property(zend_class_entry *scope, char *name, int name_length, zval *value TSRMLS_DC) +{ + zval **property; + zend_class_entry *old_scope = EG(scope); + + EG(scope) = scope; + property = zend_std_get_static_property(scope, IS_STRING, name, name_length, 0 TSRMLS_CC); + EG(scope) = old_scope; + if (!property) { + return FAILURE; + } else { + if (*property != value) { + if (PZVAL_IS_REF(*property)) { + zval_dtor(*property); + (*property)->type = value->type; + (*property)->value = value->value; + if (value->refcount > 0) { + zval_copy_ctor(*property); + } + } else { + zval *garbage = *property; + + value->refcount++; + if (PZVAL_IS_REF(value)) { + SEPARATE_ZVAL(&value); + } + *property = value; + zval_ptr_dtor(&garbage); + } + } + return SUCCESS; + } +} + +ZEND_API int zend_update_static_property_null(zend_class_entry *scope, char *name, int name_length TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_NULL(tmp); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_BOOL(tmp, value); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_long(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_LONG(tmp, value); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_double(zend_class_entry *scope, char *name, int name_length, double value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_DOUBLE(tmp, value); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_string(zend_class_entry *scope, char *name, int name_length, char *value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_STRING(tmp, value, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, char *name, int name_length, char *value, int value_len TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_STRINGL(tmp, value, value_len, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_ascii_string(zend_class_entry *scope, char *name, int name_length, char *value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_ASCII_STRING(tmp, value, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_ascii_stringl(zend_class_entry *scope, char *name, int name_length, char *value, int value_len TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_ASCII_STRINGL(tmp, value, value_len, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_rt_string(zend_class_entry *scope, char *name, int name_length, char *value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_RT_STRING(tmp, value, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_rt_stringl(zend_class_entry *scope, char *name, int name_length, char *value, int value_len TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_RT_STRINGL(tmp, value, value_len, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_unicode(zend_class_entry *scope, char *name, int name_length, UChar *value TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_UNICODE(tmp, value, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + +ZEND_API int zend_update_static_property_unicodel(zend_class_entry *scope, char *name, int name_length, UChar *value, int value_len TSRMLS_DC) +{ + zval *tmp; + + ALLOC_ZVAL(tmp); + tmp->is_ref = 0; + tmp->refcount = 0; + ZVAL_UNICODEL(tmp, value, value_len, 1); + return zend_update_static_property(scope, name, name_length, tmp TSRMLS_CC); +} + ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *name, int name_length, zend_bool silent TSRMLS_DC) { zval property, *value; @@ -3088,6 +3373,18 @@ ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *n return value; } +ZEND_API zval *zend_read_static_property(zend_class_entry *scope, char *name, int name_length, zend_bool silent TSRMLS_DC) +{ + zval **property; + zend_class_entry *old_scope = EG(scope); + + EG(scope) = scope; + property = zend_std_get_static_property(scope, IS_STRING, name, name_length, silent TSRMLS_CC); + EG(scope) = old_scope; + + return property?*property:NULL; +} + /* * Return the string type that all the passed in types should be converted to. * If none of the types are string types, IS_UNICODE or IS_STRING is returned, diff --git a/Zend/zend_API.h b/Zend/zend_API.h index f1190c5b23c..e265d56812d 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -220,6 +220,13 @@ ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, char *name, int ZEND_API int zend_u_declare_property(zend_class_entry *ce, zend_uchar type, void *name, int name_length, zval *property, int access_type TSRMLS_DC); ZEND_API int zend_u_declare_property_ex(zend_class_entry *ce, zend_uchar type, void *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC); +ZEND_API int zend_declare_class_constant(zend_class_entry *ce, char *name, size_t name_length, zval *value TSRMLS_DC); +ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, char *name, size_t name_length, long value TSRMLS_DC); +ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, char *name, size_t name_length, zend_bool value TSRMLS_DC); +ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, char *name, size_t name_length, double value TSRMLS_DC); +ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, char *name, size_t name_length, char *value, size_t value_length TSRMLS_DC); +ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, char *name, size_t name_length, char *value TSRMLS_DC); + ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC); ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, char *name, int name_length, zval *value TSRMLS_DC); ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, char *name, int name_length TSRMLS_DC); @@ -235,8 +242,24 @@ ZEND_API void zend_update_property_rt_stringl(zend_class_entry *scope, zval *obj ZEND_API void zend_update_property_unicode(zend_class_entry *scope, zval *object, char *name, int name_length, UChar *value TSRMLS_DC); ZEND_API void zend_update_property_unicodel(zend_class_entry *scope, zval *object, char *name, int name_length, UChar *value, int value_length TSRMLS_DC); +ZEND_API int zend_update_static_property(zend_class_entry *scope, char *name, int name_length, zval *value TSRMLS_DC); +ZEND_API int zend_update_static_property_null(zend_class_entry *scope, char *name, int name_length TSRMLS_DC); +ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC); +ZEND_API int zend_update_static_property_long(zend_class_entry *scope, char *name, int name_length, long value TSRMLS_DC); +ZEND_API int zend_update_static_property_double(zend_class_entry *scope, char *name, int name_length, double value TSRMLS_DC); +ZEND_API int zend_update_static_property_string(zend_class_entry *scope, char *name, int name_length, char *value TSRMLS_DC); +ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, char *name, int name_length, char *value, int value_length TSRMLS_DC); +ZEND_API int zend_update_static_property_ascii_string(zend_class_entry *scope, char *name, int name_length, char *value TSRMLS_DC); +ZEND_API int zend_update_static_property_ascii_stringl(zend_class_entry *scope, char *name, int name_length, char *value, int value_length TSRMLS_DC); +ZEND_API int zend_update_static_property_rt_string(zend_class_entry *scope, char *name, int name_length, char *value TSRMLS_DC); +ZEND_API int zend_update_static_property_rt_stringl(zend_class_entry *scope, char *name, int name_length, char *value, int value_length TSRMLS_DC); +ZEND_API int zend_update_static_property_unicode(zend_class_entry *scope, char *name, int name_length, UChar *value TSRMLS_DC); +ZEND_API int zend_update_static_property_unicodel(zend_class_entry *scope, char *name, int name_length, UChar *value, int value_length TSRMLS_DC); + ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *name, int name_length, zend_bool silent TSRMLS_DC); +ZEND_API zval *zend_read_static_property(zend_class_entry *scope, char *name, int name_length, zend_bool silent TSRMLS_DC); + ZEND_API zend_class_entry *zend_get_class_entry(zval *zobject TSRMLS_DC); ZEND_API int zend_get_object_classname(zval *object, char **class_name, zend_uint *class_name_len TSRMLS_DC); ZEND_API zend_uchar zend_get_unified_string_type(int num_args TSRMLS_DC, ...); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 38c22ea3388..0dd3be64e45 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -788,6 +788,7 @@ ZEND_FUNCTION(get_class_vars) } else { array_init(return_value); add_class_vars(*pce, &(*pce)->default_properties, return_value TSRMLS_CC); + zend_update_class_constants(*pce TSRMLS_CC); add_class_vars(*pce, (*pce)->static_members, return_value TSRMLS_CC); } } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0549b51ef53..2c078284c29 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2123,9 +2123,17 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro zend_u_mangle_property_name(&prot_name, &prot_name_length, utype, "*", 1, child_info->name, child_info->name_length, ce->type & ZEND_INTERNAL_CLASS); if (child_info->flags & ZEND_ACC_STATIC) { zval **prop; - if (zend_u_hash_find(parent_ce->static_members, utype, prot_name, prot_name_length+1, (void**)&prop) == SUCCESS) { + HashTable *ht; + + if (parent_ce->type != ce->type) { + /* User class extends internal class */ + ht = parent_ce->static_members; + } else { + ht = &parent_ce->default_static_members; + } + if (zend_u_hash_find(ht, utype, prot_name, prot_name_length+1, (void**)&prop) == SUCCESS) { zval **new_prop; - if (zend_u_hash_find(ce->static_members, utype, child_info->name, child_info->name_length+1, (void**)&new_prop) == SUCCESS) { + if (zend_u_hash_find(ht, utype, child_info->name, child_info->name_length+1, (void**)&new_prop) == SUCCESS) { if (Z_TYPE_PP(new_prop) != IS_NULL && Z_TYPE_PP(prop) != IS_NULL) { char *prop_name, *tmp; @@ -2135,8 +2143,8 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro } } (*prop)->refcount++; - zend_u_hash_update(ce->static_members, utype, child_info->name, child_info->name_length+1, (void**)prop, sizeof(zval*), NULL); - zend_u_hash_del(ce->static_members, utype, prot_name, prot_name_length+1); + zend_u_hash_update(&ce->default_static_members, utype, child_info->name, child_info->name_length+1, (void**)prop, sizeof(zval*), NULL); + zend_u_hash_del(&ce->default_static_members, utype, prot_name, prot_name_length+1); } } else { zend_u_hash_del(&ce->default_properties, utype, prot_name, prot_name_length+1); @@ -2222,7 +2230,13 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent /* Inherit properties */ zend_hash_merge(&ce->default_properties, &parent_ce->default_properties, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0); - zend_hash_merge(ce->static_members, parent_ce->static_members, (void (*)(void *)) inherit_static_prop, NULL, sizeof(zval *), 0); + if (parent_ce->type != ce->type) { + /* User class extends internal class */ + zend_update_class_constants(parent_ce TSRMLS_CC); + zend_hash_merge(&ce->default_static_members, parent_ce->static_members, (void (*)(void *)) inherit_static_prop, NULL, sizeof(zval *), 0); + } else { + zend_hash_merge(&ce->default_static_members, &parent_ce->default_static_members, (void (*)(void *)) inherit_static_prop, NULL, sizeof(zval *), 0); + } zend_hash_merge_ex(&ce->properties_info, &parent_ce->properties_info, (copy_ctor_func_t) (ce->type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal : zend_duplicate_property_info), sizeof(zend_property_info), (merge_checker_func_t) do_inherit_property_access_check, ce); zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0); @@ -2360,7 +2374,7 @@ ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *c zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->default_properties); zend_hash_destroy(&ce->properties_info); - zend_hash_destroy(ce->static_members); + zend_hash_destroy(&ce->default_static_members); zend_hash_destroy(&ce->constants_table); return NULL; } @@ -4110,17 +4124,12 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify zend_u_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, UG(unicode), 0); zend_u_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, UG(unicode), 0); - - if (persistent_hashes) { - ce->static_members = (HashTable *) malloc(sizeof(HashTable)); - } else { - ALLOC_HASHTABLE(ce->static_members); - } - - zend_u_hash_init_ex(ce->static_members, 0, NULL, zval_ptr_dtor_func, persistent_hashes, UG(unicode), 0); + zend_u_hash_init_ex(&ce->default_static_members, 0, NULL, zval_ptr_dtor_func, persistent_hashes, UG(unicode), 0); zend_u_hash_init_ex(&ce->constants_table, 0, NULL, zval_ptr_dtor_func, persistent_hashes, UG(unicode), 0); zend_u_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, UG(unicode), 0); + ce->static_members = (ce->type == ZEND_INTERNAL_CLASS) ? NULL : &ce->default_static_members; + if (nullify_handlers) { ce->constructor = NULL; ce->destructor = NULL; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 6a14c72fc56..bf8fec3c20c 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -838,7 +838,9 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, zend_uchar ty return NULL; } - zend_u_hash_quick_find(tmp_ce->static_members, type, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval); + zend_update_class_constants(tmp_ce TSRMLS_CC); + + zend_u_hash_quick_find(tmp_ce->static_members, UG(unicode)?IS_UNICODE:IS_STRING, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval); if (!retval) { if (silent) { @@ -848,7 +850,6 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, zend_uchar ty } } - zval_update_constant(retval, (void *) 1 TSRMLS_CC); return retval; } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index b2e7a53bf3c..ff46517a747 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -141,11 +141,17 @@ ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC) ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC) { + if ((*pce)->static_members) { + if ((*pce)->static_members != &(*pce)->default_static_members) { + zend_hash_destroy((*pce)->static_members); + FREE_HASHTABLE((*pce)->static_members); + } + (*pce)->static_members = NULL; + } if ((*pce)->type == ZEND_USER_CLASS) { /* Clean all parts that can contain run-time data */ /* Note that only run-time accessed data need to be cleaned up, pre-defined data can not contain objects and thus are not probelmatic */ - zend_hash_clean((*pce)->static_members); zend_hash_apply(&(*pce)->function_table, (apply_func_t) zend_cleanup_function_data TSRMLS_CC); } return 0; @@ -162,10 +168,9 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) case ZEND_USER_CLASS: zend_hash_destroy(&ce->default_properties); zend_hash_destroy(&ce->properties_info); - zend_hash_destroy(ce->static_members); + zend_hash_destroy(&ce->default_static_members); efree(ce->name); zend_hash_destroy(&ce->function_table); - FREE_HASHTABLE(ce->static_members); zend_hash_destroy(&ce->constants_table); if (ce->num_interfaces > 0 && ce->interfaces) { efree(ce->interfaces); @@ -178,10 +183,9 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) case ZEND_INTERNAL_CLASS: zend_hash_destroy(&ce->default_properties); zend_hash_destroy(&ce->properties_info); - zend_hash_destroy(ce->static_members); + zend_hash_destroy(&ce->default_static_members); free(ce->name); zend_hash_destroy(&ce->function_table); - free(ce->static_members); zend_hash_destroy(&ce->constants_table); if (ce->num_interfaces > 0) { free(ce->interfaces); diff --git a/Zend/zend_reflection_api.c b/Zend/zend_reflection_api.c index faa9fcbf6a0..970dceff73e 100644 --- a/Zend/zend_reflection_api.c +++ b/Zend/zend_reflection_api.c @@ -3566,6 +3566,7 @@ ZEND_METHOD(reflection_property, setValue) return; } } + zend_update_class_constants(intern->ce TSRMLS_CC); prop_table = intern->ce->static_members; } else { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) { diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index faa9fcbf6a0..970dceff73e 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3566,6 +3566,7 @@ ZEND_METHOD(reflection_property, setValue) return; } } + zend_update_class_constants(intern->ce TSRMLS_CC); prop_table = intern->ce->static_members; } else { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) {