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

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

[php]  view plain  copy
  1. <?  
  2. $arrD = array('0'=>'a','1'=>'b','2'=>'c');  
  3. echo key($arrD)."</br>";  
  4. foreach($arrD as $intK => $val)  
  5. {  
  6.      $arrD[] = $val."2";  
  7. }  
  8. echo(key($arrD));  
  9. ?>  
输出结果如下:
[html]  view plain  copy
  1. 0  
  2. 1  
因此再次通过指针遍历数组的时候会发现$arrD的第一个值就循环不出来了。

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

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

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

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

针对规则1 的验证

[php]  view plain  copy
  1. <?  
  2. echo "初始内存情况:".memory_get_usage()."</br>";  
  3. $foo = str_repeat('aaa', 10000);  
  4. echo "使用变量\$foo之后的内存:".memory_get_usage()."</br>";  
  5. $bar = $foo;  
  6. echo "将变量\$foo拷贝给\$bar后的内存:".memory_get_usage()."</br>";  
  7. $bar = str_repeat('aaa', 10000);  
  8. echo "对\$bar值修改后使用的内存:".memory_get_usage()."</br>";  
  9. ?>  
输出结果如下:
[html]  view plain  copy
  1. 初始内存情况:118912  
  2. 使用变量$foo之后的内存:149008  
  3. 将变量$foo拷贝给$bar后的内存:149056  
  4. 对$bar值修改后使用的内存:179104  

针对规则2的验证

[php]  view plain  copy
  1. <?  
  2.     $a = array('a','b','c');  
  3.     next($a);  
  4.     foreach($a as $v)  
  5.     {  
  6.         $a[] = 'd';//$a值发生了变化,开辟了新的空间存储  
  7.         echo $v."</br>";  
  8.     }  
  9. ?>  
输出结果如下
[html]  view plain  copy
  1. a  
  2. b  
  3. c  

针对规则3的验证

[php]  view plain  copy
  1. <?  
  2.     $a = array (1,2,3);  
  3.     next($a);  
  4.     $b = $a;//同一内存  
  5.     $b[] = 4;//$b被开辟了新的存储空间,指针与之前存储空间的一致  
  6.     echo current($b);  
  7. ?>  
输出结果如下
[html]  view plain  copy
  1. 2  

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

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

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

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

猜你喜欢

转载自blog.csdn.net/wuxing26jiayou/article/details/80040842