您的位置 首页 php

PHP在使用foreach遇到的坑,引申出foreach原理详解,你遇到过吗

今天在调试某laravel框架下的某模块时遇到了 foreach 引用地址的问题,下面总结一下

$a = array(‘a’,’b’,’c’);

foreach($a as &$v){}

foreach($a as $v){

}

首先猜测一下。输出的结果是什么? 。正确答案是: array(3) { [0]=> string(1) “a” [1]=> string(1) “b” [2]=> &string(1) “b”} 也就是a,b,b. 如果你猜测的是a,b,c的话。 那么关于引用,你还要查阅一下相关的资料:

那么为什么是a,b,b呢。让我们一步步来看:

我们知道对数组执行foreach循环时,是通过移动数组内部指针来实现的。因而对于本文中的例子:当foreach循环结束的时候,由于$v为

引用变量,因而$v 与 $a[ 2 ] 指向了同一个地址空间(共享变量值),因而之后对$v的任何修改都会直接反映到数组$a中。我们可以对例子加上调试代码,便会一清二楚,例如我们在第二次循环内部,加上var_dump($a),测试每次循环时a的值的变化:

$a = array('a','b','c');
foreach($a as &$v){}
 
foreach($a as $v){
var_dump($a);
echo "<br/>";
}
var_dump($a);
运行代码。结果为: 
array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> &string(1) "a" }
array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> &string(1) "b" }
array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> &string(1) "b" }
array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> &string(1) "b" } 

画个图:可以更加清晰看出来:(图中”$v指向了$a[2]”并不准确。应该是:$v与$a[2]指向了同一个地方)

关于引用的几点简单解释:

1.引用类似于指针,但是不同于指针。

例如对于引用:

$a = "str";
$b = &$a;//< var  class="varname"><var class="varname"> $a</var></var> 和 <var class="varname"><var class="varname">$b</var></var> 指向了同一个地方

一个简单的示意图如下:

那么此时更改$a和$b中任何一个元素的值。另外一个值都为随之改变:

$a = "str";
$b = &$a;
$b = "sssss";
echo $a;
2.unset只会删除变量。并不会清空变量值对应的内存空间:(这是与指针不同的地方)
$a = "str";
$b = &$a;
unset($b);
echo $a;
3.引用作为函数参数传递时,是可以被函数内部更改的:
function change(&$a){
if(is_array($a)){
$a = array();
}
}
$test = range(1,10);
change($test);
print_r($test);

基于以上几点,在编码的过程中,要小心使用引用。 接下来就是对foreach的个人总结

PHP foreach原理详解

一、foreach简介

1.foreach的遍历顺序

如果是索引数组,你会发现遍历出来的顺序并不是按索引大小遍历,而是按添加的顺序,如果按照索引大小遍历,应该使用for,而不是foreach

$arr[2]='中';
$arr[1]='国';
foreach($arr as $value){
 echo $value;
}
结果:中国

所以foreach遍历数组的顺序是由元素的添加顺序决定的,不管是索引数组还是关联数组

2.

当 foreach 开始执行时,数组内部的指针会自动指向第一个单元。这意味着不需要在 foreach 循环之前调用 reset()怎么来理解这个呢?

$arr = array(1,2,3);
foreach($arr as $k=>$v){
}
var_dump(current($arr));
foreach($arr as $key=>$value){
 echo $value." ";
}
var_dump(current($arr));
结果:boolean false
 1 2 3
 boolean false

第一个foreach已经把指针移到尾部去了,并且试图努力的往后移动指针,直到移出界(current($arr)返回false),foreach结束foreach结束后,并没有帮我们把指针初始化,不然current应该返回数组的第一个单元,第二个foreach并没有受第一个foreach的影响,当foreach开始执行时,数组内部的指针会自动指向第一个单元。

$key = currentKey($arrCopy); //将获取到的值分配给$k;
$val = currentVal($arrCopy); //将获取到的值分配给$v;
next($arrCopy);//移动副本数组的指针
$arr = $arrCopy;//将副本赋值回给$arr((主要是将指针同步移动))

技术细节:当本次赋值给key和val之后,按照流程指针已经向下移动了一位,所以当执行var_dump(current($arr));时打印false。 如果移动指针的结果超出了数组单元的末端,则 next() 返回 FALSE。但foreach循环的次数不是副本数组的长度

二、加深foreach理解

$arr = array('a'=>1,'b'=>2,'c'=>3);
foreach($arr as $k=>$v){
 $v*=2;
 echo $v."<br />";
}
var_dump($arr);
foreach($arr as $key=>$value){
 $arr[$key]=$value*2;
}
var_dump($arr);
//传入&
foreach($arr as &$v){
 $v=$v*2;
}

var_dump($arr);

结果:

array (size=3)
 'a' => int 1
 'b' => int 2
 'c' => int 3
array (size=3)
 'a' => int 2
 'b' => int 4
 'c' => int 6
array (size=3)
 'a' => int 4
 'b' => int 8
 'c' => &int 12

原因分析:

$k和$v 都是临时变量 ,foreach的时候,把每个数组单元的键分别赋值给$k,把每个数组单元的值分别赋给$v,相等于$v=$arr[$k],$v*2仅仅是改变了$v的值(非&传递),并不会影响到$arr[$k],自然也就不会影响到$arr

而用第二种方法(引用)的时候,相等于$v=&$arr[$k],$arr[$k]和$v指向同一内存地址,$v*2自然就改变了$arr[$k]的值,也就改变了$arr的值

文章来源:智云一二三科技

文章标题:PHP在使用foreach遇到的坑,引申出foreach原理详解,你遇到过吗

文章地址:https://www.zhihuclub.com/79079.shtml

关于作者: 智云科技

热门文章

网站地图