微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

php – 通过引用循环在foreach中取消设置的奇怪行为

我知道在通过引用循环时不应该修改数组的物理结构,但我需要解释我的代码中发生了什么.开始了:

$x= [[0],[1],[2],[3],[4]];
foreach ($x as $i => &$upper) {
    print $i;
    foreach ($x as $j => &$lower) {

        if($i == 0 && $j == 2) {
            unset($x[2]);
        } else if($i == 1 && $j == 3) {
            unset($x[3]);
        }
    }
}

输出为01.令人惊讶的是,对于索引0和1,外部循环仅迭代两次.我期望输出为014.

我已经阅读了很多关于使用数组引用的危险的博客文章和问题,但没有任何东西可以解释这种现象.我现在已经好几个小时了.

编辑:

上面的代码是最小的可重现代码.一个似乎是这种情况的解释(但不正确)是:

在内部指针设置为索引2之前,外部循环经历两次迭代.但是循环在索引2处找不到任何元素,因此认为没有剩余元素并退出.

这个理论的问题是它没有完全解释这个代码

$x= [[0],[1],[2],[3],[4]];
foreach ($x as $i => &$upper) {
    print $i;
    foreach ($x as $j => &$lower) {

        if($i == 0 && $j == 2) {
            unset($x[2]);
            // No if else here
            unset($x[3]);
        }
    }
}

出于同样的原因,上面的代码也应该产生01,但它的实际输出是014,正如预期的那样.即使删除了一系列中的两个项目,PHP也知道仍然需要迭代的元素.这可能是PHP脚本引擎的错误吗?

解决方法:

一个简单的代码来重现您的问题:

$x = [0, 1, 2];
foreach ($x as $k => &$v) {
    print $k;
    if ($k == 0) {
        unset($x[1]);
    }
    end($x); // move IAP to end
    next($x); // move IAP past end (that's the same as foreach ($x as $y) {} would do)
}

如果你对一个数组进行预处理,它就会被复制(=迭代时没问题,你将迭代整个原始数组).
但是,如果您通过引用进行操作,则不会复制该数组(引用需要与原始数组匹配,因此无法复制).

Foreach内部始终保存下一个元素的位置以进行迭代.
但是当删除数组的下一个位置时,foreach需要返回数组并检查它的内部数组指针(IAP).

在这种情况下,下一个位置被破坏,IAP超过结束,它结束循环.

这就是你在这里看到的.

同样有趣的是:hhvm在这里PHP有不同的行为:http://3v4l.org/81rl8

附录:无限的foreach循环:

$x = [0,1,2];
foreach ($x as $k => &$v) {
    print $k;
    if ($k == 1) {
        unset($x[2]);
    } else {
        $x[2] = 1;
    }
    reset($x);
}

如果您理解我上面的解释,请猜出为什么无限循环.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