php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #54408 Unexpected behaviour when using by-reference iteration
Submitted: 2011-03-28 14:35 UTC Modified: 2011-04-26 18:40 UTC
Votes:2
Avg. Score:3.5 ± 0.5
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:0 (0.0%)
From: hitchiker at mail dot ru Assigned:
Status: Not a bug Package: Arrays related
PHP Version: 5.3.6 OS: Win 7 x64, 2.6.18
Private report: No CVE-ID: None
 [2011-03-28 14:35 UTC] hitchiker at mail dot ru
Description:
------------
I was sure that arrays are passed to functions by value, not by reference. It looks like after by-reference iteration changes array not only isnide foreach statement, but array remains changed even after iteration.

Test script:
---------------
<?php
$a = array(1,2,3,4);

function myf($a,$k){
    $a[$k] = 9;
}
foreach ($a as $k => &$v) {
    myf($a, $k);
}
//myf($a, 3);
var_dump($a);
die();

Expected result:
----------------
array
  0 => int 1
  1 => int 2
  2 => int 3  
  3 => int 4

Actual result:
--------------
array
  0 => int 9
  1 => int 9
  2 => int 9
  3 => &int 9

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-04-08 13:10 UTC] hitchiker at mail dot ru
-Summary: Unexpected behavior when using by-reference iteration +Summary: Unexpected behaviour when using by-reference iteration
 [2011-04-08 13:10 UTC] hitchiker at mail dot ru
I was sure that arrays are passed to functions by value, not by reference. It looks like by-reference iteration changes array not only isnide foreach statement, but array remains changed even after iteration.
 [2011-04-26 08:33 UTC] blacknot at gmail dot com
I have similar problem:

$tags = array('iphone', 'apple', 'iPhone 4');
foreach ($tags as &$v) $v = trim($v);
           
$tags2 = $tags;
foreach ($tags2 as &$a) $a = '*';
           
print_r($tags);

Result:
Array
(
   [0] => iphone
   [1] => apple
   [2] => *
)
 [2011-04-26 08:40 UTC] rasmus@php.net
-Status: Open +Status: Bogus
 [2011-04-26 08:40 UTC] rasmus@php.net
There is no expression-scope in PHP. If you create references in an array in a foreach loop or in any other expression, those references will still exist after the foreach. Follow the references and you will see that the output makes sense. There is no bug here.
 [2011-04-26 10:25 UTC] blacknot at gmail dot com
Why only last element of array have reference link? It`s realy unexpected behaviour. We copy array $tags2 = $tags; but only last element have reference.
 [2011-04-26 12:24 UTC] johannes@php.net
I once tried to come up with some text and pictures explaining this: http://schlueters.de/blog/archives/141-References-and-foreach.html
 [2011-04-26 12:39 UTC] blacknot at gmail dot com
thanks Johannes, after articles I read interesting hack about unsetting referense value: "Standard practise after any loop iteration when using references should be an unset()"

But it is hack and unexpected behaviour
 [2011-04-26 16:35 UTC] rasmus@php.net
It is completely consistent though. You are moving that reference along in the foreach loop. It would be inconsistent if we magically unset it. 

It's not that different from something like:

for($i=0; $i<=10; $i++) echo $a[$i];

You don't really think about it, but after this loop $i is going to be 11. What you are suggesting is that either $i shouldn't be set anymore, or that it somehow shouldn't be set to 11. It is more obvious in this case, so perhaps it isn't unexpected for you, but it really is the same thing.
 [2011-04-26 17:12 UTC] blacknot at gmail dot com
In this scope is true. Variable $v must be reference, but we copy array ($tags2 = $tags;) and the last element is still reference. It is unexpected!
 [2011-04-26 18:40 UTC] rasmus@php.net
I don't understand why you don't expect references to be copied.

So, if you had code like this:

<?php
$a = 1;
$b = 2;
$c = 3;
$arr = array(&$a, $b, &$c);
$arr2 = $arr;
var_dump($arr2);

You are expecting the $a and $c references to get dropped 
in $arr2?

They are not dropped. It is a by-value copy, and the by-value 
copy of a reference remains a reference.
 [2011-04-27 10:50 UTC] blacknot at gmail dot com
I was expecting this example;-) And I understand your point of view. But I think that this is so because that is the realization, not because it is better and many people faced with this and do not expect such behavior. Thank you very much for your answers and good luck with php.

PS: Sorry for my bad english ;-)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 15:01:28 2024 UTC