【问题标题】:How do i clone an ArrayIterator in PHP?如何在 PHP 中克隆 ArrayIterator?
【发布时间】:2016-03-31 19:27:32
【问题描述】:

我正在尝试克隆一个 \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();

有人对此行为有解释吗?提前谢谢你。

【问题讨论】:

    标签: php clone arrayiterator


    【解决方案1】:

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

    documentation on clone 这么说

    PHP 5 将对对象的所有属性执行浅拷贝。任何引用其他变量的属性都将保持引用。

    所以当你cloneArrayIterator 对象时,新克隆的对象包含对与原始对象相同的数组的引用。 Here is an old bug report 其中这种行为被称为预期行为。

    如果您想复制 ArrayIterator 的当前状态,您可以考虑使用数组 returned by getArrayCopy() 来实例化一个新状态

    $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() 将指针推进到所需位置。 Here is a thorough answer explaining how that could be done.

    【讨论】:

    • 我也在寻找相同的文档,但正如它所说 Warning This function is currently not documented; only its argument list is available. 我也在考虑同样的参考问题,正如你所解释的,“'持有的数组必须是对数组的引用而不是直接存储在对象中的数组本身。”但是在测试自己之后,我发现它不是指一些外部数组。但是它将数组存储在内部,然后在克隆时将其作为参考。我不知道它的实际原因,但基于这种情况,上面的句子不是 100% 准确的。
    • 你可以用这个来测试它,$myArray = array('m'); $list = new ArrayIterator($myArray);(稍后你会看到,ArrayIterator 不会影响原来的$myArray,因为它是未来的操作。)
    • 我也测试过——引用不是对传递给迭代器的原始数组变量的引用——它是对数组的内部引用,否则 PHP 代码无法访问,从传递给迭代器。如果它是对 original 变量的引用,那会使迭代器的状态可能不一致。
    • 我希望能够使用 ReflectionProperty 对其进行检查,但在内部类上似乎无法检索私有属性。无论如何,我链接的那个错误报告确实清楚地表明了这种行为是有意的。 "如果你克隆了一个 ArrayIterator,你也克隆了它的引用,因此下面描述的行为是正确的。"
    【解决方案2】:

    完成之前所说的,如果你想克隆一个从ArrayIterator继承的类,你可以使用这个方法来自动克隆存储的数组:

    public function __clone(){
        parent::__construct($this->getArrayCopy());
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-16
      • 2012-09-18
      • 2017-08-15
      • 2011-09-19
      • 2012-09-06
      • 2017-09-17
      • 2012-10-04
      • 2017-07-30
      • 2012-12-02
      相关资源
      最近更新 更多