There are not many people using & referencing variables or objects or methods in PHP encoding, but & references can make your code simple and save resources. In this article, we focus on the exceptions and workarounds that occur with & in foreach.
$exp = [' name ' = ' test1 ', ' age ' = ', ' extension ' = ' A:3:{s:4: ' nose '; s:4: "Long"; s:5: "Mouth"; S:3: "Big"; S:3: "Eye"; s:5: "Small";} ' ], [' name ' = ' test2 ', ' age ' = ', ' extension ' = ' a:3 ': {s:4: "nose"; s:5: "Long2"; s:5: "Mouth"; s:4: "Big2"; S:3: "Eye"; S:6: "Small2";} ' ], [' name ' = ' test4 ', ' age ' = ', ' extension ' = ' a:3 ': {s:4: "nose"; s:5: "Long2"; s:5: "Mouth"; s:4: "Big2"; S:3: "Eye"; S:6: "Small2";} ' ], [' name ' = ' test3 ', ' age ' = ', ' extension ' = ' a:3 ': {s:4: "nose"; s:5: "Long3"; s:5: "Mouth"; s:4: "Big3"; S:3: "Eye"; S:6: "Small3";} ' ], ]; foreach ($exp as & $v) {$extension = @unserialize ($v [' extension ']); $v [' nose '] = $extension [' Nose ']?? ""; $v [' Mouth'] = $extension [' Mouth ']?? ""; $v [' eye '] = $extension [' eye ']?? ""; } $NEWEXP = []; foreach ($exp as $v) {if ($v [' mouth '] = = "Big3") {$newExp [] = $v; }} dump ($NEWEXP); Exit
The functionality of this section of the code is described below:
1. Mix the extension fields in EXP into exp 2. If mouth is BIG3 in exp, the new array newExp3 is assigned. Output newexp
From the simple appearance to analyze the seemingly above logic is not wrong, and we predict the output should be the result of
... 0 = array:6 [ "Name" = "Test3" "age" = " extension" "=" a:3:{s:4: "Nose"; s:5: "Long3"; s:5: " Mouth "; s:4:" Big3 "; S:3:" Eye "; S:6:" Small3 ";}" " Nose "+" long3 "mouth" + " big3" "eye" + "Small3" ] ... But the result is not what we predict, the result of the program output is: [] This is why, we have to analyze each
Exception thrown by a foreach reference
The first foreach is the following block of code
foreach ($exp as & $v) { $extension = @unserialize ($v [' extension ']); $v [' nose '] = $extension [' Nose ']?? ""; $v [' mouth '] = $extension [' Mouth ']?? ""; $v [' eye '] = $extension [' eye ']?? "";}
, &v is used in this code block. Because the only thing we need to do in this step is to handle the data in the array itself, so using references is less memory consuming. In the execution of the program
V should be a reference to the last element of exp.
Then when we modify the value of $v, the last element of exp should change. And there is a very important problem is that the reference after the use of the foreach reference after the end of the foreach still exists. In addition to the above foreach, $v still references the last element of exp.
Does the $v still exist after foreach
. foreach ($exp as & $v) { $extension = @unserialize ($v [' extension ']); $v [' nose '] = $extension [' Nose ']?? ""; $v [' mouth '] = $extension [' Mouth ']?? ""; $v [' eye '] = $extension [' eye ']?? "";} Dump ($v); the output is: array:6 [ "Name" = "Test3" "age" = " extension" = "a:3:{s:4:" Nose "; s:5:" Long3 "; s:5:" Mouth "; s:4:" Big3 "; S:3:" Eye "; S:6:" Small3 ";}" " Nose "=" "Long3" "mouth" + "big3" "Eye" and " Small3"
Second cycle analysis
$NEWEXP = []; foreach ($exp as $v) { if ($v [' mouth '] = = "Big3") {$newExp [] = $v; }} dump ($NEWEXP);
Here we are doing a regular loop to loop exp and in that loop we are using a variable that does not use a reference. The difference is $v
and &$v
please look carefully.
In this loop, the $v is still a reference to the last element of exp. So in the loop in fact each time is the award exp current value is assigned to $v because the reference relationship ultimately changes the value of the last element of exp. 那么在foreach中exp最后子元素的值一直是变的。演变过程如下
:
In order to briefly represent//the first cycle exp becomes: That is, the first element is assigned to the last element [[' Name ' = ' test1 ', ...], [' name ' = = ' Te St2 ', ...], [' name ' = ' test4 ', ...], [' name ' = ' test1 ', ... ],]//the second cycle exp becomes: That is, the second element is assigned to the last element [[' Name ' = ' test1 ', ...], [' name ' = ' test2 ', ...], [' name ' = ' test4 ', ...], [' name ' = ' test2 ', ...],]//third The secondary loop exp becomes: That is, the third element is assigned to the last element [[' Name ' = ' test1 ', ...], [' name ' = ' test2 ',. .. ], [' name ' = ' test4 ', ...], [' name ' = ' = ' test4 ', ...]],]//the fourth cycle exp becomes: the first The four-element assignment gives the last element a loop complete [[' Name ' = ' test1 ', ...], [' name ' = ' test2 ', ...] , [' name ' = ' test4 ', ...], [' name ' = ' test4 ', ...],
Cause analysis
From the above can be seen although the last element of exp compound if condition in the $v [' mouth '] = = "Big3"
, but the last element in the loop itself has become the third element, so the MOUTH=BIG3 element does not exist. This process is a bit around and can be read more than once. Of course you can also look at the implementation of the foreach in PHP's Zend engine and see the VLD intermediate code, such as the VLD of a simple loop
Number of ops:16compiled VARs:!0 = $arr,! 1 = $key,!2 = $rowline # * OP fetch Ext return operands---------------------------------------------------------------------------------2 0 > Init_array ~0 1 1 add_array_element ~0 2 2 add_array_element ~0 3 3 add_array_element ~0 4 4 add_array_element ~0 5 5 ASSIGN! 0, ~0 4 6 > Fe_reset $0,->14 7 > > Fe_fetch,->14 8 > Zend_op_data 9 ASSIGN !2, $ ASSIGN! 1, 5 ECHO !1 ECHO!2 6 13 > JMP->7 > Switch_free $7 > RETURN 1