1

I'm trying to add integer references to an array in PHP but for some reason it doesn't work. I am completely confused as to why.

Simplifying things, the code is:

<?php

$myArray = array( 1 => true, 2 => true, 3 => true );
$param_ref = array();
foreach($myArray as $key => $value) {
    $param_ref[] = &$key;
}
var_dump($param_ref);

?>

I expect the output to be:

array(3) { 
    [0] => &int(1) 
    [1] => &int(2) 
    [2] => &int(3) 
} 

But the actual output is:

array(3) { 
    [0] => &int(3) 
    [1] => &int(3) 
    [2] => &int(3) 
} 

With some closer inspection, it seems the array's ($param_ref) values are being overwritten on each iteration of the loop.

Any idea what's going on?

SweetSour
  • 73
  • 1
  • 5
  • Why do that? Just use `array_keys()`. And - yes, in your case you'll end with multiple references to same (end-of-loop) value - see answers below – Alma Do Sep 06 '14 at 13:44

3 Answers3

1

$key is being changed each iteration of the loop, so your reference to $key is always going to be a reference to the current value of $key, which (at the end of the loop) is three.... so all three references to $key are pointing to the one and only instance of $key, which has a value of 3

Consider as:

Iteration #1

$key is assigned the value 1; $param_ref[0] is a reference to $key, so it's pointing to a variable with a value of 1.

Iteration #2

$key now has a value of 2, ; $param_ref[1] is a reference to $key, so it's pointing to a variable with a value of 2.... but $param_ref[0] is also a reference to $key, so it's pointing to a variable which now has a value of 2

Iteration #3

$key now has a value of 3, ; $param_ref[2] is a reference to $key, so it's pointing to a variable with a value of 3.... but both $param_ref[0] $param_ref[1] are also referencing $key, so they're pointing to a variable which now has a value of 3

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
1

You fought PHP, and PHP won. :-)

What happened is that by using the expression &$key you caused PHP to regard the value pointed to by $key as a reference. This in turn causes reassignments to $key (which happen on every iteration of the loop) to be visible through all variables that were assigned the value &$key at any point in the past.

That is, after the first iteration the resulting array is

array(1) { 
    [0] => &int(1) 
} 

After the second iteration, the array is

array(2) { 
    [0] => &int(2) 
    [1] => &int(2) 
} 

and so on.

How to get the expected result: Simply unset($key) at the end of the loop:

foreach($myArray as $key => $value) {
    $param_ref[] = &$key;
    unset($key);
}
Jon
  • 428,835
  • 81
  • 738
  • 806
  • I'd rather use `array_keys()` for part __"How to get the expected result"__ – Alma Do Sep 06 '14 at 13:42
  • +1 for providing the "how to get the expected result" – Mark Baker Sep 06 '14 at 13:45
  • @AlmaDo: That's no fun at all! :-) – Jon Sep 06 '14 at 13:46
  • As an aside, I recently happened to answer [another question](http://stackoverflow.com/q/25420812/50079) where the unexpected result was caused by exactly this same internal mechanism. It might be useful as additional material, especially since the answer there has more detail and considers several alternatives. – Jon Sep 06 '14 at 13:49
  • Unfortunately this is now giving me the result of: `array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }` whereas I require an array of references: `array(3) { [0]=> &int(1) [1]=> &int(2) [2]=> &int(3) }` – SweetSour Sep 06 '14 at 13:58
  • 1
    @user3576985 , keys cannot be used as reference. So, "expected result" is useless. – sectus Sep 06 '14 at 14:06
  • because keys are not [`zval`](http://php.net/manual/ru/internals2.variables.intro.php) – sectus Sep 06 '14 at 14:12
  • @user3576985: sectus is right, array keys cannot be changed through references (example http://codepad.org/YJAWX0c1). – Jon Sep 06 '14 at 14:40
0

Your $param_ref values are not being overwritten, it's how a foreach works in general. Also the cause of much talked-about foreach($foo as &$bar) issue, which you can read if you search. The thing is, when you do = &$key;, you don't create a reference to something $key is pointing at, you create reference to $key value. When this value changes, so does all references to $key.

Anyways, as been pointed out numerous times, you would do yourself a favor if you accepted the fact that PHP's references are terribly broken, and just forget of their existence whatsoever.

Eternal1
  • 5,447
  • 3
  • 30
  • 45