note 65971 added to function.dom-domdocument-getelementsbytagname

From: Date: Thu, 11 May 2006 05:39:33 +0000
Subject: note 65971 added to function.dom-domdocument-getelementsbytagname
Groups: php.notes 
Request: Send a blank email to php-notes+get-111107@lists.php.net to get a copy of this message
Regarding the possibility of an infinite loop when altering the document tree while iterating: We can see what really happens by investigating the keys of the NodeList. They are numeric indices starting at 0. Suppose we call getElementsByTagName('*') and receive a NodeList like this: $nodes[0] = <root> $nodes[1] = <first> Iteration via foreach: foreach ($nodes as $node) can be re-written like this: for ($i=0; $i < count($nodes); $i++) On the first iteration, $nodes[$i] refers to <root> If we happen to insert a new node immediately before the current node: insertBefore(<infinite>, $nodes[$i]) $nodes[$i] stops referring to <root> and now refers to <infinite>; the new element takes the place of the old one (in the indexed ordering) and all subsequent nodes shift up by one. On the next iteration, $i increments by one, so $nodes[$i] refers to <root> and the process repeats. Here is PHP code to demonstrate: <?php $dom = new DOMDocument(); $rootNode = $dom->createElement('root'); $dom->appendChild($rootNode); $firstNode = $dom->createElement('first'); $rootNode->appendChild($firstNode); $allnodes = $dom->getElementsByTagName('*'); for ($i=0; ; $i++) { $node = $allnodes->item($i); echo "before: {$node->nodeName} "; $newNode = $dom->createElement('infinite'); $node->parentNode->insertBefore($newNode, $node); $node = $allnodes->item($i); echo "after: {$node->nodeName} <br/>"; if ($i > 4) break; # break arbitrarily so we can see the output } ?> Thus, if you are able to know, within the scope of the loop, that a node has been inserted, and use for instead of foreach, you can explicitly increment the iterator once more and "skip" the node that you already visited (if that's what you want; at any rate, that's what I wanted). "Can" doesn't mean "should," of course; this sounds like a kludge (violating the sanctity of the iterator), but use your best judgment. ---- Server IP: 66.163.161.117 Probable Submitter: 71.240.241.169 ---- X-Spam-Status: No, hits=3.1 required=5.0 tests=DATE_MISSING,FROM_NO_LOWER autolearn=no version=2.64 ---- Manual Page -- http://www.php.net/manual/en/function.dom-domdocument-getelementsbytagname.php Edit -- http://master.php.net/note/edit/65971 Del: integrated -- http://master.php.net/note/delete/65971/integrated Del: useless -- http://master.php.net/note/delete/65971/useless Del: bad code -- http://master.php.net/note/delete/65971/bad+code Del: spam -- http://master.php.net/note/delete/65971/spam Del: non-english -- http://master.php.net/note/delete/65971/non-english Del: in docs -- http://master.php.net/note/delete/65971/in+docs Del: other reasons-- http://master.php.net/note/delete/65971 Reject -- http://master.php.net/note/reject/65971 Search -- http://master.php.net/manage/user-notes.php

« previous php.notes (#111107) next »