在 PHP 中重置 for 循环的指针

3

给定以下代码

<?php
$a = array(1,2,3,4,5,6);
$c=0;
foreach($a as $v){
    if($v==5&&$c==0){
        $c=1;
        reset($a);
    }
    var_dump($v);
}

如何重置指针,使其打印1、2、3、4、5、1、2、3、4、5、6?

我知道在这种情况下,我可以简单地:

<?php
$a = array(1,2,3,4,5,6);
$c=0;
for($i=0;$i<count($a);++$i){
    $v = $a[$i];
    if($v==5&&$c==0){
        $c=1;
        $i=-1;  //because of the loop ++$i
    }
    var_dump($v);
}

但是我有一段更复杂的代码,解决方案并不像重新编写循环(非数字键)那样简单。

有没有PHP大师能在这里帮助我?


你的第一个例子应该可以工作。reset() (http://php.net/manual/en/function.reset.php) 是这种情况下的函数。 - Ismael Miguel
它应该可以,但是它却不能! - Fabrizio
FYI,'foreach'实际上是如何工作的是很有趣的,也许你可以看一下:How 'foreach' actually works。我可以建议您在'foreach'循环中不要调整'内部指针'。当'内部指针'被重置时,还有其他的'循环'结构可以正常工作。 - Ryan Vincent
如果我能在不重置的情况下让它工作,那就太好了。我会查看链接,谢谢。 - Fabrizio
2个回答

6

注意:答案使用在 PHP 7.2 中已弃用的函数

正如 @TheodoreR.Smith 在评论中指出的那样,list() = each() 不适用于任何 PHP 版本 >= 7.2。请参见:

如何更新使用了不推荐使用的 each() 函数的代码?

适用于版本 < 7.2 的原始答案

如文档所述:

注意:当 foreach 开始执行时,内部数组指针会自动重置为数组的第一个元素。这意味着您不需要在 foreach 循环之前调用 reset()。

由于 foreach 依赖内部数组指针,在循环中更改它可能会导致意外行为

http://php.net/manual/en/control-structures.foreach.php

我不确定什么是“意外行为”,因为我从未尝试过这个...但也许更安全的方法是手动使用each()...在你的代码中也更清晰。

reset($a);
while(list($key, $val) = each($a)) {
    if($val==5&&$c==0){
        $c=1;
        reset($a);
    }
    var_dump($val);
}

解释Foreach问题

我曾经认为在foreach中不能依赖内部指针,但这次在文档中找不到相关内容,只有“意外结果”。然而,感谢一位评论者,我找到了曾经在foreach中的文本:

除非数组被引用,否则foreach将操作指定数组的副本而不是数组本身。foreach对数组指针有一些副作用。在foreach期间或之后不要依赖数组指针而不重置它。

http://php.net/manual/en/control-structures.foreach.php#114759


这里使用 while()each() 的组合是最佳解决方案。 - Ismael Miguel
@Fabrizio,是的...它实际上让我有点困惑...我以为它说在其他地方使用了不同的指针...根据那份文档,我同意reset()“应该”起作用。所以,我主要是根据评论中的“意外行为”方面来进行的。 - Kevin Nelson
@Fabrizio,好的,我更新了我的答案,并提供了一个可能尝试的解决方案...在foreach中尝试引用你的数组。 - Kevin Nelson
1
解析错误:第二个示例中在第3行出现语法错误,意外出现'&'。 - Ismael Miguel
@KevinNelson 我认为文档意思是 foreach($a as &$v)。但别担心,我的代码也曾让我看起来很蠢。或者,你可以尝试存储一个引用并重置该引用(或在数组开头添加一个元素)。 - Ismael Miguel
显示剩余4条评论

2
如果你是面向对象编程(OOP)的粉丝,你可以使用ArrayIterator类。
它拥有rewind()方法,该方法与reset()函数相同。
$a=array(1,2,3,4,5,6);//or $a=range(1,6);

$i=new ArrayIterator($a);

$c=0;

foreach($i as $k=>$v)
{
    if($v==5&&$c==0)
    {
        $c=1;
        $i->rewind();
    }
    var_dump($v);
}

unset($i);//delete the iterator, to free memory

您可以在http://writecodeonline.com/php/http://sandbox.onlinephpfunctions.com/上在线测试它。 @KevinNelson的回答是正确的方法,但对于不熟悉的人来说可能不太明显。
这段代码存在问题。
由于迭代,数字1在第二次循环时不会被输出。
但我有两个“科学怪人解决方案”! 解决方案1:使用next()方法跳过可忽略的元素。
$a=array(0,1,2,3,4,5,6);//or $a=range(0,6);

$i=new ArrayIterator($a);

$c=0;

$i->next();//jumps over the 1st element

foreach($i as $k=>$v)
{
    if($v==5&&$c==0)
    {
        $c=1;
        $i->rewind();
    }
    var_dump($v);
}

unset($i);

解决方案2:创建一个带有“假值”(0、null、false、''等)的元素,并在循环中忽略它。
$a=array(0,1,2,3,4,5,6);//or $a=range(0,6);

$i=new ArrayIterator($a);

$c=0;

foreach($i as $k=>$v)
{
    if($v==5&&$c==0)
    {
        $c=1;
        $i->rewind();
    }
    if($v)var_dump($v);
}

unset($i);

1
很奇怪,第二次跳过了第一个值:https://eval.in/312989 - jeroen
1
@jeroen 我用一些“弗兰肯代码”有点修复了它。 - Ismael Miguel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接