PHP:为什么两个类实例共享相同的数据?

时间:2013-10-28 10:43:01

标签: php oop

早上好,

我似乎是我自己代码的代码盲,所以如果几周前写的话,我想就一段代码问一些额外的眼睛和建议。

守则(缩短)

class TrackingCostCollection {
  private $available=0;
  private $ordered=0;
  private $differenceNumKits=0;

  public function fill ($row) {
    ...
  }

  /**
  * @var TrackingCostCollection $collection
  */
  public function merge ($collection) {

    $this->available += $collection->available;
    $this->ordered += $collection->ordered;
    $this->differenceNumKits= $this->available-$this->ordered;
  }
}

问题

当通过其中一个数据字段迭代和分组数据时,我遇到了两个不同数组中存储的两个不同类实例包含相同数据的问题,尽管我不明白为什么?一旦我使用额外的“克隆”,问题就会消失,但我想知道为什么我的代码的行为方式如下:

foreach ($arrValues as $row) {
  ...
  $this->calculateStatistics($row);

}


private function calculateStatistics ($row) {
  $fieldValue= $row['country'];
  $collection = new TrackingCostCollection();
  $collection->fill($row);

  if (!isset($this->arrStatistics[$fieldValue])) {
    $this->arrStatistics[$fieldValue] = $collection2;
  } else {
    /* @var TrackingCostCollection $previousCollection2 */
    $previousCollection = $this->arrStatistics[$fieldValue];
    $previousCollection->merge($collection2);
    $this->arrStatistics[$fieldValue] = $previousCollection;
    unset($previousCollection);
  }

  // using $collection instead of $collection2 will cause 
  // two array entries containing the same data

  $collection2= clone $collection;
  if (!isset($this->arrTotals[$fieldValue])) {
    $this->arrTotals[$fieldValue] = $collection2;
  } else {
    /* @var TrackingCostCollection $previousCollection2 */
    $previousCollection = $this->arrTotals[$fieldValue];
    $previousCollection->merge($collection2);
    $this->arrTotals[$fieldValue] = $previousCollection;
    unset($previousCollection);
  }
}

如果需要更多代码来诊断问题的原因,请告诉我,我会添加更多。

非常感谢你的时间!

1 个答案:

答案 0 :(得分:1)

我承认没有详细介绍您的代码,但我想您遇到了问题:

  

[...]对象变量不包含对象本身作为值[...]。它只包含一个对象标识符,允许对象访问者查找实际对象。当一个对象通过参数发送,返回或分配给另一个变量时,不同的变量[...]会保存一个标识符的副本,该标识符指向同一个对象。

     

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

如果要制作一个对象的两个独立副本,则需要clone它。如果不这样做,那么您将传递相同的对象,并且传递此对象的任何人都可以看到对它的修改。 E.g:

$obj = new stdClass;
$obj->foo = 'bar';

function modify(stdClass $obj) {
    $obj->foo = 'baz';
}

modify($obj);

echo $obj->foo; // baz