Beware of foreach Loop in PHP

  • Avinash
  • 2
  • Aug 07, 2014
  • Tips & Tricks

You must be surprised/scared after reading title of this article. But I would say yes, foreach loop can create very confusing bug in your program/application if it has not been used in proper way. I will demonstrate the same in this article.

P.S.: This article does to mean to say foreach loop always creates problem, but it would create problem if not used in proper manner.

php foreach bug

Let’s move to practical stuff to see this problem in action, please have a look at below code block:

$arr = [1, 2, 3]; // PHP 5.4 Only echo implode(',', $arr), "\n"; foreach ($arr as $value) {} echo implode(',', $arr), "\n"; foreach ($arr as $value) {} echo implode(',', $arr), "\n";
$arr = [1, 2, 3]; // PHP 5.4 Only
echo implode(',', $arr), "\n";

foreach ($arr as $value) {}    
echo implode(',', $arr), "\n";

foreach ($arr as $value) {}    
echo implode(',', $arr), "\n";

Above code will give you following output.

1,2,3 1,2,3 1,2,3
1,2,3
1,2,3
1,2,3

Upto now foreach seems fine and nothing unusual happens. But now let’s see some unusal things with foreach now, writing same code again with just (very)minor change in it.

$arr = [1, 2, 3]; // PHP 5.4 Only echo implode(',', $arr), "\n"; foreach ($arr as &$value) {} // Reference echo implode(',', $arr), "\n"; foreach ($arr as $value) {} // Value echo implode(',', $arr), "\n";
$arr = [1, 2, 3]; // PHP 5.4 Only
echo implode(',', $arr), "\n";

foreach ($arr as &$value) {}  // Reference
echo implode(',', $arr), "\n";

foreach ($arr as $value) {}   // Value
echo implode(',', $arr), "\n";

You must have guessed that it will give you same output but infact it is not true. It will give you following output.

1,2,3 1,2,3 1,2,2
1,2,3
1,2,3
1,2,2

Now you must be surprised and having question of WHY that happens. Let’s go through each step of above code which shows the real case.

Step 1:

Here array is declared and echoed by imploding array elements. So here nothing changed to array.

Step 2:

Here we have foreach loop, you must have noted & in front of $value, which means we are passing each element of $arr with reference instead of just value. So for each iteration we are assigning reference to array element. Once this iteration is completed $value will have reference to last element of $arr which is $arr[2] and value is 3.

Step 3:

When this foreach starts $value holds 3 which is reference to $arr[2]. This loop will create a confusing issue specially when accessing $value by value instead of reference. We will go through step of step each iteration.

  1. 1st Pass: This will copies $arr[0] (i.e., “1”) into $value which is a reference to $arr[2], so $arr[2] now equals 1. So $arr now contains [1, 2, 1].
  2. 2nd Pass: This will copies $arr[1] (i.e., “2”) into $value which is a reference to $arr[2], so $arr[2] now equals 2. So $arr now contains [1, 2, 2].
  3. 3rd Pass: This will copies $arr[2] (which now equals “2”) into $value which is a reference to $arr[2], so $arr[2] still equals 2. So $arr now contains [1, 2, 2].

Now you should have clear idea on why does that wierd thing happen with foreach loop. This bug was already reported back in 2004 (https://bugs.php.net/bug.php?id=29992), but this has not been considered as BUG.

Solution

So what can be the resolution for this issue? Its very simple, just remove reference which is assigned to $value, just have a look at below code block.

$arr = [1, 2, 3]; // PHP 5.4 Only echo implode(',', $arr), "\n"; foreach ($arr as &$value) {} // Reference echo implode(',', $arr), "\n"; unset($value); // This will remove reference to last element foreach ($arr as $value) {} // Value echo implode(',', $arr), "\n"; /* Output */ 1,2,3 1,2,3 1,2,3
$arr = [1, 2, 3]; // PHP 5.4 Only
echo implode(',', $arr), "\n";

foreach ($arr as &$value) {}  // Reference
echo implode(',', $arr), "\n";

unset($value); // This will remove reference to last element

foreach ($arr as $value) {}   // Value
echo implode(',', $arr), "\n";

/* Output */

1,2,3
1,2,3
1,2,3

So this was the weird stuff I have found with foreach loop in PHP. Look forward to your comments on this.

Related Posts

Written by Avinash

Avinash Zala is leading various projects which deals with the various technology involved with the web. A combination of perfect technical and management skills. Avinash would like to chat with you and convert your imagination into the working system. You can get in touch with him on Facebook and Twitter.

View all posts by:

  • http://www.xpertdeveloper.com/ Avinash

    more worst case

    $arr = [1, 2, 3]; // PHP 5.4 Only $arr2 = [4, 5, 6]; echo implode(',', $arr), "n"; foreach ($arr as &$value) {} // Reference echo implode(',', $arr), "n"; foreach ($arr2 as $value) {} // Value echo implode(',', $arr), "n"; // Output: 1,2,3 1,2,3 1,2,6
    $arr = [1, 2, 3]; // PHP 5.4 Only
    $arr2 = [4, 5, 6];

    echo implode(',', $arr), "n";

    foreach ($arr as &$value) {} // Reference
    echo implode(',', $arr), "n";

    foreach ($arr2 as $value) {} // Value
    echo implode(',', $arr), "n";
    // Output:
    1,2,3
    1,2,3
    1,2,6
  • http://www.techwila.com/ Divy Singh Rathore

    But In scope of foreach loop your your not printing the $arr and not even replacing values of $arr. So it should not because of foreach.