【问题标题】:so how does passing by reference in php REALLY work?那么在 php 中通过引用传递是如何真正起作用的呢?
【发布时间】:2011-05-31 10:02:31
【问题描述】:

非常简单的问题,但不是要求学术解释,我想尽可能务实:PHP 什么时候会创建我传递给函数的巨大类的副本,什么时候会简单地创建一个指向相关数据?如果它一直创建指针,那么指定 & 有什么用(显然,除了闭包)?我想我对口译员的胆量了解不够。

【问题讨论】:

标签: php pointers reference pass-by-reference interpreter


【解决方案1】:

& 运算符表示通过引用传递的变量。

$x = 'Hello World';
echo($x);

function asdf(&$var){
  $var = 'Test';
}

asdf($x);
echo($x);

赋值和几乎任何其他语句也是如此。如果它不是通过引用传递或分配的,则假定它是通过值传递或分配的。

【讨论】:

  • 谢谢。我想我更感兴趣的不是值是否会改变,而是我是否会因为该对象被复制而降低效率。离开之前发布的链接,我想知道这是否真的有很大的不同,因为 PHP 是“写时复制”
  • 使用microtime() 测试复制对象所需的时间与通过引用传递对象所需的时间。我真的不认为它有很大的不同,至少对于我创建的较小对象来说,它所花费的时间可以忽略不计。更大的问题更多在于功能而不是执行时间。
  • 知道了,会做的。感谢您的帮助!
  • 没问题。告诉我进展如何。
【解决方案2】:

尽管你可以随心所欲地使用 &,但为什么要打扰 &。我就是这样做的:

假设我有一个类“Book”,其中包含一些公共方法和属性,如标题、作者、年份 然后简单地制作一个对象:

$book = new Book()
// then I can use all public methods and properties

$book->title;

$book->author;

$book->year;

如果我愿意,我可以创建一个子类

class Novel extends Books{

  function buildIt(Book $bk){

      $bk->title;

      // so on 

  }

}

在函数 buildIt 中,我故意有一个 Book 'parameter' 的类对象,其中 我可以传递“Book”类的整个对象。

希望对你有所帮助。

【讨论】:

  • 当然,我想我的问题是,当您引用 $bk->title 时,是否已将其复制到一个新的临时 Book 中,其中包含一个全新的 $title 在内存中可以更改但无效在原始 Book 对象上,如果是这种情况,复制对象对性能有影响吗?
  • 默认情况下对象是通过引用传递的,这就是为什么它在您的示例中没有意义。但是,当传递原始数据类型(例如:整数、字符串等)时,它就派上用场了。
【解决方案3】:

在 PHP 5 中,所有对象都通过它们的句柄传递。是否通过引用传递与性能无关。 (实际上,手册中警告通过引用传递会较慢。)您在函数内部处理的对象与指向函数外部的对象相同。

当您通过引用传递对象(句柄)时,您可以更改外部变量指向的内容。这几乎总是不必要的。

【讨论】:

  • 为了清楚起见,我只说对象。 PHP 确实传递了所有其他数据类型(字符串等)的副本。但是,只有在您修改数据时才会实际发生复制。同样,引用通常不会“更快”。它们的真正目的是当您需要修改调用范围内的变量实际指向的内容时。因此,除非您需要特定的行为,否则我通常会避免使用它们。
【解决方案4】:

您可以在 PHP 手册中找到很多通过引用传递变量的用法。最好的例子之一是preg_match

preg_match 将返回模式在输入字符串中匹配的次数。然后,如果提供,它将填充包含匹配项的引用 $matches 数组。

它可以被视为一种返回多个值的方法,尽管你应该小心。举例:

class Server {

    protected $_clientId = 0;

    protected $_clients = array();

    /**
     * Get a pending connection.
     *
     * @param &$connection_id int The connection identifier.
     * @return resource The socket resource.
     */
    public function getNextClient(&$connection_id) {
        $clientSocket = socket_accept($this->_server);     
        $connection_id = $this->_clientId++; 
        $this->_clients[$connection_id] = $clientSocket;
        return $clientSocket;
    }

}

$server = new Server;
$socket1 = $server->getNextClient($id);
echo $id; // 0
$socket2 = $server->getNextClient($id);
echo $id; // 1

重要提示。默认情况下,对象是通过引用传递的。 它们不会被克隆。即使没有在函数参数中指定&,修改传递的对象也会导致原始对象也被修改。防止这种情况的唯一方法是在函数/方法中克隆对象。

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 1970-01-01
    • 2012-02-10
    • 2010-11-16
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    相关资源
    最近更新 更多