1 背景
我们经常在PHP中使用for和foreach来进行遍历操作,那它们除了语法上的区别之外,还有什么不同吗?
2 实验
2.1 for
<?php
$a = ['a', 'b', 'c'];
for ($i = 0; $i < count($a); $i++) {
$a[] = $a[$i];
}
var_dump($a);
输出
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 134217736 bytes) in /box/script.php on line 5
Exited with error status 255
内存爆了。
原因是在for循环里面,一直在往$a中追加元素,而每次元素的新增都会增加$a的长度,导致$i < count($a) 这个条件一直成立,于是这个for循环变成了一个死循环,无法退出,最后内存爆掉。
可以看出,在for循环中,PHP会在每一次迭代中,忠实地去检查for循环的条件、边界,然后判断是否执行for循环体里面的内容。这个结论可以延伸到while循环以及do-while循环。
2.2 foreach
<?php
$a = ['a', 'b', 'c'];
foreach ($a as $k => $v) {
$a[] = $a[$k];
}
var_dump($a);
输出
array(6) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
string(1) "c"
[3]=>
string(1) "a"
[4]=>
string(1) "b"
[5]=>
string(1) "c"
}
可以看到,在foreach循环中,PHP会事先确定好要遍历数组的迭代次数,然后依次迭代。它的底层原理是,foreach是对数组的副本进行操作,而且每一次迭代,都是通过元素之间的指针来实现,比如current, next, rewind, valid, end等方法;当迭代器判断当前指针指向空节点的时候,valid返回false,就表示迭代完成了,底层是一个链表。