]> granicus.if.org Git - php/commitdiff
- MFH Fix issue with interfaces being inherited multiple times
authorMarcus Boerger <helly@php.net>
Wed, 7 Jun 2006 09:21:06 +0000 (09:21 +0000)
committerMarcus Boerger <helly@php.net>
Wed, 7 Jun 2006 09:21:06 +0000 (09:21 +0000)
Zend/zend_API.c
Zend/zend_compile.c
Zend/zend_vm_def.h

index b32b9eb47d72a68d9e2d5ead885562197148c040..31faa25e7a4010e3cbed1138e6bf125006f25ca8 100644 (file)
@@ -1970,24 +1970,14 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla
 ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...)
 {
        zend_class_entry *interface_entry;
-       int ce_num = class_entry->num_interfaces, impl_num;
        va_list interface_list;
        va_start(interface_list, num_interfaces);
 
-       if (class_entry->type & ZEND_INTERNAL_CLASS) {
-               class_entry->interfaces = realloc(class_entry->interfaces, sizeof(zend_class_entry*) * (class_entry->num_interfaces+num_interfaces));
-       } else {
-               class_entry->interfaces = erealloc(class_entry->interfaces, sizeof(zend_class_entry*) * (class_entry->num_interfaces+num_interfaces));
-       }
-
        while (num_interfaces--) {
                interface_entry = va_arg(interface_list, zend_class_entry *);
-               class_entry->interfaces[class_entry->num_interfaces++] = interface_entry;
-       }
-       impl_num = class_entry->num_interfaces;
-       while(ce_num < impl_num) {
-               zend_do_implement_interface(class_entry, class_entry->interfaces[ce_num++] TSRMLS_CC);
+               zend_do_implement_interface(class_entry, interface_entry TSRMLS_CC);
        }
+       
        va_end(interface_list);
 }
 
index ce64719f13d35490223632e2a5b7c2886ec151e5..117e5e3d7f32302d8536f84ece916992914867ef 100644 (file)
@@ -2247,11 +2247,38 @@ static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zva
 
 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC)
 {
-       zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
-       zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
-
-       do_implement_interface(ce, iface TSRMLS_CC);
-       zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
+       zend_uint i, ignore = 0;
+       zend_uint current_iface_num = ce->num_interfaces;
+       zend_uint parent_iface_num  = ce->parent ? ce->parent->num_interfaces : 0;
+
+       for (i = 0; i < ce->num_interfaces; i++) {
+               if (ce->interfaces[i] == NULL) {
+                       memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
+                       i--;
+               } else if (ce->interfaces[i] == iface) {
+                       if (i < parent_iface_num) {
+                               ignore = 1;
+                       } else {
+                               zend_error(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name, iface->name);
+                       }
+               }
+       }
+       if (!ignore) {
+               if (ce->num_interfaces >= current_iface_num) {
+                       if (ce->type == ZEND_INTERNAL_CLASS) {
+                               ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
+                       } else {
+                               ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
+                       }
+               }
+               ce->interfaces[ce->num_interfaces++] = iface;
+       
+               zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
+               zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
+       
+               do_implement_interface(ce, iface TSRMLS_CC);
+               zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
+       }
 }
 
 
@@ -2812,11 +2839,6 @@ void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRML
 
        ce->line_end = zend_get_compiled_lineno(TSRMLS_C);
 
-       /* Inherit interfaces */
-       if (ce->num_interfaces > 0) {
-               ce->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*ce->num_interfaces);
-               memset(ce->interfaces, 0, sizeof(zend_class_entry *)*ce->num_interfaces);
-       }
        if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
                && ((parent_token->op_type != IS_UNUSED) || (ce->num_interfaces > 0))) {
                zend_verify_abstract_class(ce TSRMLS_CC);
@@ -2824,6 +2846,12 @@ void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRML
                        do_verify_abstract_class(TSRMLS_C);
                }
        }
+       /* Inherit interfaces; reset number to zero, we need it for above check and
+        * will restore it during actual implementation. */
+       if (ce->num_interfaces > 0) {
+               ce->interfaces = NULL;
+               ce->num_interfaces = 0;
+       }
        CG(active_class_entry) = NULL;
 }
 
index 5295320de93338ce0ae3243ec9a483bac3388a76..fe07011bf0f0bd2bda0df39cb239353e06f115dd 100644 (file)
@@ -3627,8 +3627,6 @@ ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, ANY)
                zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name);
        }
 
-       ce->interfaces[opline->extended_value] = iface;
-
        zend_do_implement_interface(ce, iface TSRMLS_CC);
 
        ZEND_VM_NEXT_OPCODE();