ChatGPT解决这个技术问题 Extra ChatGPT

Are PHP Variables passed by value or by reference?

Are PHP variables passed by value or by reference?


P
Prabu Guna

It's by value according to the PHP Documentation.

By default, function arguments are passed by value (so that if the value of the argument within the function is changed, it does not get changed outside of the function). To allow a function to modify its arguments, they must be passed by reference. To have an argument to a function always passed by reference, prepend an ampersand (&) to the argument name in the function definition.

<?php
function add_some_extra(&$string)
{
    $string .= 'and something extra.';
}

$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // outputs 'This is a string, and something extra.'
?>

I also had this doubt ( newbie ) - so just to be clear , this would be the same as $str = add_some_extra($str); if I was not using the reference , right ? then what is the real added value of that ?
@Obmerk If you were not using the ampersand to signify by reference, it would not be equivalent. Notice how the function has no return statement, so $str would be assigned null, in your case.
I'm wondering if pass by reference has some performance benefits or not? I'm passing a large array & by default it is pass by value. So, if I use call by reference then, will there be some performance wise benefit??? (keeping the array values unchanged during the whole process)
the real benefit is that you can manipulate/return muliple values. You are also able to pass variables by reference and still let the function return something.
@Choxx There isn't any need to pass an array by reference for performance. The PHP engine uses copy-on-write - it doesn't physically copy the array unless it is modified in one of the scopes where it is visible. Then it makes a copy so the modification only applies in one place.
T
Tanjim Ahmed Khan

In PHP, by default, objects are passed as reference to a new object.

See this example:

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
   $obj->abc = 30;
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 30

Now see this:

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 10 not 20 same as java does.

Now see this:

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue(&$obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 20 not possible in java.

I hope you can understand this.


1st ex, the value of the reference of the obj is passed to the function, changes to the obj using the new reference will reflect to all other references pointing to the same obj. 2nd ex, again the VALUE of the reference of the obj is passed to the function, the function is changing the value of the reference to point to a new obj, the old obj stays the same. 3rd ex, the reference of the value of the reference of the obj is passed into the function, thus the changes in the function is operating on the same obj.
This example is unnecessarily complicated. $y isn't needed - there is nothing in function changeValue that requires it to be inside class Y, so that tangles together two unrelated concepts. I would move function changeValue to the outer scope, just above $x = new X();. Remove all references to $y. Now its easier to see that the first two examples leave $x alone, and the third one changes its contents to new Y(). Which would be easier to see if you dumped the type of $x - the fact that both X and Y happen to include a $abc field is also irrelevant to what is demonstrated
T
Tanjim Ahmed Khan

It seems a lot of people get confused by the way objects are passed to functions and what passing by reference means. Object are still passed by value, it's just the value that is passed in PHP5 is a reference handle. As proof:

<?php
class Holder {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }
}

