在foreach循环内更改初始数组?

30
我想要一个foreach循环,在循环内部改变初始数组。
例如:
$array = array('red', 'blue');
foreach($array as $key => $value) {
    $array[] = 'white';
    echo $value . '<br />';
}
在这个循环中,尽管我在循环内添加了另一个元素,但循环仍将打印出红色和蓝色。
有没有办法在循环内更改初始数组,以便新元素被添加,foreach将使用新数组无论发生什么变化?
我需要这种逻辑来完成一个特定的任务:
我将有一个if语句来搜索链接。 如果存在该链接,则将其添加到数组中。 将获取链接内容以进行检查,是否包含另一个链接。 如果是,则添加此链接,并获取其内容,以此类推......当不再找到链接时,foreach循环将退出。

1
你是否意识到,如果没有任何中断,你的想法会陷入无限循环? - Enrico Carlesso
5个回答

45
我不认为用foreach循环实现这个是可能的,至少按照你的写法来看,似乎不是foreach的工作方式;引用{{link1:foreach的手册页面}}的说法:
引用: 注意:除非数组被引用,否则foreach操作的是指定数组的副本,而不是数组本身。
编辑:经过对这个注释的一番思考,事实上是有可能的,以下是解决方案:
这个注释说“除非数组被引用”,这意味着代码的这部分应该可以工作:
$i = 0;
$array = array('red', 'blue');
foreach($array as $key => & $value) {
    $array[] = 'white';
    echo $value . '<br />';
    if ($i++ >= 5) {
        break;   // security measure to ensure non-endless loop
    }
}

请注意在$value之前的&符号。
实际上,它显示的是:
red
blue
white
white
white
white

这意味着在foreach循环内部添加&实际上是你正在寻找的解决方案,用于修改数组。;-)
编辑:这是我在考虑那个注释之前提出的解决方案:

你可以使用一个while循环来做到这一点,手动多做一些工作;例如:

$i = 0;

$array = array('red', 'blue');

$value = reset($array);
while ($value) {
    $array[] = 'white';
    echo $value . '<br />';
    if ($i++ >= 5) {
        break;   // security measure to ensure non-endless loop
    }
    $value = next($array);
}

将为您提供以下输出内容:
red
blue
white
white
white
white

1
在我发布的示例中,由于我使用了安全计数器来防止无限循环,你会得到4个“white”:在6次迭代后,break将强制结束循环。*(你在问题中提供的代码导致了无限循环,而我不希望在我的示例中出现这种情况)*;在你的应用程序中,你需要找到适合你需求的解决方案以避免无限循环 :-) (从你的问题中可以看出,你已经有了解决方案,即使你没有将其作为问题的一部分包含在内) - Pascal MARTIN
不太明白为什么引用的是 $value 而不是 $array...但如果它能工作那就很好了...你测试过这段代码吗?干杯。 - DCC
我的天啊,只需要一个小的&符号!(就在手册的foreach页面上) - David Gilbertson
3
不要忘记在foreach循环结束后取消 $value 的值赋值,否则下一次在另一个foreach循环中使用$value时,可能会出现一些奇怪的行为。 - JaredC
正是我所需要的,谢谢。在我的情况下,我只是从PDO结果中循环遍历多维数组。为了防止无限循环,如果当前值符合条件,我将其array_push到引用数组的末尾,然后将该值数组的唯一标识符存储到单独的$pushed数组中,以便在每个foreach循环中检查它是否存在于$pushed中。 - DaveK
显示剩余4条评论

8

您需要做的是将赋值操作放到for循环中,并在每个迭代中检查数组的长度。

$array = array('red', 'blue');
for($i = 0; $i < count($array); $i++)
{
   $value = $array[$i];
   array_push($array, 'white');
   echo $value . '<br />';
}

注意,这会引起无限循环(每次循环都会将白色添加到数组末尾)。


1
尽管之前的答案已被接受,但是对我来说,这个实际上更好地实现了通过循环来影响数组的目标。使用以上答案(“正确”的答案)会不断重置数组内部的指针,导致各种问题。请使用这个。感谢作者,请注意你的回答中 $array[$i] 的引用是错误的。 - Dormouse

4
也许你应该使用其他方式,比如:
$ar = array('blue', 'red');
while ($a = array_pop($ar) {
     array_push($ar, 'white');
}

或者像这样...

你如何确保只添加并打印一次白色?因为你的代码会导致无限循环。 - ajsie
我并没有。正如评论中指出的那样,编程人员编写聪明代码是他们自己的责任...显然,像我写的这样它将永远运行,这只是一个例子。 - Enrico Carlesso
@noname在使用array_push之前可以使用if .. else ..以及in_array来检查是否已经在一个名为“record”的重复数组中。 :) - DCC

1
为了能够在循环中直接修改数组元素,在 $value 前加上 &。这样的话,该值将通过 引用 进行赋值。[来源]
只需将旧代码更改为:
$value 前加上 &
$array = array('red', 'blue');
foreach($array as $key => &$value) {// <-- here
    $array[] = 'white';
    echo $value . '<br />';
}

一个while循环会是更好的解决方案。
while (list ($key, $value) = each ($array) ) {
    $array[] = 'white';
    echo $value . '<br />';
}

如果您不需要$key变量,就像您的示例所示,那么使用$value = array_pop($array)而不是list ($key, $value) = each ($array)将是一种更经济的选择。请参见@enrico-carlesso's答案此处
由于您的数组是顺序(数字,索引)而不是关联的,因此您可以改用for循环。
for ($key = 0; $key < count($array); ++$key) {
    $value = $array[$i];

    $array[] = 'white';
    echo $value . '<br />';
}

作为一则旁注。
我不明白为什么是&$value而不是&array&$value表明你只能修改循环中的当前元素。 &array则表明你可以修改循环中的所有数组元素,包括添加/删除元素。

1
您可以通过使用 $key 访问数组。
$array = array('red', 'blue');
foreach($array as $key => $value) {
    $array[$key] = 'white';
}

你没有理解问题,这不是一个答案。 - Christopher Thomas

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