Hidden Danger of References inside a Foreach Construct
2013-04-12 22:11
169 查看
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
That's a fact we've known for years. But I don't use it very often for it never works for me. My code is simplified as follows.
There seems no problems. Unfortunately I got the output like this:
The last record was unexpectedly modified. I've been trying to find out what the problem it is.
There's a warning in the PHP manual.
Reference of a $value and the last array element remain even after theforeach loop. It is recommended to destroy it by
unset().
In the foreach construct, we've seen the $log is assigned a new value for each line. But the previous $log won't be affected because PHP seems to unset the reference on each loop ends and then start the next loop. But what on hell happened?
Why the final log was modified in the second foreach construct?
I tried to output the $logs with print_r($logs); instead of a foreach. It wasn't modified.
It's noticed that reference $log wasn't destroyed in the last loop of the first statement. So when the second one starts, $log (references to $logs[3]) was assigned a new value, $logs[1].
In conclusion, although $log won't be affected in each loop, $log will be still there until you unset it. And as an easily overlooked assignment statement, the foreach construct can be a hidden danger. Just unset every reference when it becomes unnecessary.
Ha, now it works as expected~
That's a fact we've known for years. But I don't use it very often for it never works for me. My code is simplified as follows.
<?php //This is the file content $file = '<?php exit;?> ::1 1365393847 /healthcom/memcp.do {"idnum":"450521199309333489","password":"123459"} {"action":"login"} ::1 1365393858 /healthcom/register.do {"info":"thisis a test"} [] ::1 1365393869 /healthcom/memcp.do {"idnum":"450521199309333489","password":"123459"} {"action":"login"}'; //We read it and explode it into an array $logs = explode("\r\n", $file); unset($logs[0]); //Handle each line foreach($logs as &$log){ if(empty($log)){ continue; } $log = explode("\t", $log); $log[1] = date($log[1]); } //Output the content directly. (Maybe you'd rather output the HTML in another file with a template engine.) foreach($logs as $log){ print_r($log); } ?>
There seems no problems. Unfortunately I got the output like this:
Array ( [0] => ::1 [1] => 1365393847 [2] => /healthcom/memcp.do [3] => {"idnum":"450521199309333489","password":"123459"} [4] => {"action":"login"} ) Array ( [0] => ::1 [1] => 1365393858 [2] => /healthcom/register.do [3] => {"info":"thisis a test"} [4] => [] ) Array ( [0] => ::1 [1] => 1365393858 [2] => /healthcom/register.do [3] => {"info":"thisis a test"} [4] => [] )
The last record was unexpectedly modified. I've been trying to find out what the problem it is.
There's a warning in the PHP manual.
Reference of a $value and the last array element remain even after theforeach loop. It is recommended to destroy it by
unset().
In the foreach construct, we've seen the $log is assigned a new value for each line. But the previous $log won't be affected because PHP seems to unset the reference on each loop ends and then start the next loop. But what on hell happened?
Why the final log was modified in the second foreach construct?
I tried to output the $logs with print_r($logs); instead of a foreach. It wasn't modified.
It's noticed that reference $log wasn't destroyed in the last loop of the first statement. So when the second one starts, $log (references to $logs[3]) was assigned a new value, $logs[1].
In conclusion, although $log won't be affected in each loop, $log will be still there until you unset it. And as an easily overlooked assignment statement, the foreach construct can be a hidden danger. Just unset every reference when it becomes unnecessary.
<?php foreach($logs as &$log){ //Handle your $log } unset($log); //Don't miss me after each foreach construct with a reference. I'm in the PHP manual, but easily overlooked. ?>
Ha, now it works as expected~
相关文章推荐
- Updating a specific attribute inside a folder of AutoCAD drawings using .NET
- Object reference not set to an instance of an object.
- [Erlang 0040] Hidden Features of Erlang
- Ubuntu/Vistadual-boot(reference the the steps of installing Windows Vista on a computer which already have an Ubuntu installatio
- invalid initialization of non-const reference of type ‘int*&’ from a temporary of type ‘int*’
- JS数组filter()、map()、some()、every()、forEach()、lastIndexOf()、indexOf()实例
- js中的循环遍历数组中的元素,ES6(for-of)、ES5(forEach、for-in)、通用(for(i=0;i<length;i++))
- terminate called after throwing an instance of 'std::logic_error' what(): basic_string::_S_construct
- c:foreach jstl el表达式的用法以及c:foreach中的hidden的用法
- PyCon 2011 - Hidden Treasures of the Python Standard Library - 词法分析器分析命令行参数
- Glossary of Terms in the JavaTM platform --reference
- silverlight beta2.0安装成功后新建silverlight项目出现object reference not set to an instance of an object的解决办法
- Error: initial value of reference to non const must be lvalue 原因以及解决方法
- C++引用报错:invalid initialization of non-const reference of type ‘std::string&’ from an rvalue of type
- 关于Unity3D的错误:NullReferenceException: Object reference not set to an instance of an object 的解答
- Example of how to use both JDK 7 and JDK 8 in one build.--reference
- PHP显示Deprecated: Assigning the return value of new by reference is deprecated in解决办法
- Error:The number of method references in a .dex file cannot exceed 64K 问题解决
- Error:The number of method references in a .dex file cannot exceed 64K.
- TFS 客户端错误"Object reference not set to an instance of an object."