foreach循环中current()的意外行为
这个问题在这里已经有了答案:
为什么它以B开头?
由于foreach
(可靠地)在循环体开始前提前数组指针。 另请参阅FE_RESET
操作码。
$list = array("A", "B", "C","D");
foreach ($list as $var) {
break;
}
var_dump(current($list));
输出:
B
这可能与ZEND_OP_DATA
伪操作码的工作方式有关(没有真正记录)。
为什么current()
一直给出相同的值?
在循环开始之前, foreach
为你正在循环的数组创建一个内部引用。 一旦进入循环,每当数组变量被修改或通过引用传递时,通过复制数组结构(而不是元素)来将内部引用从变量中解除关联。 该复制值保留了数组指针(之前已通过循环初始化进行修改)。
这种行为还会带来更具破坏性的unset()
操作:
$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
)
将循环变量传递给一个函数
这是另一个有趣的场景:
$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)
这一次,数组是通过值传递的,因此它的数组结构被复制(而不是元素)到函数的$arr
参数中。 与前面的示例不同,循环的内部引用和$list
符号之间没有分离,因为复制发生在函数作用域中。
最后的"A"
呢?
这是迄今为止最神秘行为foreach
,只能在这些情况下见证。 在最后一次循环迭代中,数组指针看似倒回到第一个项目; 看起来是因为在循环结束时它显然指向元素的末尾(正如你可以从输出的最后一行看到的那样)。
这可能与在foreach
结尾执行的SWITCH_FREE
操作码有关。
那么为什么在一个函数中放置foreach
使它与众不同呢?
请注意以下代码:
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
的内部引用会使用数组的副本进行初始化(因为它的refcount> 1),因此会立即从$arr
符号中解除关联。
它会变得更糟吗?
当然! 当你开始使用引用或者在同一个变量上嵌套多个foreach
循环时,你甚至可能会产生令人怀疑的结果。
那么我怎样才能获得一致的结果呢?
使用Iterators
或不要依靠在foreach
操作期间引用数组变量来获取一致的值。
FROM PHP.net
current()函数只是返回当前内部指针指向的数组元素的值。 它不会以任何方式移动指针
然后:使用next()
$list = array("A", "B", "C","D");
foreach ($list as $var) {
print(current($list));
next($list);
}
注:第一个元素将不会被打印,因为foreach将指针移动到数组的第二个元素:)
这个例子将解释完整的行为:
$list = array("A", "B", "C","D");
foreach ($list as $var) {
if(!isset($a)) reset($list); $a = 'isset';
print(current($list));
next($list);
}
输出是ABCD
还请注意:
As foreach relies on the internal array pointer changing it within the loop
may lead to unexpected behavior.
的foreach
编辑:我想分享我的新混乱发现!
例1:
$list = array("A", "B", "C","D");
$list_copy = $list;
foreach ($list as $key => $val) {
current($list_copy);
echo current($list);
//next($list);
}
输出:AAAA
例2:
$list = array("A", "B", "C","D");
$list_copy = $list;
foreach ($list as $key => $val) {
current($list_copy);
echo current($list);
next($list);
}
输出:ABCD
当在foreach中调用current()函数时,即使对于另一个数组,它也会影响foreach行为...
示例3:
$list = array("A", "B", "C","D");
$refcopy = &$list;
foreach ($list as $key => $val) {
if(!isset($a)) { $a = 'isset'; reset($list); }
echo current($list);
next($list);
}
输出:ACD(WOW! B缺失)
例如:4
$list = array("A", "B", "C","D");
$refcopy = &$list;
foreach ($list as $key => $val) {
echo current($list);
next($list);
}
输出:BCD
无法确定在foreach循环内会发生什么!
那么,我不知道这是为什么,但我怀疑它可能与如何评估/处理任务有关。 为了好玩,我尝试了这一点,并导致另一个incorrect
行为:
$arr = array('A', 'B', 'C', 'D');
function itm($val) {
return current($val);
}
foreach ($arr as $item) {
print itm($arr);
}
结果:BCDA
所以我的猜测是,这里发生的事情是函数调用迫使评估电流以正确的方式发生。 此外,我得到BCDA而不是ABCD的原因可能是因为内部指针首先增加(指向B),然后在en中重新指向A点。
在PHP文档中可能值得注意这一行:
请注意,作业将原始变量复制到新变量(按值分配),因此对其中一个的更改不会影响另一个。 如果您需要在紧密循环内复制类似大数组的东西,这也可能具有相关性。
我想这不算是一个答案,但我喜欢你的问题,并希望贡献一点。
链接地址: http://www.djcxy.com/p/53023.html上一篇: Unexpected behaviour of current() in a foreach loop
下一篇: PHP foreach inside loop on array that added inside the loop