php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #60450 Looping in a copy of an array using foreach by-reference change original array
Submitted: 2011-12-06 10:05 UTC Modified: 2011-12-06 10:59 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: developer at elementica dot com Assigned:
Status: Not a bug Package: Arrays related
PHP Version: 5.3.8 OS: Linux, Windows
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: developer at elementica dot com
New email:
PHP Version: OS:

 

 [2011-12-06 10:05 UTC] developer at elementica dot com
Description:
------------
On a standard installation of PHP 5.3.x on many OSs (including Linux and Windows) we:
- set an array with at least two elements
- loop it using foreach by-reference changing each element
- create a copy of the array in another one using the "=" assignment
- loop on the copy as before
- we find the original array changed (usually or always: last element)

Example code given.

Documentation says "Array assignment always involves value copying. Use the reference operator to copy an array by reference." 

(http://php.net/manual/en/language.types.array.php).

It seems a problem of "foreach" used with the "by-reference" syntax.

Could be related to https://bugs.php.net/bug.php?id=8130 (subject appears to be the same, but here we have a foreach problem, while nothing is stated in #8130 about it).

Test script:
---------------
$array1 = array(0 => 'zero', 1 => 'one');
foreach ($array1 as &$elem) { $elem .= ' (1)'; }; // NOTE: if we use $array1[0] .= ' (1)'; $array1[1] .= ' (1)'; no problem arises
$array2 = $array1;
foreach ($array2 as &$elem) { $elem .= ' (2)'; }; // NOTE: if we use $array2[0] .= ' (1)'; $array2[1] .= ' (1)'; the problem is still here, so first foreach seems to be the point
print_r ($array1);
// BUG! EXPECTED: array(0 => 'zero (1)', 1 => 'one (1)'), OUTPUT: array(0 => 'zero (1)', 1 => 'one (1) (2)')

Expected result:
----------------
Array
(
    [0] => zero (1)
    [1] => one (1)
)

Actual result:
--------------
Array
(
    [0] => zero (1)
    [1] => one (1) (2)
)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-12-06 10:13 UTC] cataphract@php.net
See http://nl.php.net/manual/en/language.references.whatdo.php#language.references.whatdo.assign near the end.

The work-around is unsetting the $elem variable after the last iteration when iterating by reference.
 [2011-12-06 10:13 UTC] cataphract@php.net
-Status: Open +Status: Bogus
 [2011-12-06 10:55 UTC] developer at elementica dot com
I knew the trick. But I think that's just a trick (thankx very much, anyway!)

Foreach takes two arguments, the second being the iteration variable that 
should have a scope relative to the loop. This could also be seen as a feature, 
but we also find stated that "Referencing $value is only possible if the 
iterated array can be referenced (i.e. if it is a variable)".

So:
- if it's to be seen as a feature the latter shouldn't be true
- if it isn't (as it seems better) unset shouldn't be necessary

Let's have a different example...

Considering a function we could have:

function fun(&$x) {
  $x++;
};
$var1 = 7; // this is like the $array1 assignment
fun($var1); // this is like the foreach loop for $array1 (*)
$var2 = $var1; // this is like the $array2=$array1 assignment
fun($var2); // this is like the foreach loop for $array2 (*)
print_r($var1); // WE FIND 8

If we look at "fun" as "foreach" it seems to me we're in a similar case, but 
here $var1 isn't affected by the change of $var2.
(*) just like before... we're applying a construct (foreach before, a function 
now) to a referenced variable.

$x is just a formal parameter, just like $elem


I think the point is here... is $elem a formal parameter or not? I think yes 
would be a better answer.
 [2011-12-06 10:59 UTC] developer at elementica dot com
...and moreover:

if I use "$elem1" in the first loop and "$elem2" in the second it's buggy anyway!!
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Wed Apr 23 18:01:28 2025 UTC