4

我对通过引用传递在 PHP 中的工作方式有一点普遍的不满,我自己来自 Java 背景。这可能已经在 SO 上讨论过,所以如果这看起来多余,我很抱歉。

我将给出一个代码示例以使事情清楚。假设我们有一个 Person 类:

<?php

class Person 
{
    private $name;

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

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }
}

?>

以及以下用法:

<?php

require_once __DIR__ . '/Person.php';

function changeName(Person $person)
{
    $person->setName("Michael");
}

function changePerson(Person $person)
{
    $person = new Person("Jerry");
}

$person = new Person("John");

changeName($person);
echo $person->getName() . PHP_EOL;

changePerson($person);
echo $person->getName() . PHP_EOL;

?>

现在,我和其他许多从 Java 或 C# 编程到 PHP 的人都希望上面的代码能够输出:

Michael
Jerry

但是,它没有,它输出:

Michael
Michael

我知道它可以通过使用 & 来修复。通过调查,我了解到这是因为引用是按值(引用的副本)传递给函数的。但这对我来说构成了一种意外/不一致的行为,所以问题是:他们选择这样做有什么特别的原因或好处吗?

4

2 回答 2

2

对象本身实际上是通过引用传递的,否则你的第一个echo不会输出Michael

在您的第二个示例中发生的情况是您破坏了对原始对象的(本地)引用,并让您的变量名引用了一个在函数中具有本地范围的新对象。

这对我来说很有意义,因为您可以通过简单地为函数中的变量分配一个新值来用完全不同的东西破坏/替换您的对象。

于 2012-12-06T16:21:09.390 回答
1

如果以这种方式使用,您的代码将按预期工作:

function changePerson(Person &$person) // <- & to state the reference
{
    $person = new Person("Jerry");
}

$person = new Person("John");

changeName($person);
echo $person->getName() . PHP_EOL;

changePerson($person);
echo $person->getName() . PHP_EOL;

查看输出:http ://codepad.org/eSt4Xcpr

经常提到的 PHP 5 OOP 的关键点之一是“对象默认通过引用传递”。这并不完全正确。

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

引自http://php.net/manual/en/language.oop5.references.php

于 2012-12-06T16:36:59.403 回答