Is php pass by reference or value?

TL;DR: PHP supports both pass by value and pass by reference. References are declared using an ampersand (&); this is very similar to how C++ does it. When the formal parameter of a function is not declared with an ampersand (i.e., it's not a reference), everything is passed by value, including objects. There is no distinction between how objects and primitives are passed around. The key is to understand what gets passed along when you pass in objects to a function. This is where understanding pointers is invaluable.

For anyone who comes across this in the future, I want to share this gem from the PHP docs, posted by an anonymous user:

There seems to be some confusion here. The distinction between pointers and references is not particularly helpful. The behavior in some of the "comprehensive" examples already posted can be explained in simpler unifying terms. Hayley's code, for example, is doing EXACTLY what you should expect it should. (Using >= 5.3)

First principle: A pointer stores a memory address to access an object. Any time an object is assigned, a pointer is generated. (I haven't delved TOO deeply into the Zend engine yet, but as far as I can see, this applies)

2nd principle, and source of the most confusion: Passing a variable to a function is done by default as a value pass, ie, you are working with a copy. "But objects are passed by reference!" A common misconception both here and in the Java world. I never said a copy OF WHAT. The default passing is done by value. Always. WHAT is being copied and passed, however, is the pointer. When using the "->", you will of course be accessing the same internals as the original variable in the caller function. Just using "=" will only play with copies.

3rd principle: "&" automatically and permanently sets another variable name/pointer to the same memory address as something else until you decouple them. It is correct to use the term "alias" here. Think of it as joining two pointers at the hip until forcibly separated with "unset()". This functionality exists both in the same scope and when an argument is passed to a function. Often the passed argument is called a "reference," due to certain distinctions between "passing by value" and "passing by reference" that were clearer in C and C++.

Just remember: pointers to objects, not objects themselves, are passed to functions. These pointers are COPIES of the original unless you use "&" in your parameter list to actually pass the originals. Only when you dig into the internals of an object will the originals change.

And here's the example they provide:


I wrote an extensive, detailed blog post on this subject for JavaScript, but I believe it applies equally well to PHP, C++, and any other language where people seem to be confused about pass by value vs. pass by reference.

Clearly, PHP, like C++, is a language that does support pass by reference. By default, objects are passed by value. When working with variables that store objects, it helps to see those variables as pointers (because that is fundamentally what they are, at the assembly level). If you pass a pointer by value, you can still "trace" the pointer and modify the properties of the object being pointed to. What you cannot do is have it point to a different object. Only if you explicitly declare a parameter as being passed by reference will you be able to do that.

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

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.:

    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:

function foo(&$var)
{
    
$var++;
}
function 
bar() // Note the missing &
{
    
$a 5;
    return 
$a;
}
foo(bar()); // Produces a noticefoo($a 5); // Expression, not variable
foo(5); // Produces fatal errorclass Foobar
{
}
foo(new Foobar()) // Produces a notice as of PHP 7.0.7
                  // Notice: Only variables should be passed by reference
?>

tnestved at yahoo dot com

7 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.

ccb_bc at hotmail dot com

3 years ago

// 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
?>

mike at eastghost dot com

7 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;
}

nickshanks at nickshanks dot com

5 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:

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);

rob at librobert dot net

10 months ago

A reference remains a reference, even if it's an element of an array that is not passed by reference.

An example:

$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:

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

Jason Steelman

2 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.

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

phpnet at holodyn dot com

8 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.

diabolos @t gmail dot com

10 years ago

/*

  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

"
Define:\na = $a\nb = '$b'
"
;
swap($a,$b);
print
"
After swap(a,b):\na = '$a'\nb = $b
"
;// -------------------------------function swap (&$arg1, &$arg2)
{
// Swap contents of indicated variables.
  
$w=$arg1;   $arg1=$arg2;   $arg2=$w;
}
?>

yiangforwork at gmail dot com

2 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.

tianyiw at vip dot qq dot com

1 year ago

I designed a class that can easily pass references.

#### 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 👇
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

fdelizy at unfreeze dot net

16 years ago

Some have noticed that reference parameters can not be assigned a default value. It's actually wrong, they can be assigned a value as the other variables, but can't have a "default reference value", for instance this code won't compile :

function use_reference( $someParam, &$param =& $POST )
{
...
}
?>

But this one will work :

function use_reference( $someParam, &$param = null )
?>

So here is a workaround to have a default value for reference parameters :

$array1 = array ( 'test', 'test2' );

function

AddTo( $key, $val, &$array = null)
{
    if (
$array == null )
    {
     
$array =& $_POST;
    }
$array[ $key ] = $val ;
}
AddTo( "indirect test", "test", $array1 );
AddTo( "indirect POST test", "test" );

echo

"Array 1 " ;
print_r ( $array1);

echo

"_POST ";
print_r( $_POST );?>

And this scripts output is :

Array 1 Array
(
    [0] => test
    [1] => test2
    [indirect test] => test
)
_POST Array
(
    [indirect POST test] => test
)

Of course that means you can only assign default reference to globals or super globals variables.

Have fun

fladnag at zerezo dot com

5 years ago

Beware of using references with anonymous function and "use" keyword :

If you have a PHP version between 5.3 and < 5.3.10, "use" keyword break the reference :

function withRef(&$arg) {
  echo
'withRef - BEGIN - '.$arg."\n"; // 1
 
$func = function() use($arg) { /* do nothing, just declare using $arg */ };
 
$arg = 2;
  echo
