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
 [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

Add a Patch

Pull Requests

Add a Pull Request

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-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 23:01:28 2024 UTC