Passing by Reference

You can pass a variable by reference to a function so the function can modify the variable. The syntax is as follows:

<?php

function foo(&$var)
{
$var++;
}

$a=5;

foo($a);
// $a is 6 here

?>

Note: There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference.

The following things can be passed by reference:

  • Variables, i.e. foo($a)
  • References returned from functions, i.e.:

    <?php

    function foo(&$var)
    {
    $var++;
    }

    function &
    bar()
    {
    $a = 5;
    return
    $a;
    }

    foo(bar());

    ?>
    See more about returning by reference.

No other expressions should be passed by reference, as the result is undefined. For example, the following examples of passing by reference are invalid:

<?php

function foo(&$var)
{
$var++;
}

function
bar() // Note the missing &
{
$a = 5;
return
$a;
}

foo(bar()); // Produces a notice

foo($a = 5); // Expression, not variable
foo(5); // Produces fatal error

class Foobar {}

foo(new Foobar()) // Produces a notice as of PHP 7.0.7
// Notice: Only variables should be passed by reference

?>
add a note

User Contributed Notes 11 notes

up
442
tnestved at yahoo dot com
9 years ago
By removing the ability to include the reference sign on function calls where pass-by-reference is incurred (I.e., function definition uses &), the readability of the code suffers, as one has to look at the function definition to know if the variable being passed is by-ref or not (I.e., potential to be modified). If both function calls and function definitions require the reference sign (I.e., &), readability is improved, and it also lessens the potential of an inadvertent error in the code itself. Going full on fatal error in 5.4.0 now forces everyone to have less readable code. That is, does a function merely use the variable, or potentially modify it...now we have to find the function definition and physically look at it to know, whereas before we would know the intent immediately.
up
28
ccb_bc at hotmail dot com
5 years ago
<?php
// PHP >= 5.6

// Here we use the 'use' operator to create a variable within the scope of the function. Although it may seem that the newly created variable has something to do with '$x' that is outside the function, we are actually creating a '$x' variable within the function that has nothing to do with the '$x' variable outside the function. We are talking about the same names but different content locations in memory.
$x = 10;
(function() use (
$x){
$x = $x*$x;
var_dump($x); // 100
})();
var_dump($x); // 10

// Now the magic happens with using the reference (&). Now we are actually accessing the contents of the '$y' variable that is outside the scope of the function. All the actions that we perform with the variable '$y' within the function will be reflected outside the scope of this same function. Remembering this would be an impure function in the functional paradigm, since we are changing the value of a variable by reference.
$y = 10;
(function() use (&
$y){
$y = $y*$y;
var_dump($y); // 100
})();
var_dump($y); // 100
?>
up
37
mike at eastghost dot com
9 years ago
beware unset() destroys references

$x = 'x';
change( $x );
echo $x; // outputs "x" not "q23" ---- remove the unset() and output is "q23" not "x"

function change( & $x )
{
unset( $x );
$x = 'q23';
return true;
}
up
2
Anonymous
1 year ago
Parameters passed by references can have default values.
You can find out if a variable was actually passed by using func_num_args():

<?php

function refault( & $ref = 'Do I have to be calculated?'){
echo
'NUM ARGS: '. func_num_args()."\n";
echo
"ORI VALUE: {$ref}\n";
if(
func_num_args() > 0 ) $ref = 'Yes, expensive to calculate result: ' . sleep(1);
else
$ref = 'No.';
echo
"NEW VALUE: {$ref}\n";
}

$result = 'Do I have to be calculated?';
refault( $result );
echo
"RESULT: {$result}\n";
// NUM ARGS: 1
// ORI VALUE: Do I have to be calculated?
// NEW VALUE: Yes, expensive to calculate result: 0
// RESULT: Yes, expensive to calculate result: 0

refault();
// NUM ARGS: 0
// ORI VALUE: Do I have to be calculated?
// NEW VALUE: No.
?>
up
2
Jason Steelman
4 years ago
Within a class, passing array elements by reference which don't exist are added to the array as null. Compared to a normal function, this changes the behavior of the function from throwing an error to creating a new (null) entry in the referenced array with a new key.

<?php

class foo {
public
$arr = ['a' => 'apple', 'b' => 'banana'];
public function
normalFunction($key) {
return
$this->arr[$key];
}
public function &
referenceReturningFunction($key) {
return
$this->arr[$key];
}
}

$bar = new foo();
$var = $bar->normalFunction('beer'); //Notice Error. Undefined index beer
$var = &$bar->referenceReturningFunction('beer'); // No error. The value of $bar is now null
var_dump($bar->arr);
/**
[
"a" => "apple",
"b" => "banana",
"beer" => null,
],
*/

?>
This is in no way a "bug" - the framework is performing as designed, but it took careful thought to figure out what was going on. PHP7.3
up
1
tianyiw at vip dot qq dot com
3 years ago
I designed a class that can easily pass references.