'withRef - END - '.$arg."\n"; // 2
}$arg = 1;
echo
'withRef - BEFORE - '.$arg."\n"; // 1
withRef($arg);
// in PHP 5.3 < 5.3.10 : display 1
// in PHP 5.3 >= 5.3.10 : display 2
echo 'withRef - AFTER - '.$arg."\n";
?>

A workaround is to use a copy of the reference variable in "use" keyword :
  ...
 
$arg2 = $arg;
 
$func = function() use($arg2) { /* do nothing, just declare using $arg2 */ };

no at spam dot please

7 years ago

agreed : this change produces less readable code.

additionally, it breaks many existing perfectly working codes which are not portable anymore and in some cases will require complex modifications

another issue regards the fatal error that is produced : how the hell am i supposed to do if i want to allow the user to use a value that is not even in a variable, or the return or a function call, or use call_user_func... this produces many occasions for a code to even break at run time

Sergio Santana: ssantana at tlaloc dot imta dot mx

18 years ago

Sometimes we need functions for building or modifying arrays whose elements are to be references to other variables (arrays or objects for instance). In this example, I wrote two functions 'tst' and 'tst1' that perform this task. Note how the functions are written, and how they are used.

function tst(&$arr, $r) {
 
// The argument '$arr' is declared to be passed by reference,
  // but '$r' is not;
  // however, in the function's body, we use a reference to
  // the '$r' argument
array_push($arr, &$r);
 
// Alternatively, this also could be $arr[] = &$r (in this case)
} $arr0 = array();          // an empty array
$arr1 = array(1,2,3);   // the array to be referenced in $arr0

// Note how we call the function:

tst($arr0, &$arr1); // We are passing a reference to '$arr1' in the call ! print_r($arr0); // Contains just the reference to $arr1 array_push($arr0, 5); // we add another element to $arr0
array_push($arr1, 18); // we add another element to $arr1 as well print_r($arr1); 
print_r($arr0); // Changes in $arr1 are reflected in $arr0

// -----------------------------------------
// A simpler way to do this:

function tst1(&$arr, &$r) {
 
// Both arguments '$arr' and '$r" are declared to be passed by
  // reference,
  // again, in the function's body, we use a reference to
  // the '$r' argument
array_push($arr, &$r);
 
// Alternatively, this also could be $arr[] = &$r (in this case)
} $arr0 = array();          // an empty array
$arr1 = array(1,2,3);   // the array to be referenced in $arr0

// Note how we call the function:

tst1($arr0, $arr1); // 'tst1' understands '$r' is a reference to '$arr1' echo "-------- 2nd. alternative ------------
\n"
; print_r($arr0); // Contains just the reference to $arr1 array_push($arr0, 5); // we add another element to $arr0
array_push($arr1, 18); print_r($arr1); 
print_r($arr0); // Changes in $arr1 are reflected in $arr0

// This outputs:
// X-Powered-By: PHP/4.1.2
// Content-type: text/html
//
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//         )
//
// )
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 18
// )
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//             [3] => 18
//         )
//
//     [1] => 5
// )
// -------- 2nd. alternative ------------
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//         )
//
// )
// Array
// (
//     [0] => 1
//     [1] => 2
//     [2] => 3
//     [3] => 18
// )
// Array
// (
//     [0] => Array
//         (
//             [0] => 1
//             [1] => 2
//             [2] => 3
//             [3] => 18
//         )
//
//     [1] => 5
// )

?>

In both cases we get the same result.

I hope this is somehow useful

Sergio.

pillepop2003 at yahoo dot de

17 years ago

PHP has a strange behavior when passing a part of an array by reference, that does not yet exist.

    function func(&$a)
    {
       
// void();
   
}$a['one'] =1;
   
func($a['two']);
?>

var_dump($a) returns

    array(2) {
        ["one"]=>
        int(1)
        ["two"]=>
        NULL
    }

...which seems to be not intentional!

obscvresovl at NOSPAM dot hotmail dot com

17 years ago

Just a simple note...

$num

= 1;

function

blah(&$var)
{
   
$var++;
}
blah($num);

echo

$num; #2 ?>

$num

= 1;

function

blah()
{
   
$var =& $GLOBALS["num"];
   
$var++;
}
blah();

echo

$num; #2 ?>

Both codes do the same thing! The second code "explains" how passage of parameters by reference works.

pallsopp at gmail dot com

5 years ago

The comment by tnestved at yahoo dot com is incorrect as it is based purely on perception and not architecture. The method passing the object should not care whether it is by ref or by val, and nor should the reader.

If we are talking about readability and perception, then the receiving method needs to show that the object coming in is a reference, not an object instance, otherwise the reader is perplexed why the object is not returned.

Good functional headers alleviate all issues in this case.

Is PHP pass by reference?

Introduction. In PHP, arguments to a function can be passed by value or passed by reference. By default, values of actual arguments are passed by value to formal arguments which become local variables inside the function. Hence, modification to these variables doesn't change value of actual argument variable.

What is the difference between pass by value and pass by reference in PHP?

Definition. Pass by value refers to a mechanism of copying the function parameter value to another variable while the pass by reference refers to a mechanism of passing the actual parameters to the function. Thus, this is the main difference between pass by value and pass by reference.

Are objects in PHP 5 passed by value or reference explain?

Objects are passed by reference in PHP 5 and by value in PHP 4. Variables are passed by value by default! "Objects" are not values in PHP5 and cannot be "passed". All variables are passed by value if the parameter of the function passed to does not have & .

Is passing by reference faster PHP?

From the PHP Manual itself, “Note that passing by reference doesn't speed up your php script. PHP is smart enough not to simply copy data every time the language requires it.” Currently, the most authoritative guidance I'm aware of on this topic is Schlüter (2010), who literally says, “References in PHP are bad.