diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index 8c6b3023cca..e292728de27 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -132,7 +132,7 @@ static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) /* Only dtd named node maps, i.e. the ones based on a libxml hash table or attribute collections, * are keyed by the name because in that case the name is unique. */ if (!objmap->ht && objmap->nodetype != XML_ATTRIBUTE_NODE) { - ZVAL_LONG(key, iter->index); + ZVAL_LONG(key, iterator->index); } else { dom_object *intern = Z_DOMOBJ_P(&iterator->curobj); @@ -179,6 +179,8 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ return; } + iterator->index++; + dom_object *intern = Z_DOMOBJ_P(&iterator->curobj); dom_nnodemap_object *objmap = php_dom_iterator_get_nnmap(iterator); @@ -203,7 +205,7 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ php_dom_mark_cache_tag_up_to_date_from_doc_ref(&iterator->cache_tag, intern->document); curnode = dom_fetch_first_iteration_item(objmap); zend_ulong index = 0; - while (curnode != NULL && index++ < iter->index) { + while (curnode != NULL && index++ < iterator->index) { curnode = curnode->next; } } else { @@ -224,15 +226,15 @@ static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ previndex = 0; curnode = php_dom_first_child_of_container_node(basenode); } else { - previndex = iter->index - 1; + previndex = iterator->index - 1; curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; } curnode = dom_get_elements_by_tag_name_ns_raw( - basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iter->index); + basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iterator->index); } } } else { - curnode = php_dom_libxml_hash_iter(objmap, iter->index); + curnode = php_dom_libxml_hash_iter(objmap, iterator->index); } } diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 1c21d8a64e1..438857305db 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -98,6 +98,9 @@ typedef struct { zend_object_iterator intern; zval curobj; HashPosition pos; + /* intern->index is only updated for FE_* opcodes, not for e.g. unpacking, + * yet we need to track the position of the node relative to the start. */ + zend_ulong index; php_libxml_cache_tag cache_tag; } php_dom_iterator; diff --git a/ext/dom/tests/modern/common/unpacking_foreach.phpt b/ext/dom/tests/modern/common/unpacking_foreach.phpt new file mode 100644 index 00000000000..b2bb301ccdc --- /dev/null +++ b/ext/dom/tests/modern/common/unpacking_foreach.phpt @@ -0,0 +1,30 @@ +--TEST-- +unpacking vs foreach in new DOM +--EXTENSIONS-- +dom +--FILE-- +Hi
hi
", + options: LIBXML_NOERROR, +); + +foreach ($html->body->childNodes as $node) { + echo $node->localName, "\n"; +} + +echo "---\n"; + +foreach ([...$html->body->childNodes] as $node) { + echo $node->localName, "\n"; +} + +?> +--EXPECT-- +h1 +p +--- +h1 +p diff --git a/ext/dom/tests/unpack_foreach_behaviour.phpt b/ext/dom/tests/unpack_foreach_behaviour.phpt new file mode 100644 index 00000000000..42fe896d9f7 --- /dev/null +++ b/ext/dom/tests/unpack_foreach_behaviour.phpt @@ -0,0 +1,31 @@ +--TEST-- +Unpacking vs foreach behaviour +--EXTENSIONS-- +dom +--FILE-- +loadXML('