php foreach 遍历数据遇到的问题

来源:互联网 发布:wind数据库有免费版吗 编辑:程序博客网 时间:2024/06/14 14:13

用foreach遍历一个含有1001个元素的数组:

function get_memory(){    echo memory_get_usage() . PHP_EOL;}$arr = range(1, 10001);echo "before traversal :";get_memory();$begin = microtime(true);foreach ($arr as $key => $val) {    $t = $val;    if ($key % 2000 == 0) {        get_memory();    }   }echo "after traversal :";echo get_memory();echo microtime(true) - $begin . PHP_EOL;
执行结果:

before traversal :2791328
2792000
2792000
2792000
2792000
2792000
2792000
after traversal :2792000
0.0026109218597412

第二段代码再$arr赋值下面多了一行对$foo变量指向$arr的代码,由php内核的cow机制可以知道两个变量会指向同一份数据,但执行结果却有很大区别:

$arr = range(1, 10001);$foo = $arr;echo "before traversal :";get_memory();$begin = microtime(true);foreach ($arr as $key => $val) {    $t = $val;    if ($key % 2000 == 0) {        get_memory();    }   }echo "after traversal :";echo get_memory();echo microtime(true) - $begin . PHP_EOL;
before traversal :2791696
4123912
4123912
4123912
4123912
4123912
4123912
after traversal :2792400
0.0047910213470459

仅仅多了一行赋值代码,从内存和时间上可以推断出,foreach的时候好像进行了内存复制。要探究具体原因,需要在源码中找到答案,鸟哥之前写过一篇关于foreach的博客http://www.laruence.com/2008/11/20/630.html,引用其中的对foreach的生成的opcode。


opcode可以看出forearh执行了一个叫FE_RETSET操作。在php内核中该操作会将数组hashtable内部的指针指向其头部,在这一步操作过程中当数组的引用计数不大于1时(如上面代码就$arr一个变量指向数组),操作就在当前数组上进行,但当引用计数器大于1的时候,reset操作如果再在同一份数组上进行的时候会影响其他变量(如代码中的$foo),所以数组需要分裂复制了一份临时数组,待循环结束后又释放掉。  由于数组的复制,导致了内存的使用量和代码执行时间的增加,所以在代码中对大数据的遍历操作中最好不要给数据赋值给多个变量。

原创粉丝点击