PHP foreach原理详解

当 foreach 开始执行时,数组内部的指针会自动指向第一个单元。如果移动指针的结果超出了数组单元的末端,则退出循环。

例子:

$array = [
    'name' => 'Jobs',
    'age'  => 50,
];

foreach ($array as $key => $value) {

    $value = 22;
	//赋值,但是没有影响到$array[$key]位置的值,除非加上 $array[$key] = $value;
}

上面的foreach 对数组内的值没影响。有时候我们为了在循环过程中改变数组项的值,在foreach的时候变量入口可以加个&符号,表示,循环过程中使用数组中原来的值,而不是一个复制的值,如

$array = [
    'name' => 'Jobs',
    'age'  => 50,
];

foreach ($array as $key => &$value) {
    //直接改变数组$array[$key]位置的值
    $value = 22;
}

结果输出对比:

Array
(
    [name] => Jobs
    [age] => 50
)


Array
(
    [name] => 22
    [age] => 22
)

原因分析:

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

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

循环时,$key$value都是临时变量,只是赋值方式不同

陷阱

陷阱:两次循环使用同样的临时变量的情况下,如果第一次循环使用的是引用,那么在第二次循环中即使没有加&符号,临时变量也是引用。这个引用指向了数组中最后一个元素(循环到了最后一个元素结束)。

如:

array = [
    'name' => 'php',
    'age' => 123,
];


//标记为循环1:
 
foreach ($array as $key => &$value) {
    echo "key=$key, value=$value" . PHP_EOL;
}

//循环完后,最后一个元素  $value = &$array['age'], 这里$value 和  $array['age'] 是引用关系,都是指向的同一个空间。


var_dump($array); 

输出结果如下:

array(2) {
  ["name"]=>
  string(3) "php"
  ["age"]=>
  &int(123)
}


//标记为循环2:

foreach ($array as $key => $value) {
    //第一次循环进来  $value=$array['name'],此时$value = 'php',由于我们开始的引用中,
     $value 和 $array['age'] 建立了引用,所以这里改变了$value的值,
     其实就改变了 $array['name']的值,所以 $array['name'] = 'php',

    //以后的每次循环处理都和上面第一次相同

   //得到的结果:其实每次循环赋值给$value的值,都是给“标记为循环1”中的最后一个元素在赋值,也就是说数组中最后一个元素的值 = 数组中的倒数第2个元素的值

    echo "key=$key, value=$value" . PHP_EOL;
}


上面的 foreach循环中输出结果如下:


key=name, value=php
key=age, value=123

key=name, value=php
key=age, value=php

总结:两次循环使用同样的临时变量的情况下,如果第一次循环使用的是引用,那么在第二次循环中即使没有加&符号,临时变量也是引用。这个引用指向了数组中最后一个元素(循环到了最后一个元素结束)。,得到的最后数据结果就是数组中最后一个元素的值 = 数组中的倒数第2个元素的值 (也就是说,最后2个元素的值相同,且为到倒数第2个元素的处理值)。

如何避免这个陷阱呢?

方法1:在第二次循环之前,unset($value)

方法2:第二次foreach的时候使用不同名字的临时变量

扩:

另:查看一个变量是否是引用可以使用xdebug_debug_zval函数(需要有xdebug扩展)。

xdebug_debug_zval的结果形如: value: (refcount=2, is_ref=1)=123

转载于:https://my.oschina.net/u/3683692/blog/3030084

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值