function swap($x, $y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Outputs:

a, b

To pass by reference means we can modify the variables that are seen by the caller, which clearly the code above does not do. We need to change the swap function to:

<?php
function swap(&$x, &$y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Outputs:

b, a

in order to pass by reference.


I think this proof is a misinterpretation. It looks like you were trying to swap references. You have a problem with how objects are assigned. You are reassigning the reference which is immutable. It's the value it points to that can be changed from inside. The redefinition of swap is now passing **x, which allows you to change *x. The problem is in thinking that $x = $y would change what $x originally points to.
This isn't a proof. The output of the first example is exactly what you'd expect if the current value of the entire object was passed to the swap function; in other words, if objects were "passed by value". On the other hand, it's also exactly what you'd expect if an object handle was passed to the function, which is actually what happens. Your code doesn't distinguish between these two cases.
Object are still passed by value, it's just the value that is passed in PHP5 is a reference handle no. That's like saying passing a pointer to a C function is pass by value. It's not. It's a reference. Yes, a reference is a type of value, but it's still a reference. To pass by reference means we can modify the variables that are seen by the caller indeed, which you can do with an object: $object->foo = 1; will be seen by the caller. In your example you are assigning a new reference to the name, which erases the old reference. That does not make it less of a reference.
What the PHP docs misleadingly refer to as a "reference" &$foo would be more appropriately called an alias or a binding. "Pass by value" and "pass by reference" (and indeed "reference") have existing meanings outside the scope of PHP, with which PHP's bizarre definition is not even remotely compatible.
K
Karl Seguin

http://www.php.net/manual/en/migration5.oop.php

In PHP 5 there is a new Object Model. PHP's handling of objects has been completely rewritten, allowing for better performance and more features. In previous versions of PHP, objects were handled like primitive types (for instance integers and strings). The drawback of this method was that semantically the whole object was copied when a variable was assigned, or passed as a parameter to a method. In the new approach, objects are referenced by handle, and not by value (one can think of a handle as an object's identifier).


T
Tanjim Ahmed Khan

PHP variables are assigned by value, passed to functions by value and when containing/representing objects are passed by reference. You can force variables to pass by reference using an '&'.

Assigned by value/reference example:

$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";

print ("var1: $var1, var2: $var2, var3: $var3);

output:

var1: test, var2: final test, var3: final test

Passed by value/reference example:

$var1 = "foo";
$var2 = "bar";

changeThem($var1, $var2);

print "var1: $var1, var2: $var2";

function changeThem($var1, &$var2){
    $var1 = "FOO";
    $var2 = "BAR";
}

output:

var1: foo, var2 BAR

Object variables passed by reference example:

class Foo{
    public $var1;

    function __construct(){
        $this->var1 = "foo";
    }

    public function printFoo(){
        print $this->var1;
    }
}


$foo = new Foo();

changeFoo($foo);

$foo->printFoo();

function changeFoo($foo){
    $foo->var1 = "FOO";
}

output:

FOO

(The last example could be better probably.)


"Objects" are not values in PHP5 and cannot be "passed". The value of $foo is a pointer to an object. $foo is passed by value to the function changeFoo(), as changeFoo() did not declare its parameter with a &.
@newacct I think what you mean is that the pointer is passed by value but also the object is changed!
M
Mahsin

You can pass a variable to a function by reference. This function will be able to modify the original variable.

You can define the passage by reference in the function definition:

<?php
function changeValue(&$var)
{
    $var++;
}

$result=5;
changeValue($result);

echo $result; // $result is 6 here
?>

T
Tanjim Ahmed Khan

You can do it either way.

Put an '&' symbol in front and the variable you are passing becomes one and the same as its origin i.e. you can pass by reference, rather than make a copy of it.

so

    $fred = 5;
    $larry = & $fred;
    $larry = 8;
    echo $fred;//this will output 8, as larry and fred are now the same reference.

This is deprecated and generates a warning
P
Polsonby

Variables containing primitive types are passed by value in PHP5. Variables containing objects are passed by reference. There's quite an interesting article from Linux Journal from 2006 which mentions this and other OO differences between 4 and 5.

http://www.linuxjournal.com/article/9170


All variables are passed by value in PHP if the parameter of the function has no &.
A
AleksandrH

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:

<?php

//The two are meant to be the same
$a = "Clark Kent"; //a==Clark Kent
$b = &$a; //The two will now share the same fate.

$b="Superman"; // $a=="Superman" too.
echo $a;
echo $a="Clark Kent"; // $b=="Clark Kent" too.
unset($b); // $b divorced from $a
$b="Bizarro";
echo $a; // $a=="Clark Kent" still, since $b is a free agent pointer now.

//The two are NOT meant to be the same.
$c="King";
$d="Pretender to the Throne";
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByValue($c, $d);
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByRef($c, $d);
echo $c."\n"; // $c=="Pretender to the Throne"
echo $d."\n"; // $d=="King"

function swapByValue($x, $y){
$temp=$x;
$x=$y;
$y=$temp;
//All this beautiful work will disappear
//because it was done on COPIES of pointers.
//The originals pointers still point as they did.
}

function swapByRef(&$x, &$y){
$temp=$x;
$x=$y;
$y=$temp;
//Note the parameter list: now we switched 'em REAL good.
}

?>

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.


That should be added to top and blocked from editing.
M
Miha

Objects are passed by reference in PHP 5 and by value in PHP 4. Variables are passed by value by default!

Read here: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html


"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 &.
@newacct not quite? Objects are somewhat passed by reference. I think I've observed that php objects can be modified by functions even when not defined with & in front of the parameters in the definition - if they were passed by value the object contained in the scope which called the function with it as a parameter would not be affected.
@FélixGagnon-Grenier: Again, "objects" are not values and cannot be "passed". You cannot have a "variable" in PHP5 whose value is an "object", you can only have a value that is an object reference (i.e. a pointer to an object). Of course you can pass or assign a pointer to an object by value and modify the object it points to by calling a method that does such modifying. That has nothing to do with pass by reference. What type a value is and whether a parameter is pass-by-value/pass-by-reference are independent and orthogonal things.
R
Ricardo Saracino
class Holder
{
    private $value;

    public function __construct( $value )
    {
        $this->value = $value;
    }

    public function getValue()
    {
        return $this->value;
    }

    public function setValue( $value )
    {
        return $this->value = $value;
    }
}

class Swap
{       
    public function SwapObjects( Holder $x, Holder $y )
    {
        $tmp = $x;

        $x = $y;

        $y = $tmp;
    }

    public function SwapValues( Holder $x, Holder $y )
    {
        $tmp = $x->getValue();

        $x->setValue($y->getValue());

        $y->setValue($tmp);
    }
}


$a1 = new Holder('a');

$b1 = new Holder('b');



$a2 = new Holder('a');

$b2 = new Holder('b');


Swap::SwapValues($a1, $b1);

Swap::SwapObjects($a2, $b2);



echo 'SwapValues: ' . $a2->getValue() . ", " . $b2->getValue() . "<br>";

echo 'SwapObjects: ' . $a1->getValue() . ", " . $b1->getValue() . "<br>";

Attributes are still modifiable when not passed by reference so beware.

Output:

SwapObjects: b, a SwapValues: a, b


C
CGeorgian

Regarding how objects are passed to functions you still need to understand that without "&", you pass to the function an object handle , object handle that is still passed by value , and it contains the value of a pointer. But you can not change this pointer until you pass it by reference using the "&"

<?php
        class Example 
        {
            public $value;
         
        }
        
        function test1($x) 
        {
             //let's say $x is 0x34313131
             $x->value = 1;  //will reflect outsite of this function
                             //php use pointer 0x34313131 and search for the 
                             //address of 'value' and change it to 1

        }
        
        function test2($x) 
        {
             //$x is 0x34313131
             $x = new Example;
             //now $x is 0x88888888
             //this will NOT reflect outside of this function 
             //you need to rewrite it as "test2(&$x)"
             $x->value = 1000; //this is 1000 JUST inside this function
                 
        
        }
         
     $example = new Example;
    
     $example->value = 0;
    
     test1($example); // $example->value changed to  1
    
     test2($example); // $example did NOT changed to a new object 
                      // $example->value is still 1
     
 ?>

P
PPL

Use this for functions when you wish to simply alter the original variable and return it again to the same variable name with its new value assigned.

function add(&$var){ // The &amp; is before the argument $var
   $var++;
}
$a = 1;
$b = 10;
add($a);
echo "a is $a,";
add($b);
echo " a is $a, and b is $b"; // Note: $a and $b are NOT referenced

T
Tanjim Ahmed Khan

Actually both methods are valid but it depends upon your requirement. Passing values by reference often makes your script slow. So it's better to pass variables by value considering time of execution. Also the code flow is more consistent when you pass variables by value.


H
HSLM

A PHP reference is an alias, allowing two different variables to write to the same value.

And in PHP, if you have a variable that contains an object, that variable does not contain the object itself. Instead, it contains an identifier for that object. The object accessor will use the identifier to find the actual object. So when we use the object as an argument in function or assign it to another variable, we will be copying the identifier that points to the object itself.

https://hsalem.com/posts/you-think-you-know-php.html

class Type {}

$x = new Type();
$y = $x;
$y = "New value";

var_dump($x); // Will print the object.
var_dump($y); // Will print the "New value"

$z = &$x; // $z is a reference of $x

$z = "New value";
var_dump($x); // Will print "New value"
var_dump($z); // Will print "New value"


K
Karl Seguin

Depends on the version, 4 is by value, 5 is by reference.


I don't think this is true.
@Karl Seguin, it's partly true. Before PHP5 object by default were passed by value but since 5 they are passed by handler, which in practice can be treated as a reference (with some exceptions) because we can modify object properties via them php.net/manual/en/language.oop5.references.php.