PHP7迁移至PHP8:each()函数替换后循环及行数异常问题
PHP7迁移PHP8:each()替换foreach后的问题修复
问题背景
将PHP7脚本迁移至PHP8时,原代码依赖已废弃的each()函数,两次替换为foreach后均出现异常:
- 首次修改后触发无限循环
- 二次修改后虽能运行,但原本3列多行的表格变为3列、行数为原3倍,且列值依次单独变动,不符合预期
原代码(PHP7环境)
do { $Tabelle->SetLine(array_values($Line)); foreach($Line as $Spalte => $Kapitel) { list($Name, $URL) = each($URLs[$Spalte]); if ($URL == "") $Line[$Spalte] = $Name; else $Line[$Spalte] = '<a href="'.$URL.'">'.$Name.'</a>'; } } while (reset($Line) != "" || next($Line) != "" || next($Line) != "");
首次修改代码(出现无限循环)
do { $Tabelle->SetLine(array_values($Line)); foreach($Line as $Spalte => $Kapitel) { foreach($URLs[$Spalte] as $Name => $URL) if ($URL == "") $Line[$Spalte] = $Name; else $Line[$Spalte] = '<a href="'.$URL.'">'.$Name.'</a>'; } } while (reset($Line) != "" || next($Line) != "" || next($Line) != "");
二次修改代码(表格行数异常)
$Tabelle->SetLine(array_values($Line)); foreach($Line as $Spalte => $Kapitel) { foreach($URLs[$Spalte] as $Name => $URL) { if ($URL == "") $Line[$Spalte] = $Name; else $Line[$Spalte] = '<a href="'.$URL.'">'.$Name.'</a>'; $Tabelle->SetLine(array_values($Line)); } }
问题分析
首次修改的问题:
内层foreach会遍历$URLs[$Spalte]的所有元素,最终$Line[$Spalte]会被赋值为该列URL数组的最后一个元素;外层do-while的判断条件永远为真(因为$Line始终被赋值为非空内容),导致无限循环。二次修改的问题:
将$Tabelle->SetLine()移至内层foreach后,每处理一个URL元素就添加一行表格,3列的URL数组各有n个元素时,会生成3n行;且每次仅修改一列的值,导致列值单独变动。原代码逻辑:
each()函数每次调用会返回数组的下一个元素并移动指针,原代码通过do-while循环,每次迭代为所有列分配当前指针位置的URL元素,直到所有列的指针都走到数组末尾,从而生成与URL数组行数匹配的表格行。
正确修改方案
模拟原each()的指针遍历逻辑,通过索引统一控制所有列的URL元素读取:
// 预存每个列URL数组的键列表 $urlColumnKeys = []; foreach ($URLs as $spalte => $urlList) { $urlColumnKeys[$spalte] = array_keys($urlList); } $currentRowIndex = 0; $hasValidData = true; do { $hasValidData = false; foreach ($Line as $spalte => $_) { // 检查当前列是否存在对应索引的URL元素 if (isset($urlColumnKeys[$spalte][$currentRowIndex])) { $hasValidData = true; $name = $urlColumnKeys[$spalte][$currentRowIndex]; $url = $URLs[$spalte][$name]; $Line[$spalte] = $url === "" ? $name : '<a href="'.$url.'">'.$name.'</a>'; } else { // 无数据时设为空,确保循环能终止 $Line[$spalte] = ""; } } if ($hasValidData) { $Tabelle->SetLine(array_values($Line)); } $currentRowIndex++; } while ($hasValidData);
逻辑说明
- 先收集每个列URL数组的键集合,避免每次循环重复计算
- 通过统一的行索引
$currentRowIndex,同步读取所有列的对应位置元素 - 每次迭代生成完整的一行表格数据后,再调用
SetLine()添加行 - 当所有列都没有对应索引的元素时,终止循环,避免无限执行
内容的提问来源于stack exchange,提问作者Rscompu
相关产品推荐
相关产品推荐

