When using PHP 5.5.9 and given this example test class:
class Test
implements Iterator
{
private $ar = [ 1, 2, 3 ];
public function toArray() {
return $this->ar;
}
public function rewind() {
reset( $this->ar );
}
public function valid() {
return !is_null( $this->key() );
}
public function key() {
return key( $this->ar );
}
public function current() {
return current( $this->ar );
}
public function next() {
next( $this->ar );
}
}
and executing this example test:
$t = new Test;
foreach( $t as $key => $value ) {
echo "orig: $key: $value\n";
// work on the immediate method result
foreach( $t->toArray() as $copyKey => $copyValue ) {
echo " copy: $copyKey: $copyValue\n";
}
echo "----\n";
}
I get the following result:
orig: 0: 1
copy: 0: 1
copy: 1: 2
copy: 2: 3
----
It appears as though the inner foreach
loop is working on a reference to the internal member $ar
of Test
and advancing its internal pointer, when I expect $t->toArray()
to give me a copy of the internal member $ar
of Test
.
Since my understanding was that PHP always copies arrays, certainly when returned from a method, I expected the following result:
orig: 0: 1
copy: 0: 1
copy: 1: 2
copy: 2: 3
----
orig: 1: 2
copy: 0: 1
copy: 1: 2
copy: 2: 3
----
orig: 2: 3
copy: 0: 1
copy: 1: 2
copy: 2: 3
----
When I make an explicit copy of the array, before the inner foreach
loop, with:
// store method result in variable first
$a = $t->toArray();
foreach( $a as $copyKey => $copyValue ) { /* etc. */ }
Or change the toArray()
method to:
public function toArray() {
$copy = $this->ar; // this alone won't work
reset( $copy ); // this is what is needed to do the trick
return $copy;
}
I do get the expected result.
What is going on here? Is this expected behavior? Am I overlooking something vital here?
Apparently this behavior disappeared in PHP 7.0.0: