PHP多重foreach循环数组赋值异常:仅首个元素生效问题排查
问题分析与解决方案
你的代码出现问题的核心原因有两个:
1. 不匹配的$ready元素会覆盖已设置的属性
在你的内层foreach循环中,每一次遇到不匹配$gi->id的$rdy元素时,都会执行else分支,把$gi的属性重置为空。
比如处理$data['garduinduk'][0](id=1)时:
- 第一次循环匹配
$ready[0](lokasi=1),给$gi赋值了ON PROGRESS相关属性; - 但后面三次循环的
$rdy元素(lokasi=16、2、2)都不匹配id=1,每次都会执行else把属性清空; - 最终
$gi的属性会变成最后一次循环的结果——空值,这显然和你的预期不符。
2. 多个匹配项时,后续项会覆盖之前的赋值
对于有多个匹配$gi->id的$rdy元素(比如$data['garduinduk'][1]的id=2,对应$ready[2]和$ready[3]),你的代码会用最后一个匹配的元素覆盖之前的赋值。如果你的需求是优先显示On_progress状态,这种逻辑会导致优先级更高的状态被覆盖。
修正后的代码
我调整了逻辑,先给$gi设置默认空值,然后遍历$ready找匹配项,找到后赋值,并且如果是On_progress状态就直接跳出循环(保证优先级),去掉了会重置属性的else分支:
foreach ($data['garduinduk'] as $key => $gi){ // 先设置默认值,避免未找到匹配项时属性未定义 $gi->berlaku_dari = ''; $gi->berlaku_sampai = ''; $gi->file = ''; foreach ($ready as $rdy){ if ($rdy->lokasi == $gi->id){ if ($rdy->status == 'On_progress'){ $gi->berlaku_dari = 'ON PROGRESS'; $gi->berlaku_sampai = 'ON PROGRESS'; $gi->file = 'ON PROGRESS'; // 找到On_progress状态就跳出,避免被后续的Selesai项覆盖 break; }else{ $gi->berlaku_dari = $rdy->berlaku_dari; $gi->berlaku_sampai = $rdy->berlaku_sampai; $gi->file = $rdy->file; // 如果需要保留最新的Selesai记录,可以去掉上面的break,让最后一个匹配项生效 } } // 移除else分支,避免不匹配时清空已设置的属性 } }
额外优化建议
如果$ready数组的数据量较大,这种嵌套循环的效率会很低。你可以先把$ready数组转换成以lokasi为键的关联数组,这样可以直接通过$gi->id查找匹配项,时间复杂度从O(n*m)降到O(n+m):
// 先预处理$ready,按lokasi分组,保留On_progress优先的项 $readyMap = []; foreach ($ready as $rdy) { $lokasi = $rdy->lokasi; // 如果当前lokasi还没记录,或者已有记录不是On_progress,就更新 if (!isset($readyMap[$lokasi]) || $readyMap[$lokasi]->status != 'On_progress') { if ($rdy->status == 'On_progress') { $readyMap[$lokasi] = $rdy; } else { // 如果是Selesai,只有当没有On_progress时才保留 if (!isset($readyMap[$lokasi])) { $readyMap[$lokasi] = $rdy; } } } } // 然后遍历garduinduk直接取值 foreach ($data['garduinduk'] as $gi) { $gi->berlaku_dari = ''; $gi->berlaku_sampai = ''; $gi->file = ''; if (isset($readyMap[$gi->id])) { $rdy = $readyMap[$gi->id]; if ($rdy->status == 'On_progress') { $gi->berlaku_dari = 'ON PROGRESS'; $gi->berlaku_sampai = 'ON PROGRESS'; $gi->file = 'ON PROGRESS'; } else { $gi->berlaku_dari = $rdy->berlaku_dari; $gi->berlaku_sampai = $rdy->berlaku_sampai; $gi->file = $rdy->file; } } }
这种方式不仅效率更高,逻辑也更清晰,更容易维护。
内容的提问来源于stack exchange,提问作者highcal
相关产品推荐
相关产品推荐

