PHP - 常规foreach使用copy,但是如果IteratorAggregate对象在其组件对象数组上循环呢?

时间:2014-07-08 22:06:43

标签: php foreach iterator unset

PHP说取消设置临时foreach变量以防止出现一些问题。但对于像这样的对象集合,它不会取消集合中的原始对象吗?或者不是?

内置的IteratorAggregate接口允许您指定如何在foreach循环中处理类对象。这里,“collection”类为foreach循环提供了$ things数组的thing个对象。在执行foreach($collection as $thing)时,每个$ thing将是$ collection的$ things数组中的thing对象。

class collection implements IteratorAggregate {
  protected $things = array();
  public function addAThing(thing $thing) {
    $this->things[$thing->getId()] = $thing;
  }
  /**
  * For IteratorAggregate
  */
  public function getIterator() {
    return new ArrayIterator($this->things);
  }
}

class thing {
  $number = 0;
  public function __construct($number) {
    $this->number = (int)$number;
  }
  public function getNumber() {
    return $this->number;
  }
}


$coll = new collection();
$coll->addAThing(new thing(1));
$coll->addAThing(new thing(3));
$coll->addAThing(new thing(4));
$coll->addAThing(new thing(24));

foreach($coll as $thing) {
  echo $thing->getNumber();
}
unset($thing); // To unset, or not to unset?

2 个答案:

答案 0 :(得分:1)

每个循环都会将一个新对象放入$thing,这意味着先前的$thing将被孤立并最终被PHP收集垃圾。

垃圾收集是一项昂贵的工作,通常你不应该强迫PHP去做 - 当它认为内存可能越来越紧时它会自己做。可能有一些原因导致PHP猜错了,或者你知道一个内存昂贵/时间关键的操作即将出现并且想要确保它没有被垃圾收集运行暂停。


评论后续:

取消设置引用并不会取消引用指向的原始内容:

php > $x = 7;
php > $y = &$x;
php > var_dump($x, $y);
int(7)
int(7)
php > unset($y);
php > var_dump($x, $y);
PHP Notice:  Undefined variable: y in php shell code on line 1
int(7)
NULL

请注意$ x是否仍然存在且具有原始值。然而,$ y已经消失了。这同样适用于foreach循环中的引用:

php > $x = array(1,2,3);
php > foreach($x as $y) { if ($y == 2) { unset($y); } } // no references here
php > var_dump($x);
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

php > foreach($x as &$y) { if ($y == 2) { unset($y); } }  // note: $y is now a reference
php > var_dump($x);
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  &int(3)
}

请注意,2元素再次未从原始数组中删除。这同样适用于对象/更复杂的事物:

php > $x = array(new StdClass(), new StdClass());
php > foreach($x as $y) { unset($y); }
php > var_dump($x);
array(2) {
  [0]=>
  object(stdClass)#1 (0) {
  }
  [1]=>
  object(stdClass)#2 (0) {
  }
}
php > var_dump($y);
PHP Notice:  Undefined variable: y in php shell code on line 1
NULL
php > foreach($x as $y) { /* do nothing */ }
php > var_dump($x, $y);
array(2) {
  [0]=>
  object(stdClass)#1 (0) {
  }
  [1]=>
  object(stdClass)#2 (0) {
  }
}
object(stdClass)#2 (0) {
}
php > unset($y);
php > var_dump($x, $y);
PHP Notice:  Undefined variable: y in php shell code on line 1
array(2) {
  [0]=>
  object(stdClass)#1 (0) {
  }
  [1]=>
  object(stdClass)#2 (0) {
  }
}
NULL

答案 1 :(得分:0)

关于foreach的推荐仅供参考。

http://php.net/manual/en/control-structures.foreach.php

foreach (array(1, 2, 3, 4) as &$value) {
    $value = $value * 2;
}
  

警告

     

$ value的引用和最后一个数组元素仍然保留在   foreach循环。建议通过unset()来销毁它。

Some explanation why

您的代码没有引用,您不必取消设置临时变量。

P.S。你知道,重读后,我认为你的问题不正确。听起来像#34; php有功能,我应该使用它吗?"。 Unset只是语言的一部分,您必须决定在哪里使用它。你已经掌握了常见的“陷阱”和#34;参考和foreach。但即使在我的例子中使用或不使用取决于任务。例如:循环后需要change last value。如果没有设置,你需要额外的行和额外的函数调用。

$array = array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
foreach ($array as &$value) {
    $value = $value * 2;
}
unset($value);
end($array);
$key = key($array);
$array[$key]++;

Whitout未设置你只需要改变价值。

$array = array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
foreach ($array as &$value) {
    $value = $value * 2;
}
$value++;