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;
}
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;
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;
}
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++) {
}
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);
}
}
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);
/* {{{ 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;
}
/* }}} */
/* {{{ 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;
}
/* }}} */