如何在PHP中克隆一个ArrayIterator?

4
我试图克隆一个 \ArrayIterator 对象,但克隆的对象好像仍然指向原始对象。
$list = new \ArrayIterator;
$list->append('a');
$list->append('b');

$list2 = clone $list;
$list2->append('c');
$list2->append('d');

// below result prints '4', i am expecting result '2'
echo $list->count();

有人对这种行为有解释吗?提前谢谢您。
2个回答

7
尽管我很难找到明确说明的文档,但内部 ArrayIterator 的私有 $storage 属性(其中包含数组)必须是对数组的引用,而不是直接存储在对象中的数组本身。 clone 的文档 表示:

PHP 5 将执行所有对象属性的浅层复制。任何作为其他变量引用的属性都将保持引用。

因此,当你克隆 ArrayIterator 对象时,新克隆的对象包含对与原始对象相同的数组的引用。 这里有一个旧的错误报告,其中说这种行为是预期的行为。
如果你想复制一个 ArrayIterator 的当前状态,可能可以考虑使用 getArrayCopy() 返回的数组 实例化一个新的 ArrayIterator
$iter = new \ArrayIterator([1,2,3,4,5]);

// Copy out the array to instantiate a new one
$copy = new \ArrayIterator($iter->getArrayCopy());
// Modify it
$copy->append(6);

var_dump($iter); // unmodified
php > var_dump($iter);
class ArrayIterator#1 (1) {
  private $storage =>
  array(5) {
    [0] =>
    int(1)
    [1] =>
    int(2)
    [2] =>
    int(3)
    [3] =>
    int(4)
    [4] =>
    int(5)
  }
}

var_dump($copy); // modified
class ArrayIterator#2 (1) {
  private $storage =>
  array(6) {
    [0] =>
    int(1)
    [1] =>
    int(2)
    [2] =>
    int(3)
    [3] =>
    int(4)
    [4] =>
    int(5)
    [5] =>
    int(6)
  }
}

上面的操作虽然简单,只是使用当前存储的数组作为原始数据创建了一个新的ArrayIterator。它不会维护当前的迭代状态。如果要维护迭代状态,您还需要调用seek()将指针移动到所需位置。这里有一个详细的答案,解释如何实现

我也在寻找同样的文档,但是它说警告:此函数目前没有记录;只有其参数列表可用。我也考虑了同样的参考问题,就像你解释的那样,"数组所持有的必须是一个对数组的引用,而不是直接存储在对象中的数组本身。"但是经过我的测试,我发现它并没有引用任何外部数组。相反,它将数组存储在内部,然后在克隆时将其保留为引用。我不知道实际原因是什么,但基于这种情况,上面的句子并不是100%准确的。 - Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ
你可以使用以下代码进行测试:$myArray = array('m'); $list = new ArrayIterator($myArray); (稍后您将看到,ArrayIterator不会影响原始的$myArray以供未来操作使用。) - Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ
我也测试过了 - 引用不是指向传递给迭代器的原始数组变量 - 它是对一个对 PHP 代码不可访问的内部数组的引用,该内部数组是从传递给迭代器的数组变量复制而来。如果它是对 原始 变量的引用,那么迭代器的状态可能会不一致。 - Michael Berkowski
1
我希望能够使用ReflectionProperty来检查它,但在内部类上似乎无法检索私有属性。无论如何,我链接的那个错误报告清楚地说明了这种行为是有意的。"如果你克隆一个ArrayIterator,你也会克隆它的引用,因此下面描述的行为是正确的。" - Michael Berkowski

1
完成之前的讲解,如果你试图克隆一个从ArrayIterator继承的类,你可以使用这个方法来自动克隆存储的数组:
public function __clone(){
    parent::__construct($this->getArrayCopy());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接