If a NodeVisitor returns an array of nodes to merge these will no longer be traversed by all other visitors. That "feature" turned out to be a real pain in the ass on some occasions ;)
a) ->traverseNode() now operates on a clone of the node, otherwise the original node will be modified too
b) before nodes were passed to the following visitor unchanged, even though they were already changed in the tree
Instead manually implement IteratorAggregate and define the required magic methods. The reasoning behind this is:
a) Extending ArrayObject is always risky, because a lot of magic which is known to be buggy is involved
b) This allows to lateron change the implementation for the nodes altogether, for example it could be changed to using real public fields instead of a $subNodes array.