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?
3 Answers 3
$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
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);
}
-
I'd rather use
array_keys()
for part "How to get the expected result"Alma Do– Alma Do2014年09月06日 13:42:18 +00:00Commented Sep 6, 2014 at 13:42 -
As an aside, I recently happened to answer another question 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– Jon2014年09月06日 13:49:08 +00:00Commented Sep 6, 2014 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– SweetSour2014年09月06日 13:58:18 +00:00Commented Sep 6, 2014 at 13:58 -
1@user3576985 , keys cannot be used as reference. So, "expected result" is useless.sectus– sectus2014年09月06日 14:06:25 +00:00Commented Sep 6, 2014 at 14:06
-
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.
array_keys()
. And - yes, in your case you'll end with multiple references to same (end-of-loop) value - see answers below