【问题标题】:Are PHP5 objects passed by reference? [duplicate]PHP5 对象是通过引用传递的吗? [复制]
【发布时间】:2011-02-12 11:44:00
【问题描述】:

我似乎无法获得任何一致的信息。不同的来源似乎在说不同的东西,而古老的 php.net 本身(似乎)没有明确说明这一点 - 尽管我必须承认,我只是快速浏览了一下。

在我传递“重”对象的情况下,我需要通过引用传递,但我不想继续输入:

function foo(TypeName& $obj)

如果我能轻松逃脱

function foo(TypeName $obj)

那么标准是怎么说的呢?

【问题讨论】:

    标签: php


    【解决方案1】:

    对象通过引用传递(和分配)。无需使用运营商地址。

    我输入的内容过于简单化,但符合您的目的。 documentation 声明:

    PHP5 OOP 的关键点之一是 经常提到的是“物 默认情况下通过引用传递”。 这并不完全正确。这 部分纠正了一般的想法 使用一些例子。

    PHP 引用是一个别名,它 允许两个不同的变量 写入相同的值。从 PHP5 开始, 对象变量不包含 对象本身不再是价值。它 只包含一个对象标识符 它允许对象访问器找到 实际的对象。当一个对象是 通过参数发送,返回或分配 到另一个变量,不同的 变量不是别名:它们持有 标识符的副本,它指向 到同一个对象。

    如需更详细的解释(解释过度简化以及标识符),请查看this answer。

    【讨论】:

    • 这样你就可以传递对象标识符的引用了吗?
    • 当你传递一个对象时,你仍然是“按值”传递。但是,“价值”不是对象本身。该值是对象标识符,访问器 (->) 使用它来查找对象。因此,每当您传递一个对象或将一个对象分配给其他东西时,它“感觉”就像是通过引用传递。使用 -> 时,它“感觉”像一个别名。但从技术上讲,它不是别名,而是值的副本,其中值是对象标识符。如果它是别名,重新分配给完全不同的值会将所有别名更改为该新值,但您会看到它不会使它们成为别名。
    • @OCDev 所以每次该对象被克隆?有点浪费资源。
    • @JohnSmith - 不,对象没有被克隆。复制的“值”不是对象本身。被复制的值是一个微小的对象标识符,允许他们在内存中找到相同的对象。在变量之间传递或复制对象(进出函数等)非常类似于复制整数。这些“整数”(可以这么说)代表内存中的位置以找到实际对象。当发生任何这种情况时,不会复制完整的对象。 (它只是存在于内存中。)不同的变量也不是彼此的别名。
    【解决方案2】:

    来自PHP manual:

    你可以通过引用传递一个变量 到一个函数,所以这个函数可以 修改变量。语法如下 如下:

    <?php
    function foo(&$var)
    {
        $var++;
    }
    
    $a=5;
    foo($a);
    // $a is 6 here
    ?>
    

    注意:上没有参考符号 函数调用 - 仅在函数上 定义。函数定义 仅此一项就足以正确通过 通过引用论证。从 PHP 开始 5.3.0,你会得到一个警告说“call-time pass-by-reference”是 使用 & in 时已弃用 foo(&$a);.

    来自What's New in PHP5:

    在 PHP 5 中, 对象模型被重写以工作 带有对象句柄。除非你 通过使用显式克隆对象 你永远不会的克隆关键字 在幕后创建副本 你的对象。在 PHP 5 中,有 也不需要传递对象 参考或分配它们 参考

    因此,您唯一需要使用 function foo(&amp;$var) 语法的情况是 $var 可能不是类的实例。

    【讨论】:

    • 我对您的陈述采取了迂腐的例外“因此,您唯一需要使用 > 语法的情况是 $var 可能不是类的实例”。还有另一种重要的情况,您确实希望对类的实例使用按引用...如果 - 作为调用函数的结果,您希望传递的参数引用(指向)a 不同的实例,那么您将需要该函数采用通过引用传递的参数,并在该函数中将该参数分配给不同的实例。
    【解决方案3】:

    似乎更准确一点,对象的值是传值的,而对象本身的值是指针。这与仅传递引用不同。

    在http://www.php.net/manual/en/language.oop5.references.php 上列出的示例很好。在第一组中,$a = NULL;不影响 $b 因为 $a 只是一个指针。在第二组中,$c = NULL;导致 $d 也为 NULL,因为 $d 是对 $c 的引用。

    <?php
    class A {
        public $foo = 1;
    }  
    
    $a = new A;
    $b = $a;
    $a->foo = 2;
    $a = NULL;
    echo $b->foo."\n"; // 2
    
    $c = new A;
    $d = &$c;
    $c->foo = 2;
    $c = NULL;
    echo $d->foo."\n"; // Notice:  Trying to get property of non-object...
    ?> 
    

    【讨论】:

      【解决方案4】:

      从 PHP 5 开始,所有对象都通过引用传递和分配。

      在 PHP 4 中,您仍然需要通过显式使用 &amp; 运算符来指定要通过引用传递对象的位置。

      【讨论】:

        【解决方案5】:

        简短的回答是是。来自Objects and references:

        PHP5 OOP 的关键点之一是 经常提到的是“物 默认情况下通过引用传递”。 这并不完全正确。这 部分纠正了一般的想法 使用一些例子。

        PHP 引用是一个别名,它 允许两个不同的变量 写入相同的值。从 PHP5 开始, 对象变量不包含 对象本身不再是价值。它 只包含一个对象标识符 它允许对象访问器找到 实际的对象。当一个对象是 通过参数发送,返回或分配 到另一个变量,不同的 变量不是别名:它们持有 标识符的副本,它指向 到同一个对象。

        重要的是,如果您担心的话,除非您在函数调用中明确使用 clone 关键字,否则您永远不会复制对象。无论是别名还是标识符都不会改变这一事实。

        【讨论】:

        • 为了进一步澄清,一个例子我有一个 PSR-7 响应对象作为functionName(\Response $response) 传递的行为就像我在 PHP 5+ 中写这个functionName(\Response &amp;$response) 一样?如果这是真的,那么我必须重新考虑我的小项目中的所有内容。
        • @ZsoltOroszlány 在PSR-7 中,根据定义,响应必须是不可变的。这意味着实现必须显式调用clone,例如Slim framework.
        【解决方案6】:

        只是一个通过引用传递“对象”很有用的示例:

        class RefTest1
        {
            public $foo;
        
            public function __construct(RefTest2 &$ref = null)
            {
                $this->foo =& $ref;
            }
        }
        
        class RefTest2
        {
            public $foo;
        
            public function __construct(RefTest1 &$ref = null)
            {
                $this->foo =& $ref;
            }
        }
        
        class RefTest3
        {
            public $foo;
        
            public function __construct(RefTest2 &$ref = null)
            {
                $this->foo =& $ref;
            }
        }
        
        class DoCrossRef
        {
            public $refTest1;
            public $refTest2;
        
            public function __construct()
            {
                $this->refTest1 = new RefTest1($this->refTest2);
                $this->refTest2 = new RefTest2($this->refTest1);
            }
        
            public function changeReference()
            {
                $this->refTest1 = new RefTest3($this->refTest2);
            }
        }
        

        最后RefTest1 持有对RefTest2 的引用,反之亦然,如果RefTest2 对象在RefTest1 创建时不存在。

        在调用DoCrossRef-&gt;changeReference() 之后,RefTest2 对象还持有对新RefTest3 对象的引用。

        【讨论】:

          【解决方案7】:

          是的,从 PHP5 开始,对象通过引用传递。不需要明确地这样做。

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

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

          【讨论】:

            【解决方案8】:

            这是另一个确认对象是通过引用传递的示例。

            <?php
            
            // discussion: https://stackoverflow.com/questions/2715026/are-php5-objects-passed-by-reference#_=_
            class A {
                public $foo = 1;
            }
            
            class B {
                function inc($obj) {
                    $obj->foo++;
                }
            }
            
            $objA = new A();
            $objB = new B();
            $objB->inc($objA);
            
            echo "[" . $objA->foo . "]"; // Outputs [2]
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-07-08
              • 2011-12-11
              • 2014-08-07
              • 1970-01-01
              • 2020-07-02
              • 2017-06-12
              • 1970-01-01
              • 2011-09-30
              相关资源
              最近更新 更多