A strange phenomenon occurred in the recent work of using references in foreach, where the value of the array was changed when using 2-time foreach, and the code shows examples such as the following
1 <? PHP 2 $arr Array (' 1 ', ' 2 ', ' 3 '); 3 foreach ($arr as &$row) {4} 5 foreach ($arras$row) {6 }
My expected result is a 1,2,2, but the actual result output is
Strangely, iterating over an array will change the value of the array, and the reason for guessing must be on the &row reference.
Print a $arr in the 2nd loop
Array
(
[0] = 1
[1] = 2
[2] = 1
)
Array
(
[0] = 1
[1] = 2
[2] = 2
)
Array
(
[0] = 1
[1] = 2
[2] = 2
)
Explain the specific implementation process
1. End of the 1th foreach, $row as a reference to $arr[3]
2.2nd foreach Loop 1th time $row=1, so at this time $arr[3]=1, so at this time $arr=array (1,2,1),
3. And so on, the 2nd foreach Loop at the end of the time $row=2, so at this time $arr=array (1,2,2);
While pondering this code, the PHP manual to explain the reference: in PHP refers to a different name to access the same variable content, this is not like a C pointer: for example, you can not do pointer operations, they are not the actual memory address.
The closest analogy is the Unix filename and the file itself-the variable name is the directory entry, and the variable content is the file itself. References can be seen as hard links in Unix file systems (if you take windows as a metaphor that's a shortcut).
See here, another piece of code found in the manual.
1<?PHP2 $array 1=Array();3 $x= &$array 1[1];//Unused Reference4 $array 2=$array 1;//reference now also applies to $array 2!5 $array 2[1]=22;//(changing [0] would not affect $array 1)6 Print_r($array 1);
Produces:
Array
(
[0] = 1
[1] = +//Var_dump () would show the & here
)
The result is unexpectedly, comment out $x = & $array 1[1], change the value of $array2 not affect the value of $arry1, Lenovo to the PHP garbage Collection reference counter, each PHP variable exists in the Zval container, Zval container In addition to the value and type of the variable, There are 2 additional messages,
The 1th one is Is_ref, which is a bool value that identifies whether the variable is a reference set, and through which I know whether the variable is a normal variable or a reference variable, and the 2nd extra field is RefCount, which represents the number of variables that point to the Zval container.
The ZVAL structure is as follows
struct _zval_struct Zval; struct _zval_struct { /* */* * * /* * *Zend_uchar is_ref__gc;};
$a = ' OK ';
Xdebug_debug_zval (' a ');
A: (Refcount=1, is_ref=0), String ' OK ' (length=2)
$b = & $a;
Xdebug_debug_zval (' a ');
Xdebug_debug_zval (' B ');
A: (refcount=2, is_ref=1), String ' OK ' (length=2)
B: (refcount=2, is_ref=1), String ' OK ' (length=2)
At this point, the number of references is 2 because the same variable container is associated with variable A and variable B. When not necessary, PHP does not replicate the generated variable container, and the variable container is destroyed when "RefCount" becomes 0 o'clock.
Because PHP built-in functions debug_zval_dump not see Zval is_ref information, so using xdebug_debug_zval here, you need to install Xdebug extensions.
$a = ' OK '; $b $a ; $a = ' no ';xdebug_debug_zval (' a '); Xdebug_debug_zval (' B ');
$a the last value has undoubtedly become ' no ', how does PHP do it?
When executing $b= $a; $ A and $b point to the same Zval container, refcount=2,
When you finally change the value of $ A, the copy on write mechanism of PHP is executed
The copy on write mechanism of PHP:
PHP before modifying a variable, will check the RefCount value, RefCount greater than 1,php will copy a new zval, and the original Zval refcount minus 1,
and modify the symbol_table (symbol table), so that two variables separated, this mechanism is called copy on write (copy),
$a = ' OK ';
$b = & $a;
$b = ' no ';
$a, the last value of $b has undoubtedly become ' no ',
Execute to line 2nd when $ A, $b point to the same Zval container, refcount=2,is_ref=1, then back to execute PHP's change on write mechanism
PHP change on write mechanism:
Is_ref=1, PHP modifies the value of zval, but does not replicate zval, a process called (change on write: Changes in write)
Back to the beginning of the problem with the array assignment on the manual, Array1 and $array2
When considering composite types such as array and object, things are a little bit more complicated. With scalars (scalar) types, arrays and objects such as compound variables generate a zval container for each item item when the Zval is generated.
$array 1 Array (a); $x = &$array 1// Unused reference$array 2$array 1// Reference now also applies to $array 2!//xdebug_debug_zval (' x '); Xdebug_debug_zval (' array1 '); Xdebug_debug_zval (' array2 '); Print_r ($array 1);
(refcount=2, is_ref=0),
Array (size=2)
0 = (refcount=1, is_ref=0), int 1
1 = (refcount=2, is_ref=1), int 2
Array2:
(refcount=2, is_ref=0),
Array (size=2)
0 = (refcount=1, is_ref=0), int 1
1 = (refcount=2, is_ref=1), int 2
Array ([0] = 1 [1] = 2)
Can see $array1, $array 2 point to the same zval, and $array1[1], $array 2[1], $x point to the same zval,
And the property is Ref_count=1, so when the value of $array2[1] is modified, the value of $array 1[1] is modified together.
If you remove $x = & $array 1[1], then $array[1] points to the Zval variable property is_ref=0, and then executes $array2= $array 1, at which time the value of $array2[1] is modified,
Does not affect the $array1[1].
PHP foreach uses a referenced trap