summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/bug48667_1.phpt2
-rw-r--r--Zend/zend_inheritance.c30
-rw-r--r--Zend/zend_interfaces.c136
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;
}
/* }}} */