相关文章推荐
风流的手术刀  ·  PHP ...·  1 周前    · 
打酱油的柿子  ·  Perl 数组 | 菜鸟教程·  昨天    · 
礼貌的消炎药  ·  linux - Netcat uses ...·  1 年前    · 
含蓄的火柴  ·  调研linux库alsa - 简书·  1 年前    · 
独立的肉夹馍  ·  Window.OnSourceInitial ...·  1 年前    · 

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

在数组中, 我们同样可以进行引用传值, 引用返回值, 以及取消引用的操作. 只不过是在引用的核心逻辑外面套了一层数组的外衣.

但针对数组的模式, 有2点需要注意的火坑:

先看下面两个例子:

这是引用在数组中的一般应用,和普通赋值没有什么区别:
$arr = array(1, 'test');
$p =& $arr[1];  // $p和$arr[1]都指向了test
$new = 'new';
$arr[1] =& $new;//$new给$arr[1]赋予新的引用,都指向了new
echo $arr[1]; // echo 'new';
echo $p.'<br>'; //'test',$p的指向并没变;
这个是数组引用特殊的地方,不注意的话会出问题:
$array1 = array(1,2);
$x = &$array1[1];  //x和$array1[1]指向同一个变量
$array2 = $array1;  // 这里是数组对数组整体的赋值,将其中元素的引用关系,也进行了传递!
$array2[1]=22;      // (changing [0] will not affect $array1)
var_dump($array2,$x);  //同时修改了$array1[1]

上面第二个例子中, $array2 = $array1, 这一步非常重要, 我们如果不注意, 可能就认为这是一个普通赋值, 不存在引用关系. 但实际上, 元素级的引用关系却进行了传递, 在新数组下得到了保留.

这就牵出了数组型引用的第一个坑:

元素级用 & 数组引用

上面那个例子是元素级别的引用关系, 它可以通过普通数组间赋值来传递引用关系.

我们再来看数组级别的引用:

$brr1=[1,2,3,4];
$brr2=[5,6,7,8];
$brr3=&$brr1;  //建立brr3和brr1的引用关系;
$brr2=$brr3; //对brr2进行整体赋值
$brr3[3]=100;
print_r($brr2); //依然是[1,2,3,4]
print_r($brr1); //[1,2,3,100], 被修改;

可以看到,数组级别的引用关系, 无法通过普通赋值来传递. 引用关系不会保留. 只能通过引用赋值来传递.

这就好比, 你(数组$a) 和 你的老婆(数组$b,引用赋值), 或和情人(普通赋值), 她们怀了你的孩子(数组元素), 这个孩子都是你的家人(引用关系), 而且你和你的老婆也是一家人(引用关系), 但和你的情人却不是一家人.

元素级别的引用和数组整体的引用, 是相互独立. 当我们为数组进行整体赋值的时候, 元素级别的应用会进行传递和保留, 而数组级别的引用却不会, 需要单独加&说明.

所以在进行元素级引用的时候要格外小心!!!尽量少用, 可以通过条件判断, 如果发生改变就重新赋值的操作, 更安全一些.

好的,我们再来看一下第二个坑:

foreach()引用的小尾巴

这个函数可以用来遍历数组, 并可与引用组合使用, 实现数组赋值, 修改等操作. 举例:

$a1=[1,2,3,4]
foreach ($a as &$value) {
$value = $value * 2;
print_r($a1);  //[2,4,6,8] 通过引用实现了对数组所有元素的修改

现在问题来了, 数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。这个就是 foreach引用的小尾巴.

此时数组$a1的结构已经变为了:

$a1=[$a1[0]=>2, $a1[1]=>4, $a1[2]=>6, &$a1[3]=>8]

注意最后一项a1[3],它有一个引用关系.a1[3], 它有一个引用关系. 是a1[3]与函数参数$var之间的引用关系. 可以理解为:

$a1[3]=&$value=8;

如果我们忽视这个小尾巴的话, 就会被它反噬, 比如我们现在再遍历一次数组的话, 你就会发现:

$a1=[1,2,3,4]
foreach ($a as &$value) {
$value = $value * 2;
print_r($a1);
foreach ($a as $key => $value){
echo "$key to $value";
}  //0 => 2  1 => 4  2 => 6  3 => 6  

此时, $a1[3]=6. Why?

因为第二次foreach的时候, a轮流赋值给a轮流赋值给value, 而同时也修改着$a[3].

我把每一步分解一下:

$value= $a1[0]=2, 此时$a1[3] = 2;
$value= $a1[1]=4, 此时$a1[3] = 4;
$value= $a1[2]=6, 此时$a1[3] = 6;
$value= $a1[3]=6, 此时$a1[3] = 6;

看到这里, 大家应该都明白了, foreach (&)会在遍历结束后,保留最后一项的引用关系, 最终导致被引用数组的最后一项发生改变.

那么如何规避这个问题? 2个办法:

unset, 每次foreach遍历后,都对引用变量$value进行unset, 解除它与数组元素的引用关系.

 \$a=[1,2,3,4];
 foreach ($a as $key => $value){
 $a[$key]=$value*2;
 print_r($a); //可以通过这样的方式进行赋值,避开引用;

以上就是关于PHP数组中涉及引用的两个坑, 这两个坑都很隐蔽, 各位在写代码时要特别小心!

感谢阅读, 抛砖引玉, 如有不准确和错误之处请留言指正, 我会及时修正, 拜谢!

学习不易,请勿私自转载, 否则别怪老大爷不客气.

参考资料: www.php.net 官方文档

分类:
后端
标签: