Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /share/CACHEDEV1_DATA/Web/www/libraries/UBBcode/text_parser.class.php on line 228

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /share/CACHEDEV1_DATA/Web/www/libraries/UBBcode/text_parser.class.php on line 228
Forcing foreach to loop over an array reference

Comments Blog About Development Research Sites

Forcing foreach to loop over an array reference

Oct 11, 2009
One of the primary causes for loops in PHP is manipulating a dataset you are looping over. A foreach on an array that adds entries to itself is a sure way to break any server, at least till the max_execution_time limit is reached.

In command-line PHP this is even more dangerous, since by default that does not have a max_execution_time limit - potentially a command line PHP script stuck in an infinite loop will continue to run untill its memory limit is reached. Overall, not a good thing. For that reason it's pretty handy that foreach loops seem to work on a copy of the actual array, which means they are less likely to cause infinite loops. Consider for example the following pseudo-code:
Code (php) (nieuw venster):
1
2
3
4
5
6
7
8
9
$array = array(1, 2, 3, 4, 5);
foreach (
$array as $index => $value)
  removeIndex ($index + 1);

function
removeIndex ($index) {
  global $array;
  echo
$index;
  unset($array[$index]);
}

The above code will output '12345' - so even though each even entry is removed from the global $array variable, it will still loop over those entries! This presents us with a bit of a problem if we want to remove certain entries from a result set.

Luckily, there is a simple way to force the foreach to loop over the actual, current array instead of a copy:
Code (php) (nieuw venster):
1
2
3
4
5
6
7
8
9
$array = array(1, 2, 3, 4, 5);
foreach (
$array as $index => & $value)
  removeIndex ($index + 1);

function
removeIndex ($index) {
  global $array;
  echo
$index;
  unset($array[$index]);
}

Notice the change? Don't strain your eyes, it is indeed a small one: instead of retrieving a copy of the indexed value, we retrieve a reference to that value in the foreach loop, using the '&' character. Now suddenly our output changes to '135'! Thus, by referencing the array values (and not even using them!) we ensure the foreach loops over the actual array, not just a copy!

In my opinion this behaviour is somewhat ambiguous, or unclear at best. It is probably documented somewhere, but not something I would expect to find or search for. It is easily explained if you understand the underlying mechanics of array manipulations of the kind we attempt here, and in most cases one need not even worry about removing array entries like this anyway - there exists an array_filter method for that very purpose. Still, it is an anomaly worth keeping in mind when dynamically removing entries from an array manually.

FragFrog out!

New comment

Your name:
Comment: