php中foreach对数组指针的影响及原因

问题描述:遍历数组时,改变了数组的值,数组遍历完成后,数组的指针指向了第二个元素,当发生这种情况时,会对后续通过指针遍历数组产生影响。


<?
$arrD = array('0'=>'a','1'=>'b','2'=>'c');
echo key($arrD)."</br>";
foreach($arrD as $intK => $val)
{
     $arrD[] = $val."2";
}
echo(key($arrD));
?>

输出结果如下:

0
1

因此再次通过指针遍历数组的时候会发现$arrD的第一个值就循环不出来了。


其实问题很好解决,在foreach之后,直接用reset()方法将$arrD的指针重置一下就可以了,但导致问题的原因才是值得关注的,在做了一些搜索和阅读的工作之后,总结问题原因如下,首先,先知道几个php处理赋值遍历等动作的原则:

1,php在变量赋值时候的内存使用策略:写时复制(copy on write, COW),当用赋值方法把一个变量值赋给另一个变量时,由于这两个变量值相同,因此公用同一内存,当其中一个变量值发生变化时候,才会重新为值变化的变量申请内存,已达到节省内存的目的;

2,foreach遍历数组时,实际上是遍历的数组的一个拷贝,并且在开始遍历之前会把指针指向拷贝的开始;

3,在发生写时复制时候,指针的位置也会一并被复制;


针对规则1 的验证

<?
echo "初始内存情况:".memory_get_usage()."</br>";
$foo = str_repeat('aaa', 10000);
echo "使用变量\$foo之后的内存:".memory_get_usage()."</br>";
$bar = $foo;
echo "将变量\$foo拷贝给\$bar后的内存:".memory_get_usage()."</br>";
$bar = str_repeat('aaa', 10000);
echo "对\$bar值修改后使用的内存:".memory_get_usage()."</br>";
?>
输出结果如下:

初始内存情况:118912
使用变量$foo之后的内存:149008
将变量$foo拷贝给$bar后的内存:149056
对$bar值修改后使用的内存:179104


针对规则2的验证

<?
    $a = array('a','b','c');
    next($a);
    foreach($a as $v)
    {
        $a[] = 'd';//$a值发生了变化,开辟了新的空间存储
        echo $v."</br>";
    }
?>

输出结果如下

a
b
c


针对规则3的验证

<?
    $a = array (1,2,3);
    next($a);
    $b = $a;//同一内存
    $b[] = 4;//$b被开辟了新的存储空间,指针与之前存储空间的一致
    echo current($b);
?>

输出结果如下

2




然后来看产生最初问题的原因:

1. foreach 循环遍历 $arrD 时,php创建了一个 $arrD 的拷贝 AA 是不可见的,只是为了描述方便 ),但是由于此时A 和 $arrD 值一样,所以,共用同一个内存;

2.执行 foreach时候,先把A中第一个指针所在的 keyvalue 分别赋值给 $a 和 $b,同时指针后移一位,由于此时A 和 $arrD 共用同一内存,此时 $arrD 的指针也指向了第二个值;

3.当执行到 $a[] = 'd'; 时,由于 $arrD 的值发生改变,此时系统给 $arrD分配了其他内存,而同时,其指针指向也被拷贝到新内存中;而之后的遍历过程中,A$arrD 相当于两个完全不同的变量,不同值,不同存储地址,A  指针的移动已经无法影响 $arrD 指针的变化,因此当 A 被遍历完成后,$arrD的指针仍然被留在第二个值的位置。






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值