在fo​​reach循环电流()的意外行为 [英] Unexpected behaviour of current() in a foreach loop

查看:142
本文介绍了在fo​​reach循环电流()的意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是一个简单的循环

$list = array("A", "B", "C","D");
foreach ($list as $var) {
    print(current($list));
}

输出(演示

 BBBB   // Output for 5.2.4 - 5.5.0alpha4
 BCD    // Output for 4.4.1
 AAAA   // Output for 4.3.0 - 4.4.0, 4.4.2 - 5.2.3

问:


  • 可以有人请解释怎么回事?

  • 为什么我没有得到ABCD

  • 即使数组的一个副本是由的foreach 做我应该得到 AAAA ,但没有得到,在当前 PHP 稳定版

  • Can someone please explain whats going on ?
  • Why am i not getting ABCD
  • Even if a copy of the array was made by foreach i should be getting AAAA but not getting that in the current PHP stable version

注*我知道我可以简单地使用打印是$ var 但是从PHP DOC

Note* I know i can simply use print $var but the from PHP DOC

电流 - 返回当前数组中的元素
  该电流()函数只是返回的目前正由内部指针指向的数组元素的值。它不以任何方式移动指针。如果超出了元素列表或数组的末尾内部指针指向是空的,当前的()返回FALSE。

current — Return the current element in an array The current() function simply returns the value of the array element that's currently being pointed to by the internal pointer. It does not move the pointer in any way. If the internal pointer points beyond the end of the elements list or the array is empty, current() returns FALSE.

更新1 - 新观察

感谢 丹尼尔·菲格罗亚 :只需通过包装电流在函数中你会得到不同的结果。

Thanks to Daniel Figueroa : Just by wrapping current in a function you get different result

foreach ( $list as $var ) {
    print(item($list));
}

function item($list) {
    return current($list);
}

输出(演示

 BCDA   // What the hell 

问:


  • 为什么没有得到BBBB?

  • 如何在函数包装目前影响的foreach 输出?

  • 在哪里额外的A从何而来?

更新2

$list = array("A","B","C","D");
item2($list);
function item2($list) {
    foreach ( $list as $var ) {
        print(current($list));
    }
}

输出(见演示

AAAA // No longer BBBB when using a function

问:


  • 什么是不同的运行函数中的循环和功能外运行它,因为你得到 AAAA 之外, BBBB 在大多数PHP版本的函数

  • What is the different running a loop in a function and running it outside a function because you get AAAA outside and BBBB in a function in most PHP version

推荐答案

为什么它与B'开始

由于5.2 的foreach (可靠)推进前数组指针的 的循环体开始。又见 FE_RESET 运code。

Since 5.2 foreach (reliably) advances the array pointer before the loop body starts. See also the FE_RESET opcode.

$list = array("A", "B", "C","D");
foreach ($list as $var) {
    break;
}
var_dump(current($list));

输出:

B

这可能与东西怎么 ZEND_OP_DATA 伪运code ++工程,(这是不是真的记录)。

This may have something to with how the ZEND_OP_DATA pseudo opcode works (which isn't really documented).

为什么电流()继续给予同样的价值?

Why does current() keep giving the same value?

的foreach 创建一个内部参考,你遍历数组。一旦循环,每当数组变量通过引用改性或通过内部,内部参考从可变通过使阵列结构(但不是元素)的拷贝关联。这个复制的值保留数组指针(它早先被环路初始化修改)。

Before the loop starts, foreach creates an internal reference to the array that you're looping over. Once inside the loop, whenever the array variable is modified or passed by reference, the internal reference is disassociated from the variable by making a copy of the array structure (but not the elements). This copied value retains the array pointer (which had earlier been modified by the loop initialization).

此行​​为也表现出了更大的破坏性未设置()操作:

This behaviour is also exhibited with a more destructive unset() operation:

$list = array('A', 'B', 'C', 'D');
foreach ($list as $key => $val) {
  echo $val;
  unset($list[1], $list[2], $list[3]);
}
echo "\n", print_r($list, true), "\n";

输出:

ABCD
Array
(
    [0] => A
)

传递循环变量的函数

这是另一个有趣的场景:

This is another interesting scenario:

$list = array('A', 'B', 'C', 'D');
function itm($arr) 
{
    return current($arr);
}

foreach ($list as $item) {
    print itm($list);
}
var_dump(current($list));

输出:

BCDA
bool(false)

这时候,数组是按值传递,因此,其阵列结构被复制(而不是元素)到函数的 $改编参数。不同于previous例如,有循环的内部参考和 $列表符号之间没有解离,因为复制发生在函数范围内。

This time, the array is passed by value and thus its array structure is copied (not the elements) into the function's $arr parameter. Unlike the previous example, there's no disassociation between the loop's internal reference and the $list symbol because the copy takes place in the function scope.

怎么样的最后一个A

这是迄今为止的foreach 中最神秘的行为,只能在这些情况下见证。在最后的循环迭代,数组指针的看似的后退到第一个项目;似乎是因为在循环结束,这点显然超出了元素的末尾(你可以从输出的最后一行看到的)。

This is by far the most mystifying behaviour of foreach and can only be witnessed under these circumstances. In the last loop iteration, the array pointer is seemingly rewound to the first item; seemingly because at the end of the loop it obviously points beyond the end of the elements (as you can see from the last line of the output).

这可能有一些做的 SWITCH_FREE 这是在结束时执行运算code一的foreach

那么,为什么把的foreach 在功能使它不同?

So why does placing foreach in a function make it different?

遵守以下code:

function item2($arr) 
{
    foreach ($arr as $var) {
        print(current($arr));
    }
    var_dump(current($arr));
}
$list = array("A","B","C","D");
item2($list);

输出:

AAAA
string(1) "A"

在这种情况下,内部参考在的foreach 与所述数组的副本初始化(因为它具有引用计数> 1),从而创建从一个立即解除关联在 $改编符号。

In this case, the internal reference of the foreach is initialized with a copy of the array (because it has a refcount > 1) and thus creates an immediate disassociation from the $arr symbol.

它可以得到更糟?

当然!当你开始使用引用或嵌套多个的foreach 循环上相同的变量,你可以得到甚至whackier结果。

Of course! You can get even whackier results when you start using references or nest multiple foreach loops on the same variable.

那么如何才能得到一致的结果?

使用 迭代器 或不依赖于得到一个一致的值从的foreach 操作过程中引用数组变量。

Use Iterators or don't rely on getting a consistent value from referencing the array variable during a foreach operation.

这篇关于在fo​​reach循环电流()的意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