Found at: http://publish.ez.no/article/articleprint/77

PHP References explained



One of the most underused features of PHP is the ability to use references. The problem is that using references are rather troublesome in PHP. References was not part of the original syntax but has been added later on, thus leading to a somewhat confusing syntax. There's also little support for references in the native function set.

References in PHP are simpler than the related mechanism found in C and C++, C and C++ uses pointers which allows for pointing to memory areas. C++ also has references which are less troublesome than pointers but not as versatile. By using references you can refer or point to the same data using different variables. This is useful when you want to avoid costly memory operations or want functions to access your data directly rather than copying it.

References are created by assigning a variable with the reference operator &.

$a = "data";
$b =& $a; // Now $b refers to data in $a


As I mentioned above the behavior is not as advanced as in C/C++, this means that you cannot create a reference to a reference. For instance let's extend the above example by create a new reference.

$c =& $b;


Now $c will refer to the same data as $b, i.e the reference has been copied but not the data. This means that we've done a cheap copy of the data, sometimes known as shallow copy.

References are similar to C/C++ pointers but does not use a pointer to the content, the difference should be clearer in this example.

$a = "test";
$b =& $a;
$c =& $b;

$a = "ok";
print( "$a $b $c" ); // outputs ok ok ok

$d = "test";
$a =& $d;
print( "$a $b $c" ); // outputs test ok ok


As you can see both $b and $c refer to the content of $a, but when $a is changed into a reference they still point to the same content as before, i.e they are not referring to what $a is referring.
The same thing happens with the unset function.

$a = "test";
$b =& $a;
$c =& $b;

unset( $a );

print( "$b $c" ); // outputs test test


$b and $c still point to the same content as before the unset.

Arrays and references

You can also let array elements be references.

$a = array();
$b = "test";
$a[0] =& $b;
$a[1] = "ok";
$a["ok"] =& $b;


Now let's get back to the standard assignment operator, consider

$d = $a;


This creates a new copy of the data and refers to it in $d. This is known as deep copy and is what you've probably been using.
References are extremely important when you're working with complex object and array hierarchies.

All of PHP's iterating structures and functions does not create references but actually copies each element, this is OK when dealing with small data sizes but has a significant performance hit with larger data.

Arrays have a different behavior when using the assignment operator.

$b = "data";
$arr = array();
$arr["a"] =& $b;
$arr_copy = $arr;


This actually performs a copy of all the elements of the array but only a shallow copy, so the reference is only copied to the new element not the data.

Using the function var_dump you can easily spot elements which are references.
This means that array elements will be deep copied if they have real contents but will have a shallow copy when a reference is encountered.

Functions

Using references in functions is done by adding an & before the parameter.

function inc( &$var )
{
  ++$var;
}
$a = 1;
inc( $a ); // $a is now 2


Unfortunately you cannot do this

function assign( &$a )
{
  $GLOBALS["a"] =& $a;
}
function retval()
{
  return "abc";
}
$c = "a";
$d = "b";
assign( 4 ); // Constant cannot be passed
assign( retval() ); // No reference in return value
assign( $c == $d ); // Expression cannot be passed


Also returning a reference is done by adding an & before the function name and by referring to the function call.

function &createRef()
{
  $a = "text";
  return $a;
}
$b =& createRef(); // $b refers to the data of $a in the function


What happens if you want a function to change the reference of a variable but not the data itself. As you might recall it's not possible to create a reference to a reference.

The clue is to use arrays, create an array and let a specific key refer to your data then pass the array to function which takes the parameter as a reference.

function refChange( &$b )
{
  $c = "text";
  $b["ref"] =& $c; // Changes the reference for "ref" key 
}
$a = "test";
$arr = array();
$arr["ref"] =& $a;
refChange( $arr ); // Now $arr["ref"] refers to "text".

Globals

The global syntax is actually a reference too, it creates a reference to a global variable.

function a()
{
  global $glob1;
  $glob2 =& $GLOBALS["glob1"];
}


Now $glob1 and $glob2 refer to the same data. The limitations of using the global syntax is that you can't change what the global variable is referring to you can just change the data it's referring. To achieve changing the reference for the global variable you must do.

function b()
{
  $a = "test";
  $GLOBALS["glob1"] =& $a; // Now the global variable $glob1 refers to contents of $a
}


Iterating

As mentioned above PHPs array iterator structures and functions such as foreach and each does not handle references very well, in-fact they create a copy of each element they iterate over. For instance this will not work:

$ref_arr = array();
foreach ( $arr as $item )
{
  $ref_arr[] =& $item;
}


When the foreach is done the $ref_arr will contain references to the last element in the $arr array.
The reason is that when you create the reference you refer to the variable $item which will contain the last item after foreach is done.

There are two ways to iterate arrays correctly, the first only works with normal arrays while the second works with all types of arrays. Method 1 involves using a for loop.

for ( $i = 0; $i < count( $arr ); ++$i )
{
  $item =& $arr[$i];
}


While method 2 uses the key and next functions.

reset( $arr ); // Restart the internal pointer
while ( ( $key = key( $arr ) ) !== null ) // fetch the current key, or null if at end
{
  $item =& $arr[$key]; // Create reference to element
  next( $arr ); // Advance to next key
}


The second method is similar to the first but now the key is fetched from the array instead of assuming a numerical index.

When should references be used?

When you're passing on large text, array or object structures to functions or passing data trough nested function calls. You should also perform benchmarking of your PHP code to find out places that need references, often using references will reduce execution time significantly.

When should references not be used?

When creating functions which usually is fed with constants values. PHP cannot create references to unassigned data, except for new object instances. For instance consider this example

function doIt( &$a )
{
  // Do something with $a
}

doIt( "some text" ); // Will not work

$txt = "some text";
doIt( $txt ); // Will work


The latter will always work but is cumbersome when you're using these functions often.

Links

References explained in the PHP manual
foreach structure
key function


| Back to normal page view |