这里是我自己整理的一些资料,大家不懂的可以相互学习呀。。。

foreach 对数组指针操作的理解

PHP ZZT 1514次浏览 已收录 0个评论

转载内容:
foreach指针问题
foreach指针引用销毁问题

代码1:

<?php
$arr = array(1,2,3,4,5);

foreach($arr as $key => &$row) {
echo key($arr), '=>', current($arr), "\r\n";
}

代码2:

<?php
$arr = array(1,2,3,4,5);

foreach($arr as $key => $row) {
echo key($arr), '=>', current($arr), "\r\n";
}

结论:

1、为什么foreach循环体中执行key或current会显示第二个元素(非引用情况)?
以key函数为例,我们执行函数调用时,会执行中间代码SEND_REF,此中间代码会将没有设置引用的变量复制一份并设置为引用。当进入循环体时,PHP内核已经经过了一次fetch操作,相当于执行了一次next操作,当前元素指向第二个元素。因此我们在foreach的循环体中执行key函数时,key中调用的数组变量为PHP执行了一次fetch操作的数组拷贝,此时foreach的内部指针指向第二个元素。

2、为什么在foreach中执行end等操作,其循环过程不变?
在遍历的代码中通过end,next等操作数组的指针,数组的指针不会变化,这是因为在PHP内核进行FETCH操作时,会通过中间变量存储当前操作数组的内部指针,每遍历一个元素,会先获取之前存储的指针位置,获取下一个元素后,再恢复指针位置。

3、为什么$row的引用和非引用情况下输出结果不同?
如果是引用,PHP内核在reset数组时,会直接分裂数组,生成一个数组的拷贝,并将其设置为引用。
如果是非引用,PHP内核在reset数组时,当数组的引用计数大于1,并且不存在引用时,会拷贝数组供foreach使用,其它情况使用原数组,将其引用计数加1。


代码:

$a = array('abe','ben','cam');
foreach ($a as $k=>&$n){
    $n = strtoupper($n);
}
print_r($a);
foreach ($a as $k=>$n){ // notice NO reference here!
    echo "$n\n";
}
print_r($a);

打印结果:

Array
(
    [0] => ABE
    [1] => BEN
    [2] => CAM
)
ABE
BEN
BEN
Array
(
    [0] => ABE
    [1] => BEN
    [2] => BEN
)

可以看到第一次foreach()循环以后是正常的,第二次循环以后$a[2]从变成了'BEN',和$a[1]一样。

初看很纳闷,但是如果在第二个foreach()里print_r($a),就很容易明白了,结果如下:

Array
(
    [0] => ABE
    [1] => BEN
    [2] => ABE
)

Array
(
    [0] => ABE
    [1] => BEN
    [2] => BEN
)

Array
(
    [0] => ABE
    [1] => BEN
    [2] => BEN
)

由于第一个foreach()是用指针指向数组元素,所以循环结束后变量$n依然指向数组$a的最后一个元素,也就是$a[2]。

第二个foreach()里,第一次循环就将$a[0]的值'ABE'赋给$n,第二次又将$a[1]的值'BEN'赋给$n,其实这两次修改的都是$a[2]这个元素,第三次等于没有变化,所以$a[2]无辜地被修改了三次,导致最后的结果。

由此可见,如果foreach()中用指针指向数组元素,循环结束后最好销毁指针,以免后面再次用到重名的变量导致数组的值被无辜修改。


附加一只小的算法题:

$arr个人围成一个圈,按照$num计算,数到第$num的时候踢出该人,直到最后一个,糗最后一个人。

<?php

$num = 3;

$arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

$i=1;
$node = 0;


while(true){
    if($i<3){
        $i++;
        if(next($arr)===false){
            reset($arr);
        }
    }else{
        $i=1;
        $node = key($arr);
        $val = $arr[$node];
        unset($arr[$node]);

        if(count($arr)===0){
            echo $node;
            break;
        }

    }
}


乐趣公园 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明foreach 对数组指针操作的理解
喜欢 (1)

文章评论已关闭!