SPL problem

$xmlString = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<text>
	<mod id = "id 0" name="name a">
		<item id="id 1"/>
		<item id="id 2"/>
	</mod>
	<mod id = "id 3"  name = "name b">
		<item id="id 4"/>
		<item id="id 5"/>
	</mod>
	<mod id = "id 6" name="name c">
		<item id="id 7"/>
		<item id="id 8"/>
	</mod>
</text>

XML;

// function to apply the 'fn' to all the elements
// question1: do I really need to write such a function? I did search but failed to find one, does PHP already have one?
function for_each(Traversable $it, $fn) {
	foreach($it as $item) {
		if(call_user_func_array($fn, array($item)) === false) {
			break;
		}
	}
}

$it = new SimpleXMLIterator($xmlString);

function callback($a) {
	$a['id'] = 'xxxxxxx'; // just modify every 'id' to 'xxxxxxx'
}

for_each(new RecursiveIteratorIterator($it, 1), 'callback');

// question 2: after the loop, only three 'id' are modified, why ?
var_dump($it->asXML());


please see the comments,
Thanks in advance.

Hi aj3423, welcome to Sitepoint.

First, may I ask which version of PHP you’re using? I can only reproduce your described behaviour (only 3 ids changed) on versions 5.2.4 and below. PHP 5.2.5 included a couple of changes to the RecursiveIteratorIterator which fix your issue so, using that version or newer, the code will do what you want it to do.

As for your for_each() function, there is a built-in function which does similar to what you want (but not the same!): iterator_apply(). You would use it like:


function callback($iterator) {
    $current = $iterator->current();
    $current['id'] = 'xxxxxxx';
    return TRUE;
}

$rit = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);
iterator_apply($rit, 'callback', array($rit));

var_dump($it->asXML());

Any questions, do feel free to ask here. (:

Thanks you, the iterator_apply is exactly what I want, it is much multipurpose than the for_each().
after I upgrade PHP from 5.2.0 to 5.2.14, all the ‘id’ are modified to ‘xxxxxx’, it seems to be a bug of previous PHP ?