PHP变量是通过值还是通过引用传递的?

时间:2008-08-03 22:51:41

标签: php variables pass-by-reference pass-by-value

PHP变量是按值传递还是按引用传递?

16 个答案:

答案 0 :(得分:271)

根据PHP Documentation按值计算。

  

默认情况下,函数参数按值传递(因此,如果函数中的参数值发生更改,则不会在函数外部更改)。要允许函数修改其参数,必须通过引用传递它们。

     

要使函数的参数始终通过引用传递,请将&符号(& )添加到函数定义中的参数名称。

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

答案 1 :(得分:58)

似乎很多人对对象传递给函数的方式以及通过引用传递的方式感到困惑。对象变量仍然按值传递,它只是在PHP5中传递的值是一个引用句柄。作为证据:

<?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";

输出:

a, b

To pass by reference表示我们可以修改调用者看到的变量。显然上面的代码没有做到。我们需要将交换功能更改为:

<?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";

输出:

b, a

以便通过引用传递。

答案 2 :(得分:51)

在PHP中,默认情况下,对象作为引用副本传递给新对象。

参见此示例.............

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

现在看这..............

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.

现在看这..............

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.

我希望你能理解这一点。

答案 3 :(得分:27)

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

  

在PHP 5中有一个新的对象模型。 PHP对对象的处理已经完全重写,允许更好的性能和更多的功能。在以前的PHP版本中,对象的处理方式与原始类型(例如整数和字符串)相同。这种方法的缺点是语义上整个对象在分配变量时被复制,或者作为参数传递给方法。在新方法中,对象由句柄引用,而不是通过值引用(可以将句柄视为对象的标识符)。

答案 4 :(得分:21)

PHP变量按值分配,按值传递给函数,当包含/表示对象通过引用传递时。您可以使用&amp;

强制变量通过引用传递

按值/参考示例分配:

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

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

会输出

  

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

通过值/参考例子传递:

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

changeThem($var1, $var2);

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

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

会输出:

  

var1:foo,var2 BAR

参考例子传递的对象变量:

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

输出:

  

FOO

(最后一个例子可能更好......)

答案 5 :(得分:7)

您可以通过引用将变量传递给函数。此功能将能够修改原始变量。

您可以在函数定义中通过引用定义段落:

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

$result=5;
changeValue($result);

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

答案 6 :(得分:5)

你可以这样做。

放一个'&amp;'前面的符号和你传递的变量与它的原点相同。即:你可以通过引用传递,而不是复制它。

所以

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

答案 7 :(得分:4)

包含基本类型的变量在PHP5中按值传递。包含对象的变量通过引用传递。 2006年Linux Journal上发表了一篇非常有趣的文章,其中提到了4和5之间的这种和其他OO差异。

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

答案 8 :(得分:1)

通过PHP 5中的引用和PHP 4中的值传递对象。 默认情况下,变量按值传递!

请在此处阅读:http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html

答案 9 :(得分:1)

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

如果没有通过引用传递,属性仍然可以修改,所以要小心。

输出:

SwapObjects:b,a SwapValues:a,b

答案 10 :(得分:1)

对于以后遇到此问题的任何人,我想分享PHP docs, posted by an anonymous user中的这个宝石:

这里似乎有些混乱。指针和引用之间的区别不是特别有用。 可以用更简单的统一术语来解释已经发布的某些“综合”示例中的行为。例如,海莉(Hayley)的代码完全按照您的预期做。 (使用> = 5.3)

第一个原则: 指针存储用于访问对象的内存地址。每当分配对象时,都会生成一个指针。 (我还没有深入研究Zend引擎,但是据我所知,这仍然适用)

第二个原理,最混乱的原因是: 默认情况下,将变量传递给函数是值传递,即您正在使用副本。 “但是对象是通过引用传递的!”在这里和Java世界中,都有一个普遍的误解。我从没说过什么。默认传递是通过值完成的。总是。但是,要复制和传递的是指针。当使用“->”时,您当然将访问与调用程序函数中原始变量相同的内部函数。仅使用“ =”只会播放副本。

第三个原则: “&”会自动将另一个变量名/指针与其他变量永久设置为相同的内存地址,直到您将它们解耦为止。在此处使用术语“别名”是正确的。可以认为它是在臀部连接两个指针,直到用“ unset()”强制分隔为止。此功能既存在于同一作用域中,又存在于将参数传递给函数时。经常将传递的参数称为“引用”,这是因为在C和C ++中“按值传递”和“按引用传递”之间存在某些区别。

请记住:指向对象而不是对象本身的指针被传递给函数。这些指针是原始文档的副本,除非您在参数列表中使用“&”来实际传递原始文档。只有当您深入研究对象的内部时,原始对象才会改变。

这是他们提供的示例:

<?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,但我认为它同样适用于PHP,C ++和其他人们对按值传递与按引用传递感到困惑的其他语言。

很明显,PHP和C ++一样,是一种确实支持按引用传递的语言。默认情况下,对象按值传递。当使用存储对象的变量时,将这些变量视为指针是有帮助的(因为从根本上来说,它们是汇编级的)。如果按值传递指针,则仍然可以“跟踪”指针并修改所指向对象的属性。您不能做的就是让它指向另一个对象。只有将参数明确声明为通过引用传递,您才能做到这一点。

答案 11 :(得分:1)

关于如何将对象传递给函数,您仍然需要了解,如果没有“&”,您将传递给函数一个对象句柄,对象句柄仍然通过值传递,并且它包含一个指针的值。但是你不能改变这个指针,除非你使用“&”通过引用传递它

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

答案 12 :(得分:0)

当您希望简单地更改原始变量并将其再次返回到指定了新值的相同变量名称时,将其用于函数。

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

答案 13 :(得分:0)

看这个例子:

<?php

$string = 'First String. ';
$string .= 'Second String. ';
$string .= 'Third String. ';

echo $string;

// output: First String. Second String. Third String. 

?>

答案 14 :(得分:0)

PHP 引用是一个别名,允许两个不同的变量写入相同的值。

而在 PHP 中,如果您有一个包含对象的变量,则该变量不包含对象本身。相反,它包含该对象的标识符。对象访问器将使用标识符来查找实际对象。因此,当我们将对象用作函数中的参数或将其分配给另一个变量时,我们将复制指向对象本身的标识符。

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"

答案 15 :(得分:-7)

取决于版本,4是按值,5是参考。