Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do i clone an ArrayIterator in PHP?

I am trying to clone an \ArrayIterator object, but it seems like the cloned one is still referencing to the original one.

$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();

Anyone have explanation to this behavior? Thank you in advance.

like image 421
Eimihar Avatar asked Sep 02 '25 04:09

Eimihar


2 Answers

Though I am having difficulty locating documentation that explicitly says so, internally ArrayIterator's private $storage property wherein the array is held must be a reference to an array rather than the array itself directly stored within the object.

The documentation on clone says that

PHP 5 will perform a shallow copy of all of the object's properties. Any properties that are references to other variables will remain references.

So when you clone the ArrayIterator object, the newly cloned object contains a reference to the same array as the original one. Here is an old bug report wherein this behavior is said to be the expected behavior.

If you want to copy the current state of an ArrayIterator, you might consider instead instantiating a new one using the array 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)
  }
}

The above is a simple operation though, and only creates a new ArrayIterator with the currently stored array as the original. It does not maintain the current iteration state. To do that, you would need to also call seek() to advance the pointer to the desired position. Here is a thorough answer explaining how that could be done.

like image 113
Michael Berkowski Avatar answered Sep 05 '25 01:09

Michael Berkowski


Completing what has been said before, if you are trying to clone a class that inherits from ArrayIterator, you can use this method in order to automatically clone the stored array :

public function __clone(){
    parent::__construct($this->getArrayCopy());
}
like image 30
Estecka Avatar answered Sep 04 '25 23:09

Estecka