Even if a copy of the array was made by foreach i should be getting AAAA but not getting that in the current PHP stable version
Since I found no answer to this question here, I'll (try to) explain.
Before the first iteration of foreach
$list
is not actually copied. Only reference counting of $list
will be increased to 2. So on the first iteration: first value of $list
will be copied in $var
, pointer will move to the second element of $list
and actual copy of $list
will be made. So when you call current
pointer points to second element but on the second and farther iterations it's never modified because actual copy of $list
exists so current
always will output the second element.
Edit:
I've played with debug_zval_dump
to understand this really very unexpected behavior with:
Ref count before entering foreach:
';
debug_zval_dump($list); echo '
';
$i = 0;
echo 'Ref count in foreach:
';
foreach ($list as $var) {
$i++;
echo 'Iteration #'.$i.': ';
debug_zval_dump($list);
echo '
';
}
$list = array("A", "B", "C","D"); //re-assign array to avoid confusion
echo 'Ref count before entering foreach that calls method "item" and passes array by value:
';
debug_zval_dump($list);
$i = 0;
echo 'Ref count in foreach that calls method "item" and passes array by value:
';
foreach ( $list as $var ) {
$i++;
item($list, $i);
}
function item($list, $i) {
echo 'Iteration #'.$i.': ';
debug_zval_dump($list);
}
$list = array("A", "B", "C","D"); //re-assign array to avoid confusion
echo 'Ref count before entering foreach that calls method "item" and passes array by reference:
';
debug_zval_dump($list);
$i = 0;
echo 'Ref count in foreach that calls method "item" and passes array by reference:
';
foreach ( $list as $var ) {
$i++;
itemWithRef($list, $i);
}
function itemWithRef(&$list, $i) {
echo 'Iteration #'.$i.': ';
debug_zval_dump($list);
}
And got the following output:
Ref count before entering foreach:
array(4) refcount(2){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(1)
}
Ref count in foreach:
Iteration #1: array(4) refcount(3){
[0]=>
string(1) "A" refcount(2)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(1)
}
Iteration #2: array(4) refcount(3){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(2)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(1)
}
Iteration #3: array(4) refcount(3){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(2)
[3]=>
string(1) "D" refcount(1)
}
Iteration #4: array(4) refcount(3){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(2)
}
Ref count before entering foreach that calls method "item" and passes array by value:
array(4) refcount(2){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(1)
}
Ref count in foreach that calls method "item" and passes array by value:
Iteration #1: array(4) refcount(5){
[0]=>
string(1) "A" refcount(2)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(1)
}
Iteration #2: array(4) refcount(5){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(2)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(1)
}
Iteration #3: array(4) refcount(5){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(2)
[3]=>
string(1) "D" refcount(1)
}
Iteration #4: array(4) refcount(5){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(2)
}
Ref count before entering foreach that calls method "item" and passes array by reference:
array(4) refcount(2){
[0]=>
string(1) "A" refcount(1)
[1]=>
string(1) "B" refcount(1)
[2]=>
string(1) "C" refcount(1)
[3]=>
string(1) "D" refcount(1)
}
Ref count in foreach that calls method "item" and passes array by reference:
Iteration #1: array(4) refcount(1){
[0]=>
string(1) "A" refcount(4)
[1]=>
string(1) "B" refcount(3)
[2]=>
string(1) "C" refcount(3)
[3]=>
string(1) "D" refcount(3)
}
Iteration #2: array(4) refcount(1){
[0]=>
string(1) "A" refcount(3)
[1]=>
string(1) "B" refcount(4)
[2]=>
string(1) "C" refcount(3)
[3]=>
string(1) "D" refcount(3)
}
Iteration #3: array(4) refcount(1){
[0]=>
string(1) "A" refcount(3)
[1]=>
string(1) "B" refcount(3)
[2]=>
string(1) "C" refcount(4)
[3]=>
string(1) "D" refcount(3)
}
Iteration #4: array(4) refcount(1){
[0]=>
string(1) "A" refcount(3)
[1]=>
string(1) "B" refcount(3)
[2]=>
string(1) "C" refcount(3)
[3]=>
string(1) "D" refcount(4)
}
The output is little bit confusing.
In first example foreach
has created internal copy of $list
so reference count was 2 (4 in the result because debug_zval_dump
adds one refCount
). In the second example (pass by value) refCount
increased to 3, because $list
was copied for function. In the third example count kept to 1 because $list
was passed by value. I need some time to realize why. If you get the point out of this result share.
All I can say is that when we passed array by value foreach
was passing array that was iterating, but when passed by reference it took the original $list
. The question is: why was foreach
passing that array?