在foreach循环中修改数组的值

143

我想知道是否可能在foreach循环中编辑当前正在处理的对象。

我正在使用对象数组$questions,并且我想遍历并查找与该问题对象相关联的答案。因此,对于每个问题,请获取答案对象并更新foreach循环内部的当前$question,以便我可以在其他地方进行输出/处理。

foreach($questions as $question){
    $question['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}

正如ArtjomKurapov和@topener所建议的那样,我正在寻找使用&符号的“按引用传递”。谢谢你们:)祝你们有美好的一天。 - Garbit
2个回答

266

有两种方法可以做到这一点

foreach($questions as $key => $question){
    $questions[$key]['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}

这样你就可以保存该键,以便在主要的$questions变量中再次更新它

或者

foreach($questions as &$question){

&加入后,将可以使$questions保持更新。但是我会建议使用第一个选项,即使这个选项比较长(参见Paystey的评论)

根据PHP foreach文档

为了能够直接修改循环内的数组元素,在$value前加上&。这种情况下,该值将被引用赋值。


43
foreach中使用引用并不推荐,因为foreach循环传递变量值的方式会导致不可预测的行为。尽管可能会更繁琐,但在这里使用方法1会更安全。 - Paystey
2
我刚刚花了一个困惑的小时来调试一个由于在foreach中使用引用而引起的问题。我为第二个foreach调用重复使用了相同的变量名 - 因为我通过引用传递了第一个,它一直修改数组中的最后一个项目!使用显式索引就不会有这个问题。 - Hippyjim
10
@Paystey,你能引用你的来源或提供详细的解释吗? - Nico
3
为什么操纵引用会不安全?在C/C++中,需要到处操纵引用就不安全吗?这取决于你是否让它变得安全,而不是语言本身。 - Kalzem
5
Paystey并没有说“一般情况下”的引用,而是针对类似这样的情况,在foreach中出现恐怖问题,具体内容请参考此链接:https://dev59.com/anA75IYBdhLWcg3wboUz (附注给Nico) - Sz.
显示剩余7条评论

10

使用array_map,如果使用实现了ArrayAccess的容器来派生对象,这只是一种更聪明、更语义化的方式,对吧?

就我看到过的大多数语言和实现而言,array_map的语义相似。它被设计为基于输入数组元素返回修改后的数组(高级别忽略语言编译/运行时类型偏好);循环则用于执行更多逻辑。

为了通过ID/PK检索对象,取决于您是否使用SQL(似乎建议是这样),我会使用过滤器来确保获得有效PK的数组,然后与逗号 implode 并放入SQL的IN()子句中返回结果集。它只需要一个SQL调用,优化了部分call->wait周期。最重要的是,我的代码可以让任何具有一定能力的人都能够轻松理解,并且我们不会遇到可变性问题。

<?php

$arr = [0,1,2,3,4];
$arr2 = array_map(function($value) { return is_int($value) ? $value*2 : $value; }, $arr);
var_dump($arr);
var_dump($arr2);

对战

<?php

$arr = [0,1,2,3,4];
foreach($arr as $i => $item) {
    $arr[$i] = is_int($item) ? $item * 2 : $item;
}
var_dump($arr);

如果您知道自己在做什么,就不会有可变性问题(请记住,如果您打算覆盖$arr,您始终可以使用$arr = array_map并明确说明)。


2
比使用foreach更直观 - 这正是这个函数的设计目的。 - benjaminhull
除非你没有访问密钥。 - COil

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