<?php
#### Problem 1
function problem(&$value)
{
}
problem(1); // cannot be passed by reference

#### Problem 2
class problem2
{
static function
__callStatic($name, &$arguments) // cannot take arguments by reference
{
}
}
?>

My solution 👇
<?php
class Reference
{
function
__construct(public mixed &$data)
{
}

/**
* create
*
* @param mixed $data
* @return self
*/
static function &create(mixed &$data): self
{
if (
$data instanceof self) {
return
$data;
}
$r = new self($data);
return
$r;
}

/**
* get value
*
* @param mixed $reference
* @return mixed
*/
static function &get(mixed &$reference): mixed
{
if (
$reference instanceof self) {
return
$reference->data;
}
return
$reference;
}
}

#### Problem solving 1 ####

function test($value)
{
$value = &Reference::get($value); // values OR reference
$value = "test-$value";
return
$value;
}

echo
test(1), PHP_EOL; // test-1

$val = 2;
echo
test(Reference::create($val)), PHP_EOL; // test-2
echo $val, PHP_EOL; // test-2

#### Problem solving 2 ####
class TestCall
{
static function
__callStatic($name, $arguments)
{
$value = &Reference::get($arguments[0]);
$value = "$name-$value";
return
$value;
}
}

echo
TestCall::test(3), PHP_EOL; // test-3

$val = 4;
echo
TestCall::test(Reference::create($val)), PHP_EOL; // test-4
echo $val, PHP_EOL; // test-4
up
1
phpnet at holodyn dot com
10 years ago
The notes indicate that a function variable reference will receive a deprecated warning in the 5.3 series, however when calling the function via call_user_func the operation aborts without fatal error.

This is not a "bug" since it is not likely worth resolving, however should be noted in this documentation.
up
0
nickshanks at nickshanks dot com
7 years ago
For anyone wondering, the copy-on-write behaviour just does the Right Thing™ when an array is passed to a function not by-ref which then passes it through to another function by-ref without writing to it. For example:

<?php

function do_sort(array $array) : array {
usort($array, function ($a, $b) {
return
strnatcasecmp($a['name'], $b['name']);
});

return
$array;
}

$data = [
[
'name' => 'one',
], [
'name' => 'two',
], [
'name' => 'three',
], [
'name' => 'four',
],
];

var_dump($data);
do_sort($data); // does not affect value of $data
var_dump($data);
$data = do_sort($data);
var_dump($data);
up
1
diabolos @t gmail dot com
12 years ago
<?php

/*

This function internally swaps the contents between
two simple variables using 'passing by reference'.

Some programming languages have such a swap function
built in, but PHP seems to lack such a function. So,
one was created to fill the need. It only handles
simple, single variables, not arrays, but it is
still a very handy tool to have.

No value is actually returned by this function, but
the contents of the indicated variables will be
exchanged (swapped) after the call.
*/

// ------------------------------------------
// Demo call of the swap(...) function below.

$a = 123.456;
$b = 'abcDEF';

print
"<pre>Define:\na = $a\nb = '$b'</pre>";
swap($a,$b);
print
"<pre>After swap(a,b):\na = '$a'\nb = $b</pre>";

// -------------------------------

function swap (&$arg1, &$arg2)
{

// Swap contents of indicated variables.
$w=$arg1; $arg1=$arg2; $arg2=$w;
}

?>
up
-5
yiangforwork at gmail dot com
3 years ago
function set(&$arr) {
$test = 10;
$arr = &$test;
}

$arr = [1, 2, 3];
set( $arr );

var_dump( $arr ); // [1, 2, 3]

If you changed a reference variable with a new `Address`, the variable it originally pointed to won't change.
up
-4
rob at librobert dot net
2 years ago
A reference remains a reference, even if it's an element of an array that is not passed by reference.

An example:

<?php
$c
= 3;
$array = array(
'a' => 1,
'b' => 2,
'c' => &$c
);
var_dump($array);
function
func($array) {
$array['a'] = 4;
$array['b'] = 5;
$array['c'] = 6;
var_dump($array);
}
func($array);
var_dump($array);
var_dump($c);
?>

This will output the following:

array(3) {
["a"]=>
int(1)
["b"]=>
int(2)
["c"]=>
&int(3)
}
array(3) {
["a"]=>
int(4)
["b"]=>
int(5)
["c"]=>
&int(6)
}
array(3) {
["a"]=>
int(1)
["b"]=>
int(2)
["c"]=>
&int(6)
}
int(6)

You could use this to allow a function to have read-write access to part of the array, while limiting it to read-only access for the rest of the array:

<?php
$config
= [
'ro' => [
// ...
],
'rw' => [
// ...
]
];
$copy = $config;
$copy['rw'] = &$config['rw'];
func($copy);
?>
To Top