在PHP中有人可以解释克隆与指针引用吗?

时间:2010-08-31 18:22:01

标签: php reference clone

首先,我理解编程和对象,但以下对我来说对PHP没有多大意义。

在PHP中我们使用&运算符以检索对变量的引用。我理解一个引用是一种用不同变量引用相同“事物”的方法。如果我说例如

$b = 1;
$a =& $b;
$a = 3;
echo $b;

将输出3,因为对$ a的更改与对$ b的更改相同。相反地​​:

$b = 1;
$a = $b;
$a = 3;
echo $b;

应输出1。

如果是这种情况,为什么需要克隆关键字?在我看来,如果我设置

$obj_a = $obj_b然后对$ obj_a所做的更改不应影响$ obj_b, 相反,$ obj_a =& $ obj_b应指向同一个对象,因此对$ obj_a所做的更改会影响$ obj_b。

然而,在PHP中,似乎$ obj_a DO上的某些操作会影响$ obj_b,即使在没有引用运算符($obj_a = $obj_b)的情况下进行了分配也是如此。这对我今天在使用DateTime对象时造成了令人沮丧的问题,我最终基本上已经修复了这些对象:

$obj_a = clone $obj_b

但我编写的大多数PHP代码似乎都不需要像这种情况那样进行显式克隆,没有它就可以正常工作。这里发生了什么?为什么PHP必须如此笨重?

3 个答案:

答案 0 :(得分:44)

基本上,PHP中有两种变量工作方式......

除了对象之外的所有内容:

  1. 分配是按值(意味着如果您执行$a = $b则会发生复制。
  2. 可以通过$a = &$b来实现参考(注意引用运算符对变量进行操作,而不是赋值运算符,因为您可以在其他地方使用它)...
  3. 副本使用copy-on-write tehnique。因此,如果执行$a = $b,则不存在变量的内存副本。但是如果你再做$a = 5;,那么就会复制内存并覆盖它。
  4. 对象:

    1. 分配是通过对象引用。它与正常变量的引用并不相同(我将在后面解释原因)。
    2. 可以通过$a = clone $b来实现按值复制。
    3. 可以通过$a = &$b来实现参考,但要注意这与对象无关。您将$a变量绑定到$b变量。如果它是一个对象并不重要。
    4. 那么,为什么对象的赋值不能真正引用?如果您这样做会发生什么:

      $a = new stdclass();
      $b = $a;
      $a = 4;
      

      什么是$b?好吧,它是stdclass ......那是因为它不是写变量的引用,而是写对象......

      $a = new stdclass();
      $a->foo = 'bar';
      $b = $a;
      $b->foo = 'baz';
      

      什么是$a->foo?它是baz。那是因为当你做$b = $a时,你告诉PHP使用相同的对象实例(因此对象引用)。请注意,$a$b不是同一个变量,但它们都引用同一个对象。

      考虑它的一种方法是考虑将对象存储为存储指向该对象的指针的所有变量。所以对象住在其他地方。当您分配$a = $b $b是一个对象时,您所做的就是复制该指针。实际变量仍然是不相交的。但是当你执行$a = &$b时,你会在$b内存储指向$a的指针。现在,当你操纵$a时,它将指针链级联到基础对象。当您使用clone运算符时,您告诉PHP复制现有对象,并创建一个具有相同状态的新对象...所以clone实际上只是一个副本值的副本varaible ...

      所以如果你注意到,我说对象没有存储在实际变量中。它存储在其他地方,只有指针存储在变量中。所以这意味着您可以拥有(并且经常会有)多个指向同一实例的变量。因此,内部对象表示包含refcount(简单地指向指向它的变量数)。当一个对象的引用计数降为0(意味着指向它的所有变量都超出范围,或者更改为其他一些)时,它会被收集(因为它不再可访问)...

      您可以在references and PHP in the docs...

      上阅读更多内容

      免责声明:其中一些可能过于简单化或模糊某些概念。我打算这只是一个指导它们如何工作的指南,而不是内部发生的事情的确切细分......

      编辑:哦,至于这个“笨重”,我认为不是。我认为这非常有用。否则你会在整个地方传递变量引用。当应用程序的一个部分中的变量影响应用程序另一部分中的另一个变量时,这会产生一些非常有趣的错误。并不是因为它已经通过了,而是因为参考是在某条线上进行的。

      一般来说,我不太多使用变量引用。我很少找到他们的诚实需求。但我确实一直使用对象引用。我非常使用它们,我很高兴他们是默认的。否则我需要编写一些运算符(因为&表示变量引用,需要另一个表示对象引用)。考虑到我很少使用clone,我会说99.9%的用例应该使用对象引用(所以让运算符用于较低频率的情况)...

      JMHO

      我还创建了一个解释这些差异的视频。请查看on YouTube

答案 1 :(得分:4)

简而言之:

在PHP 5+对象中通过引用传递。在PHP 4中,它们通过值传递(这就是为什么它通过引用传递运行时,它被弃用)。所以, 使用PHP5中的clone运算符来复制对象:

$objectB = clone $objectA;

另请注意,它只是通过引用传递的对象,而不是其他变量。以下内容可能会让您了解更多信息:

答案 2 :(得分:2)

我写了一个演示文稿来更好地解释php如何使用变量管理内存:

https://docs.google.com/presentation/d/1HAIdvSqK0owrU-uUMjwMWSD80H-2IblTlacVcBs2b0k/pub?start=false&loop=false&delayms=3000

看看;)