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


Answers:


310

根据PHP文档的价值。

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

有一个参数总是通过引用传递函数,在前面加上符号(),以在函数定义的参数名称。

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

4
我也有这个疑问(新手),所以要清楚一点,就$str = add_some_extra($str);好像我没有使用参考一样,对吗?那么那真正的附加值是什么?
Obmerk Kronen

7
@Obmerk如果您使用&号表示引用,则表示该名称不是等效的。请注意,该函数没有返回语句,因此$str在您的情况下将被分配为null。
未知开发人员

如果以这种方式使用@ObmerkKronen,则必须返回该值并通过代码捕获它。否则,初始变量将保持不变。
Nabeel Khan

我想知道通过引用传递是否具有某些性能优势?我正在传递一个大数组,默认情况下是按值传递。因此,如果我使用按引用调用,那么在性能上会有一些好处吗???(在整个过程中保持数组值不变)
Choxx

4
真正的好处是您可以操纵/返回多个值。您还可以通过引用传递变量,并且仍然让函数返回某些内容。
Martin Schneider

65

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

我希望你能理解这一点。


1
这很好地说明了PHP对象如何处理。
Frederik Krautwald

2
首先,将obj的引用值传递给函数,使用新引用对obj进行的更改将反映指向该obj的所有其他引用。第二个例子,再次将obj引用的VALUE传递给函数,该函数将引用的值更改为指向新obj,旧obj保持不变。第三例,将obj的引用的值的引用传递到函数中,因此函数中的更改对同一obj进行操作。
s-hunter 2015年

完美的例子以及我所想的都会发生。我是PHP的新手(从Javascript / node.js背景开始),有时很难理解发生了什么,但这很清楚!
TKoL

此示例不必要地复杂。$y不需要-没有任何function changeValue内容要求它在内部class Y,因此将两个不相关的概念缠在一起。我将移至function changeValue上方的外部范围$x = new X();。删除所有对的引用$y。现在,更容易看到前两个示例不涉及$ x,而第三个示例将其内容更改为new Y()。这将是更容易地看到,如果你甩了type$x-事实上,这两个XY发生在包括$abc现场也无关证明什么
ToolmakerSteve

60

似乎很多人对对象传递给函数的方式以及引用所传递的方式感到困惑。对象变量仍然按值传递,它只是在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

为了按引用传递手段,我们可以修改被调用者得到的变量。显然上面的代码不起作用。我们需要将交换功能更改为:

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

为了通过引用。


18
我认为这个证明是一种误解。似乎您正在尝试交换引用。您对对象的分配方式有疑​​问。您正在重新分配不可变的参考。它指向的值可以从内部更改。交换的重定义现在通过** x,这使您可以更改* x。问题在于认为$ x = $ y会改变$ x最初指向的内容。
Grantwparks 2012年

9
这不是证明。如果将整个对象的当前值传递给swap函数,则第一个示例的输出正是您所期望的。换句话说,如果对象被“传递了价值”。另一方面,如果将对象句柄传递给函数,这也正是您所期望的,这实际上是会发生的。您的代码无法区分这两种情况。
EML 2015年

31

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

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


25

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

通过值/参考示例分配:

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

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

将输出

var1:测试,var2:最终测试,var3:最终测试

通过价值/参考书目:

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

将输出:

OO

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


2
“对象”不是PHP5中的值,因此不能“传递”。的值$foo指向对象指针$foo通过值传递给函数changeFoo(),因为changeFoo()没有使用来声明其参数&
newacct

9

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

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

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

$result=5;
changeValue($result);

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

6

您可以采用任何一种方式来做。

在前面加上“&”符号,您要传递的变量将与原点相同。即:您可以通过引用传递,而不是复制引用。

所以

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

2
已弃用,并产生警告
fijiaaron 2010年

5

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

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


如果函数的参数为​​no,则所有变量均按PHP中的值传递&
newacct

1

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

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


“对象”不是PHP5中的值,因此不能“传递”。如果传递给的函数的参数没有,则按值传递所有变量&
newacct

@newacct不完全吗?对象在某种程度上是通过引用传递的。我认为我已经观察到,即使未在定义&中的参数前面定义php对象,也可以通过函数对其进行修改-如果它们通过值传递,则包含在范围内的对象将其作为参数调用该函数不受影响。
费利克斯·加侬-格尼尔

3
@FélixGagnon-Grenier:同样,“对象”不是值,不能“传递”。在PHP5中,不能有一个值是“对象”的“变量”,只能有一个对象引用(即指向对象的指针)的值。当然,您可以按值传递或分配指向对象的指针,并通过调用进行此修改的方法来修改其指向的对象。这与通过引用无关。值是什么类型以及参数是否为按值传递/按引用传递是独立且正交的事物。
newacct 2014年

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


1

对于以后遇到此问题的任何人,我想分享一个匿名用户发布PHP文档中的这个宝石:

这里似乎有些混乱。指针和引用之间的区别不是特别有用。可以使用更简单的统一术语来解释已经发布的某些“综合”示例中的行为。例如,海莉(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.
}

?>

我在JavaScript的这个主题上写了一篇详尽的博客文章,但是我认为它同样适用于PHP,C ++和其他人们对按值传递与按引用传递感到困惑的其他语言。

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


0

实际上这两种方法都是有效的,但这取决于您的要求。通过引用传递值通常会使脚本变慢。因此,最好通过考虑执行时间按值传递变量。同样,当按值传递变量时,代码流更加一致。


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.