Arrays and References Gotcha, Array Passed by Value Behaves Like Array Passed by Reference

In PHP 5, when you pass an array by value, but the array contains references, then, you will get some subtly weird behavior.

Basically, when you copy an array of references, the references still refer to the same variables. So changes to those variables aren't local to the function.

$args = array();
$args['x'] =& $_REQUEST['x'];

echo "<p>$args[x]</p>";

f($args);

echo "<p>$args[x]</p>";

$x = $_REQUEST['x'];

echo "<p>$x</p>";

function f($a)
{
    $a['x'] = 100;
}

Calling it like this: test.php?x=5

Displays:

5
100
100
$args = array();
$args['x'] = $_REQUEST['x'];

echo "<p>$args[x]</p>";

f($args);

echo "<p>$args[x]</p>";

$x = $_REQUEST['x'];

echo "<p>$x</p>";

function f($a)
{
    $a['x'] = 100;
}

That displays:

5
5
5

This second example is the "expected" behavior. The array is passed to f() by value, so we expect change made within f() to remain local to f().

However, the array $args is an array of references. That is, it's an array, but it's element 'x' refers to $_REQUEST['x'].

So, when $args is copied as an argument to f(), it's copies the reference. Then, within f(), $a['x'] refers to $_REQUEST['x']. So changes to $a['x'] affect $_REQUEST['x'].

This can cause problems if you are creating objects based on $args, like this:

$args =& $_REQUEST['x'];
$obj1 = new Obj($args);
$obj2 = new Obj($args);

class Obj {
    function Obj($args) {
      $this->args = $args;
    }
}

In this situation, changes to $obj1->args['x'] will affect $obj2->args['x'], because they refer to the same variable!