If you've seen PHP-related books, you'll learn that PHP has this feature: copy when you write. So when you use foreach, you need to make changes to the data, will copy the data, if the data is very large, then will bring a certain amount of memory consumption, so in order to avoid this copy operation, the use of the reference, the following reference to the pit
Problem Cases
<?php
$arr = Array (4, 5, 6);
Var_dump ($arr);
foreach ($arr as & $v) {
Do something here
}
foreach ($arr as $v) {
Do something here
}
Var_dump ($arr);
?>
The output is:
Array (3) {
[0]=>
Int (4)
[1]=>
Int (5)
[2]=>
Int (6)
}
Array (3) {
[0]=>
Int (4)
[1]=>
Int (5)
[2]=>
&int (5)
}
Problem analysis
It's fine not to use a reference in foreach, $k => $v and then $ar [$k] To change the original array, slightly losing some of the efficiency.
When you execute the first foreach that uses a reference:
At first, $v point to the storage space $arr [0], where 4 is stored, and at the end of foreach, $v points to the storage space of $arr [2], which stores 6 of the space.
When you start a second foreach:
Note that unlike the first foreach, the second foreach does not use a reference, it is the assignment, which assigns the value of the $arr to the $v in turn. When you go to the first element, you assign the $ar [0] to the $v. The problem is right here, since the first foreach has just been executed, $v is not a new variable, but a reference that already exists that points to $arr [2], so that when the $v is assigned, $arr [0] = 4 is written to the actual storage space $arr [2], which is quite To assign to the $arr [2]. So, the result of the second foreach execution is that the last element of the array becomes the value of the penultimate element.
PHP developers also believe that this situation is caused by language features, not bugs. One way to fix this problem is to do a special deal with foreach and to limit the scope of $v in foreach, both of which are inconsistent with the current language features of PHP, which developers do not want to change, but are described in the official documentation with Warning.
Solution
The easy way to do this is to unset off the $v after using the referenced foreach
Modified Case:
<?php
$arr = Array (4, 5, 6);
Var_dump ($arr);
foreach ($arr as & $v) {
Do something here
}
Unset ($v);
foreach ($arr as $v) {
Do something here
}
Var_dump ($arr);
?>
Output:
Array (3) {
[0]=>
Int (4)
[1]=>
Int (5)
[2]=>
Int (6)
}
Array (3) {
[0]=>
Int (4)
[1]=>
Int (5)
[2]=>
Int (6)
}
Add:
foreach is simple, but it may cause unexpected behavior, especially if the code involves references.
Here are a few examples to help us further understand the nature of foreach
$arr = Array (1,2,3);
foreach ($arr as $k => & $v) {
$v = $v * 2;
}
Now $arr are array (2, 4, 6)
foreach ($arr as $k => $v) {
echo "$k", "=>", "$v";
}
First from the simple start, if we try to run the above code, we will find that the final output is 0=>2 1=>4 2=>4.
Why not 0=>2 1=>4 2=>6?
In fact, we can assume that the foreach ($arr as $k => $V) structure implicitly assigns the current ' key ' and current ' value ' of the array to the variable $k and $v. The concrete expansion form is as follows:
foreach ($arr as $k => $v) {
2 assignment actions implied before user code execution
$v = Currentval ();
$k = Currentkey ();
Continue to run user code
......
}
Based on the above theory, now we re going to analyze the first foreach:
1th cycle, because $v is a reference, so $v = & $arr [0], $v = $v *2 equals $arr[0]*2, so $arr becomes 2,2,3
2nd cycle, $v = & $arr [1], $arr become 2,4,3
3rd cycle, $v = & $arr [2], $arr become 2,4,6
The code then enters the second foreach:
The 1th cycle, the implied operation $v= $arr [0] is triggered, because at this time $v is still $arr[2] reference, that is equivalent to $arr[2]= $arr [0], $arr into 2,4,2
The 2nd cycle, $v = $arr [1], i.e. $arr[2]= $arr [1], $arr into 2,4,4
The 3rd cycle, $v = $arr [2], i.e. $arr[2]= $arr [2], $arr into 2,4,4
OK, the analysis is complete.
How do you solve similar problems? The PHP manual has a reminder:
Warning: The $value reference to the last element of the array remains after the Foreach loop. It is recommended that you use unset () to destroy it.
$arr = Array (1,2,3);
foreach ($arr as $k => & $v) {
$v = $v * 2;
}
Unset ($v);
foreach ($arr as $k => $v) {
echo "$k", "=>", "$v";
}
Output 0=>2 1=>4 2=>6
We can see from this problem that references are likely to be accompanied by side effects. If you do not want the unconscious changes to result in an array content change, it is best to unset these references in time.
unset only deletes variables. Does not empty the memory space for the value of the variable: (this is a different place from the pointer
As follows:
$a = "STR";
$b = & $a;
Unset ($b);
echo $a;
Still output str