“参考”的使用方式是否存在歧义?

时间:2011-01-19 23:19:08

标签: php reference terminology

例如,在PHP中我们可以这样写:

class C {
    var $x;

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

    function __toString() {
        return (string)$this->x;
    }
}

function f1($obj) {
    $obj->x = 2;
}

$a = new C(1);
f1($a);
echo $a; // 2

有些人会说这表明对象是通过引用传递的,因为您可以修改它们的属性,并且这些更改会反映在类之外。即,对象不会以原语的方式复制。

但是我们可以写下这个:

function f2($obj) {
    $obj = new C(2);
}


$b = new C(1);
f2($b);
echo $b; // 1

现在建议该对象根本不通过引用传递。实际上,对象被复制(即通过值传递)但不是 - 复制; $obj已被复制,但$x仍指同一件事。

我听说“参考”这个词曾经意味着两种方式;有人会说PHP是通过引用传递的,有些人会说传递值。

如果我们说PHP是通过引用传递的,那么在定义像

这样的函数时我们的意思是什么
function f3(&$obj)

那个函数对一个对象进行引用,这表明第一个意思是错误的。

但那么像C ++这样的语言和C#中的结构呢?我的C ++有点生疏,但我相信整个类在传递它时实际上会被深层复制,这就是为什么鼓励你的函数在可能的情况下使用引用,或使用指针。在C#中,结构和类之间的区别在于它们如何通过。

如果不按值传递,您称之为深度复制行为是什么?

似乎我们有3个行为,只有两个短语来描述它们,这在社区中造成了很多混乱。

哎呀,我只是在等你们其中一个人告诉我,我在这里写错了。


总之,这三种行为是:

  1. 对象被深度复制(克隆对象及其属性)
  2. 仅复制对象(其属性仍引用相同的内存块)
  3. 根本不会复制该对象
  4. 从技术上讲,我们应该将这些行为称为什么?传递通过 - ???

4 个答案:

答案 0 :(得分:2)

首先要做的事情:您可能想阅读References Explained


通常,变量总是按值传递。重要的是价值实际上是什么。

如果变量“持有一个对象”,它将持有对象的引用

因此,当你有一个像

这样的函数定义时
function foo($bar) {}

传递对象的引用。这就是你可以改变对象的原因。

但是如果你为函数内部的变量赋一个新值,那么你只是用其他东西覆盖了引用,你就失去了对象的引用。

假设您传递给函数的变量$someVar$bar$someVar将具有相同的值(即引用),但它们在存储器中。

在:

$someVar -> object_reference  ┐

                              ├ -> object

$bar     -> object_reference  ┘

后:

$someVar -> object_reference  -> object



$bar     -> other_value

现在,如果函数定义类似于

function foo(&$bar) {}

然后你实际上传递了一个引用到内存中某个其他变量的位置

如果您使用foo($someVar)调用此函数,$bar将指向与$someVar相同的位置,即如果您指定了新值,则会覆盖内存中的特定位置

在:

$someVar  ┐

          ├ ->  object_reference -> object

$bar      ┘

后:

$someVar  ┐

          ├ ->  other_value         object

$bar      ┘

答案 1 :(得分:1)

如果我有我的druthers,.net中的术语“对象引用”将被替换为类似“object-id”的东西,以明确在大多数情况下将对象传递给例程时,object-id是按值传递的(尽管在某些情况下,例如Dictionary.TryGetValue,其中object-id通过引用传递)。使用相同的术语来描述对象id和一种参数传递会导致混淆。

答案 2 :(得分:1)

在C ++中,前两个都被称为pass-by-value。深层复制的深度取决于所讨论的类的复制语义,它可以并且应该由程序员指定(某些类是资源的句柄,必须浅层复制;其他类,如大多数容器,必须深-copied)。 Python具有用于深度和浅层复制的库函数。深度复制有时称为克隆,尤其是克隆。在C ++和Java中。

第三个被称为传递参考。这是传递可以被被调用者就地修改的东西的通用术语。

(C是这个约定的一个例外,因为它没有引用的概念,但是pass-by-pointer几乎与pass-by-reference相同。)

答案 3 :(得分:0)

您必须区分两件事:对变量的引用和对象的引用。只要您不为参数$ obj指定其他值,就会处理与函数外部完全相同的对象。在为其分配了另一个对象之后,变量已经更改,但由于您只传递了对象的引用而没有传递给变量,因此外部的变量仍未触及指向原始对象...