Tuesday 14 August 2018

PHP : Passing an array by reference

Passing an array in php to a foreach which loops over the elements by reference can have strange behaviour.
Look at the following code:
//Create an array
$array=array('a','b','c','d','e','f','g');

//Loop over the array by reference
foreach($array as &$a){
}

//Loop again over the array
foreach($array as $a){
}

//Print the array
print_r($array);

What do you think the output would be if you run this piece of code? Because the array is never changed, the expected result would be:
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => d
    [4] => e
    [5] => f
    [6] => g
)

If that was the case, I obviously wouldn't have made this blogpost ;-) The result of the code is:
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => d
    [4] => e
    [5] => f
    [6] => f
)

What's going on?? Well... When you loop the first time over the array, the variable $a will be referenced to the array $array. This means that with every iteration $a points to the specified element in the array. After every element passed the foreach, $a still points to the last element in the array. In this case 'g'.
Now you have to loop again over the array. When the first element 'a' is passed to the foreach. $a will be set to 'a' but there is still a reference to $a from the previous foreach, which holds the value 'g'. Because it's a reference, the value of 'g' in the array changes to 'a'. When the second element 'b' is passed to the foreach. $a will be set to 'b' but the reference to $a still exists so the value of the referenced $a changes from 'a' to 'b' And so on.
If you print the value of the array at every iteration, you will have the following output:
Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => a ) 
Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => b ) 
Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => c ) 
Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => d ) 
Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => e ) 
Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => f ) 
Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => f )

What to do?? 1. Don't use references in a foreach. Really. If you have to do it, you propably are doing something wrong. 2. If you do need them, delete them after they are used:
$array=array('a','b','c','d','e','f','g');

//Loop over the array
foreach($array as &$a){
}
//remove the reference
unset($a);
//loop again over the array. The output looks like expected
foreach($array as $a){
        print_r($array);
}

  1. If you do need them and you can't delete it because you need the variable elsewhere. Document your code!!! This little piece of code is very hard to debug when there's something wrong. Good documented code can save you a lot of headache.

0 comments:

Post a Comment