diff options
-rw-r--r-- | Zend/tests/bug48667_1.phpt | 2 | ||||
-rw-r--r-- | Zend/zend_inheritance.c | 30 | ||||
-rw-r--r-- | Zend/zend_interfaces.c | 136 |
3 files changed, 61 insertions, 107 deletions
diff --git a/Zend/tests/bug48667_1.phpt b/Zend/tests/bug48667_1.phpt index 2d94aed2bf..b2e4d28769 100644 --- a/Zend/tests/bug48667_1.phpt +++ b/Zend/tests/bug48667_1.phpt @@ -7,4 +7,4 @@ abstract class A implements Iterator, IteratorAggregate { } ?> --EXPECTF-- -Fatal error: Class A cannot implement both IteratorAggregate and Iterator at the same time in %s on line %d +Fatal error: Class A cannot implement both Iterator and IteratorAggregate at the same time in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index f15c325d67..a031207b85 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -141,10 +141,6 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ if (EXPECTED(!ce->get_iterator)) { ce->get_iterator = parent->get_iterator; } - if (parent->iterator_funcs_ptr) { - /* Must be initialized through iface->interface_gets_implemented() */ - ZEND_ASSERT(ce->iterator_funcs_ptr); - } if (EXPECTED(!ce->__get)) { ce->__get = parent->__get; } @@ -1185,19 +1181,6 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par ce->parent = parent_ce; ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT; - /* Inherit interfaces */ - if (parent_ce->num_interfaces) { - if (!ce->num_interfaces) { - zend_do_inherit_interfaces(ce, parent_ce); - } else { - uint32_t i; - - for (i = 0; i < parent_ce->num_interfaces; i++) { - do_implement_interface(ce, parent_ce->interfaces[i]); - } - } - } - /* Inherit properties */ if (parent_ce->default_properties_count) { zval *src, *dst, *end; @@ -1378,6 +1361,10 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par do_inherit_parent_constructor(ce); if (ce->type == ZEND_INTERNAL_CLASS) { + if (parent_ce->num_interfaces) { + zend_do_inherit_interfaces(ce, parent_ce); + } + if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } @@ -1533,7 +1520,9 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry ce->interfaces = interfaces; ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES; - i = num_parent_interfaces; + for (i = 0; i < num_parent_interfaces; i++) { + do_implement_interface(ce, ce->interfaces[i]); + } /* Note that new interfaces can be added during this loop due to interface inheritance. * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */ for (; i < num_interfaces; i++) { @@ -2459,6 +2448,8 @@ ZEND_API int zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_nam } if (interfaces) { zend_do_implement_interfaces(ce, interfaces); + } else if (parent && parent->num_interfaces) { + zend_do_inherit_interfaces(ce, parent); } if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { zend_verify_abstract_class(ce); @@ -2542,6 +2533,9 @@ zend_bool zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, } } zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS); + if (parent_ce && parent_ce->num_interfaces) { + zend_do_inherit_interfaces(ce, parent_ce); + } zend_build_properties_info_table(ce); if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { zend_verify_abstract_class(ce); diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index fe403b3d7a..cf8b24d76a 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -313,59 +313,39 @@ static int zend_implement_traversable(zend_class_entry *interface, zend_class_en /* {{{ zend_implement_aggregate */ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entry *class_type) { - uint32_t i; - int t = -1; - zend_class_iterator_funcs *funcs_ptr; + if (zend_class_implements_interface(class_type, zend_ce_iterator)) { + zend_error_noreturn(E_ERROR, + "Class %s cannot implement both Iterator and IteratorAggregate at the same time", + ZSTR_VAL(class_type->name)); + } - if (class_type->get_iterator) { - if (class_type->type == ZEND_INTERNAL_CLASS) { - /* inheritance ensures the class has necessary userland methods */ + zend_function *zf = zend_hash_str_find_ptr( + &class_type->function_table, "getiterator", sizeof("getiterator") - 1); + if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_new_iterator) { + /* get_iterator was explicitly assigned for an internal class. */ + if (!class_type->parent || class_type->parent->get_iterator != class_type->get_iterator) { + ZEND_ASSERT(class_type->type == ZEND_INTERNAL_CLASS); return SUCCESS; - } else if (class_type->get_iterator != zend_user_it_get_new_iterator) { - /* c-level get_iterator cannot be changed (exception being only Traversable is implemented) */ - if (class_type->num_interfaces) { - ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_RESOLVED_INTERFACES); - for (i = 0; i < class_type->num_interfaces; i++) { - if (class_type->interfaces[i] == zend_ce_iterator) { - zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time", - ZSTR_VAL(class_type->name), - ZSTR_VAL(interface->name), - ZSTR_VAL(zend_ce_iterator->name)); - return FAILURE; - } - if (class_type->interfaces[i] == zend_ce_traversable) { - t = i; - } - } - } - if (t == -1) { - return FAILURE; - } } - } - if (class_type->parent - && (class_type->parent->ce_flags & ZEND_ACC_REUSE_GET_ITERATOR)) { - class_type->get_iterator = class_type->parent->get_iterator; - class_type->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR; - } else { - class_type->get_iterator = zend_user_it_get_new_iterator; - } - funcs_ptr = class_type->iterator_funcs_ptr; - if (class_type->type == ZEND_INTERNAL_CLASS) { - if (!funcs_ptr) { - funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); - class_type->iterator_funcs_ptr = funcs_ptr; - } - funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&class_type->function_table, "getiterator", sizeof("getiterator") - 1); - } else { - if (!funcs_ptr) { - funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); - class_type->iterator_funcs_ptr = funcs_ptr; - memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); - } else { - funcs_ptr->zf_new_iterator = NULL; + + /* The getIterator() method has not been overwritten, use inherited get_iterator(). */ + if (zf->common.scope != class_type) { + return SUCCESS; } + + /* getIterator() has been overwritten, switch to zend_user_it_get_new_iterator. */ } + + ZEND_ASSERT(!class_type->iterator_funcs_ptr && "Iterator funcs already set?"); + zend_class_iterator_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS + ? pemalloc(sizeof(zend_class_iterator_funcs), 1) + : zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); + class_type->get_iterator = zend_user_it_get_new_iterator; + class_type->iterator_funcs_ptr = funcs_ptr; + + memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); + funcs_ptr->zf_new_iterator = zf; + return SUCCESS; } /* }}} */ @@ -373,55 +353,35 @@ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entr /* {{{ zend_implement_iterator */ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type) { - zend_class_iterator_funcs *funcs_ptr; + if (zend_class_implements_interface(class_type, zend_ce_aggregate)) { + zend_error_noreturn(E_ERROR, + "Class %s cannot implement both Iterator and IteratorAggregate at the same time", + ZSTR_VAL(class_type->name)); + } if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) { - if (class_type->type == ZEND_INTERNAL_CLASS) { - /* inheritance ensures the class has the necessary userland methods */ + if (!class_type->parent || class_type->parent->get_iterator != class_type->get_iterator) { + /* get_iterator was explicitly assigned for an internal class. */ + ZEND_ASSERT(class_type->type == ZEND_INTERNAL_CLASS); return SUCCESS; - } else { - /* c-level get_iterator cannot be changed */ - if (class_type->get_iterator == zend_user_it_get_new_iterator) { - zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time", - ZSTR_VAL(class_type->name), - ZSTR_VAL(interface->name), - ZSTR_VAL(zend_ce_aggregate->name)); - } - return FAILURE; } + /* Otherwise get_iterator was inherited from the parent by default. */ } - if (class_type->parent - && (class_type->parent->ce_flags & ZEND_ACC_REUSE_GET_ITERATOR)) { - class_type->get_iterator = class_type->parent->get_iterator; + + if (class_type->parent && (class_type->parent->ce_flags & ZEND_ACC_REUSE_GET_ITERATOR)) { + /* Keep the inherited get_iterator handler. */ class_type->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR; } else { class_type->get_iterator = zend_user_it_get_iterator; } - funcs_ptr = class_type->iterator_funcs_ptr; - if (class_type->type == ZEND_INTERNAL_CLASS) { - if (!funcs_ptr) { - funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); - class_type->iterator_funcs_ptr = funcs_ptr; - } else { - funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); - funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); - funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); - funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); - funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); - } - } else { - if (!funcs_ptr) { - funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); - class_type->iterator_funcs_ptr = funcs_ptr; - memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); - } else { - funcs_ptr->zf_valid = NULL; - funcs_ptr->zf_current = NULL; - funcs_ptr->zf_key = NULL; - funcs_ptr->zf_next = NULL; - funcs_ptr->zf_rewind = NULL; - } - } + + ZEND_ASSERT(!class_type->iterator_funcs_ptr && "Iterator funcs already set?"); + zend_class_iterator_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS + ? pemalloc(sizeof(zend_class_iterator_funcs), 1) + : zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); + memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); + class_type->iterator_funcs_ptr = funcs_ptr; + return SUCCESS; } /* }}} */ |