PHP7.4循环调用API时isset判断引发504超时与空数组偏移问题求助
根因说明
你遇到的超时和isset函数本身完全无关,isset是PHP内核实现的轻量判断函数,不可能引发超时。真正的问题是你的循环逻辑存在严重的重复API调用问题:
- 你在
while遍历每一条数据库返回行的内部,额外加了一层foreach ($row as $key => $value)遍历当前行的所有字段。只要某一轮遍历中$sudCode和$sudBroj被赋值后,后续遍历其他字段时这两个变量依旧保留有效值,会重复触发ePredmetiAPI调用,相当于一行数据你调用了N次API(N为行字段数),数据量上来后必然会因为API调用次数过多导致超时。 - 你移除
isset判断后脚本能跑完,只是因为少了后续的逻辑处理,执行速度变快刚好没触发Apache超时阈值,本质问题并没有解决。
可行解决方案
步骤1:修复UNION查询,统一字段别名
UNION查询的结果集字段名由第一个查询决定,给字段加统一别名避免后续取值混乱:
$results = mysqli_query($con, " SELECT DISTINCT predf_nas_br as nas_br, predf_odv as odv, predf_SUD as sud, predf_SUDBROJ as sud_broj FROM PREDMETIFView WHERE predf_SUD <> '' AND predf_SUDBROJ <> '' AND predf_SUDBROJ NOT LIKE '% %' UNION ALL SELECT DISTINCT predp_nas_br as nas_br, predp_odv as odv, predp_SUD as sud, predp_SUDBROJ as sud_broj FROM PREDMETIPView WHERE predp_SUD <> '' AND predp_SUDBROJ <> '' AND predp_SUDBROJ NOT LIKE '% %' ;");
步骤2:预生成sud映射表,删除低效遍历查询
原来的findSudCode每次调用都要遍历整个数组,预转成键值对映射表后可以O(1)取值:
// 原eSudovi()函数保持不变,处理返回结果时转映射表 $eSudovi = eSudovi()["data"]["sudovi"] ?? []; $sudoviMap = []; foreach ($eSudovi as $item) { $sudoviMap[trim($item['sudNaziv'])] = $item['id']; }
步骤3:给CURL加超时配置,避免单请求阻塞
在eSudovi()和ePredmeti()两个函数的CURL配置段添加超时规则:
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 连接超时5秒 curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 整个请求最多等待10秒
步骤4:重写核心循环,删除多余字段遍历
彻底去掉内层的foreach ($row as $key => $value),一行数据仅调用一次API:
while ($row = $results->fetch_assoc()) { $nas = $row['nas_br'] ?? ''; $sud = trim($row['sud'] ?? ''); $sudBroj = trim($row['sud_broj'] ?? ''); $sudCode = $sudoviMap[$sud] ?? null; // 无效参数直接跳过 if (empty($sudCode) || empty($sudBroj)) { continue; } $epredmet = ePredmeti($sudCode, $sudBroj); // 仅匹配lastUpdateTime为有效字符串的第三种场景 if (!empty($epredmet['data']['prvi']['lastUpdateTime']) && is_string($epredmet['data']['prvi']['lastUpdateTime'])) { $lastUpdateTime = $epredmet["data"]["prvi"]["lastUpdateTime"]; $dateTime = str_replace("T", " ", $lastUpdateTime); echo $nas . " - " . $dateTime . "<br>"; } }
额外优化建议
如果数据量较大,可以给API调用增加本地缓存,相同$sudCode + $sudBroj的请求不用重复调用接口,进一步减少请求量。
内容的提问来源于stack exchange,提问作者ikiK
相关产品推荐
相关产品推荐

