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

Are PHP Variables passed by value or by reference?

提问人:cmcculloh 提问时间:8/4/2008 最后编辑:hichris123cmcculloh 更新时间:6/25/2021 访问量:220544

问:

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

PHP 变量 传递

评论

6赞 nawfal 11/18/2015
另请参阅 are-arrays-in-php-passed-by-value-or-by-reference
2赞 Premlatha 4/2/2019
codeexpertz.com/blog/php/ 的良好解释......

答:

-8赞 Karl Seguin 8/4/2008 #1

取决于版本,4 是按值,5 是按引用。

评论

13赞 Nick Heiner 8/18/2009
我不认为这是真的。
0赞 Navidot 4/29/2020
@Karl Seguin 来说,这在一定程度上是正确的。在PHP5之前,对象默认是按值传递的,但从5开始,它们是由处理程序传递的,在实践中,处理程序可以被视为引用(有一些例外),因为我们可以通过它们 php.net/manual/en/language.oop5.references.php 修改对象属性。
33赞 cmcculloh 8/4/2008 #2

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

输出:

FOO公司

(最后一个例子可能更好。

评论

3赞 newacct 10/1/2013
“对象”不是 PHP5 中的值,不能“传递”。的值是指向对象的指针按值传递给函数,因为没有用 声明其参数。$foo$foochangeFoo()changeFoo()&
0赞 Achraf JEDAY 10/16/2020
@newacct 我想你的意思是指针是按值传递的,但对象也被更改了!
375赞 Michael Stum 8/4/2008 #3

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

评论

5赞 Obmerk Kronen 11/24/2013
我也有这个疑问(新手) - 所以为了清楚起见,这与我没有使用参考一样,对吧?那么它真正的附加值是什么?$str = add_some_extra($str);
9赞 The Unknown Dev 1/23/2015
@Obmerk 如果你使用与号来表示引用,它就不等价。请注意,该函数没有 return 语句,因此在您的情况下将被分配为 null。$str
2赞 Choxx 10/8/2016
我想知道通过引用传递是否具有一些性能优势?我正在传递一个大数组,默认情况下它是按值传递的。因此,如果我使用调用引用,那么是否会有一些性能方面的好处???(在整个过程中保持数组值不变)
5赞 Martin Schneider 6/18/2017
真正的好处是您可以操作/返回多个值。您还可以通过引用传递变量,并且仍然让函数返回某些内容。
3赞 bdsl 12/4/2020
@Choxx 无需通过引用传递数组来提高性能。PHP 引擎使用写入时复制 - 它不会物理复制数组,除非在它可见的某个作用域中对其进行修改。然后,它会复制一个副本,以便修改仅适用于一个位置。
37赞 Karl Seguin 8/4/2008 #4

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

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

5赞 Polsonby 8/4/2008 #5

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

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

评论

1赞 newacct 10/1/2013
如果函数的参数没有 .&
62赞 grom 8/11/2008 #6

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

通过引用传递意味着我们可以修改调用者看到的变量,这显然是上面的代码没有做到的。我们需要将 swap 函数更改为:

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

以便通过引用。

评论

20赞 grantwparks 6/18/2012
我认为这个证明是一种误解。看起来您正在尝试交换引用。您对对象的分配方式有疑问。您正在重新分配不可变的引用。它所指向的价值可以从内部改变。swap 的重新定义现在正在传递 **x,它允许您更改 *x。问题在于认为 $x = $y 会改变$x最初指向的内容。
11赞 EML 5/13/2015
这不是证据。第一个示例的输出正是将整个对象的当前值传递给函数时所期望的;换句话说,如果对象是“按值传递”的。另一方面,如果将对象句柄传递给函数,这也正是您所期望的,这实际上是发生的事情。您的代码不区分这两种情况。swap
0赞 DimeCadmium 3/23/2022
Object are still passed by value, it's just the value that is passed in PHP5 is a reference handle不。这就像说传递指向 C 函数的指针是按值传递的。事实并非如此。这是一个参考。是的,引用是一种值,但它仍然是一种引用。 事实上,你可以用一个对象来做:将被调用者看到。在示例中,您将为该名称分配一个新引用,这将擦除旧引用。这并没有使它成为一个参考。To pass by reference means we can modify the variables that are seen by the caller$object->foo = 1;
0赞 DimeCadmium 3/23/2022
PHP文档误导性地称为“引用”的东西更合适地称为别名或绑定。“按值传递”和“按引用传递”(实际上是“引用”)在PHP的范围之外具有现有的含义,PHP的奇怪定义甚至与PHP的奇怪定义甚至不兼容。&$foo
6赞 Bingy 2/22/2009 #7

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

在前面加上一个“&”符号,你传递的变量就变成了与它原点相同的变量,即你可以通过引用传递,而不是复制它。

所以

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

评论

3赞 fijiaaron 2/26/2010
此功能已弃用,并生成警告
1赞 Miha 1/10/2010 #8

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

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

评论

1赞 newacct 10/1/2013
“对象”不是 PHP5 中的值,不能“传递”。如果传递给的函数的参数没有 ,则所有变量都按值传递。&
0赞 Félix Adriyel Gagnon-Grenier 12/21/2014
@newacct不完全是?对象在某种程度上是通过引用传递的。我想我已经观察到 php 对象可以被函数修改,即使没有在定义中的参数前面定义 - 如果它们按值传递,则以它作为参数调用函数的范围内包含的对象不会受到影响。&
3赞 newacct 12/21/2014
@FélixGagnon-Grenier:同样,“对象”不是值,不能“传递”。在 PHP5 中,你不能有一个值是 “object” 的 “variable”,你只能有一个值是对象引用(即指向对象的指针)。当然,您可以按值传递或分配指向对象的指针,并通过调用执行此类修改的方法修改它指向的对象。这与通过引用传递无关。值是什么类型以及参数是按值传递还是按引用传递是独立且正交的东西。
1赞 Ricardo Saracino 5/11/2010 #9
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>";

当属性不通过引用传递时,属性仍然是可修改的,因此要小心。

输出:

交换对象:b、a 交换值:a、b

97赞 hardik 3/14/2012 #10

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

我希望你能理解这一点。

评论

4赞 s-hunter 4/28/2015
第一个示例,将 obj 的引用值传递给函数,使用新引用对 obj 的更改将反映到指向同一 obj 的所有其他引用。 第二个示例,再次将 obj 引用的 VALUE 传递给函数,函数正在更改引用的值以指向新的 obj, 旧的 OBJ 保持不变。第三个例子,obj 的引用值的引用被传递到函数中,因此函数的变化在同一个 obj 上运行。
1赞 ToolmakerSteve 7/2/2019
这个例子过于复杂。 是不需要的 - 里面没有任何东西需要它在里面,所以把两个不相关的概念纠缠在一起。我会移到外面的范围,就在上面。删除对 的所有引用。现在更容易看出,前两个示例不理会$x,第三个示例将其内容更改为 .如果您转储了 of ,这将更容易看到 - 两者恰好包含一个字段的事实也与演示的内容无关$yfunction changeValueclass Yfunction changeValue$x = new X();$ynew Y()type$xXY$abc
0赞 André Walker 3/9/2023
我讨厌第一个例子中的行为。
10赞 Mahsin 12/21/2014 #11

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

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

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

$result=5;
changeValue($result);

echo $result; // $result is 6 here
?>
0赞 atif 7/15/2015 #12

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

0赞 PPL 3/31/2018 #13

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

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
9赞 Aleksandr Hovhannisyan 2/6/2020 #14

TL的;DR:PHP 同时支持按值传递和按引用传递。引用使用与号();这与C++的做法非常相似。当函数的形式参数不是用 & 符号声明的(即,它不是引用)时,一切都按值传递,包括对象。对象和基元的传递方式没有区别。关键是要了解将对象传递给函数时传递的内容。这就是理解指针非常宝贵的地方。&

对于将来遇到这种情况的任何人,我想分享一下由匿名用户发布的 PHP 文档中的这个宝石:

这里似乎有些混乱。指针和引用之间的区别并不是特别有用。 已经发布的一些“全面”示例中的行为可以用更简单的统一术语来解释。例如,Hayley 的代码正在做你应该期望它应该做的事情。(使用 >= 5.3)

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

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

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

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

以下是他们提供的示例:

<?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赞 fearis 3/10/2021
应该将其添加到顶部并阻止编辑。
0赞 Jay Dadhania 9/13/2022
想知道为什么这里没有很多赞成票..PHP Docs 中的那些引述清楚地解释了一切!
1赞 CGeorgian 4/12/2021 #15

关于如何将对象传递给函数,您仍然需要了解,如果没有“&”,您将一个对象句柄传递给函数,该对象句柄仍按 value 传递,并且它包含指针的值。但是,在使用“&”通过引用传递它之前,您不能更改此指针

<?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
     
 ?>
0赞 HSLM 6/25/2021 #16

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"