PHP过早退出while循环
Posted
技术标签:
【中文标题】PHP过早退出while循环【英文标题】:PHP prematurely exiting while loop 【发布时间】:2015-09-14 22:11:21 【问题描述】:对 php 很陌生,我被困在一个(我认为)一个奇怪的问题上。我已经将这个文件拼接在一起,(它被分割成几个不同的函数)进行测试,并且更容易解释这个问题。
这是 Laravel 中的一个基本 while 循环,它似乎过早退出,但奇怪的是没有退出到循环之后的行,而是在循环之前退出然后再次进入。不能为我的生活锻炼为什么。我在整个函数中添加了一些日志事件,以便我可以尝试了解发生了什么。
在第 7 页之前,这可以正确地获取产品并将其写入数据库,然后我在日志中收到“启动 API 帮助程序”事件,但从未收到“结束 API 帮助程序”。因此,在第 7 页的某处某处导致 while 循环退出到上面的行,将 pagecount 重置为 0。然后重新进入循环,获取第一批产品并在写入时抛出 SQL 重复键异常。我知道它正在退出到循环之前,因为我在日志中的“新客户端”之后得到“之前”。当然,页数正在重置。这怎么可能发生?
任何帮助将不胜感激。
public function store()
$items = array();
Log::info('Before while');
$pagecount = 0;
$prodcount = 1;
while ($prodcount > 0)
Log::info('Top of while');
$prodcount = 0; // Reset product counter
Log::info('Page Count:'.$pagecount);
Log::info('Start API Helper');
$headers = array(
'NETOAPI_KEY' => env('NETO_API_KEY'),
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'NETOAPI_ACTION' => 'GetItem'
);
Log::info('Headers Declared');
$body = '
"Filter":
"DateAddedFrom" : "2013-06-01 12:00:00",
"Page": "'.$pagecount.'",
"Limit": "500",
"OutputSelector": [
**Lots of JSON here - removed for readability**
]
';
Log::info('Start API Helper');
$client = new client();
Log::info('New Client');
try
$res = $client->post(env('NETO_API_URL'), [ 'headers' => $headers , 'body' => $body ]);
catch (RequestException $e)
echo $e->getRequest();
Log::error($e->getRequest());
if ($e->hasResponse())
echo $e->getResponse();
Log::error($e->getResponse());
Log::info('End API Helper');
$items = json_decode(utf8_encode($res->getBody()), true);
foreach($items["Item"] as $item)
// JSON is returning an empty array for empty strings. Need to convert to empty string for SQL save.
foreach($item as $key => $value)
if (empty($value))
$item["$key"] = "";
$Product = new Item;
$Product->SKU = array_get($item, 'SKU');
** LOTS OF DB FIELDS REMOVED FROM HERE FOR READABILITY**
$Product->save();
$prodcount++;
$pagecount++;
Log::info($prodcount.' products written to DB:');
Log::info('Bottom of while');
;
Log::info('Exited While');
return 'Complete';
更新:我已将 ELoquent SQL 客户端修改为 firstorNew 以避免任何潜在的重复键错误。现在日志在第 7 页(偶尔在第 8 页)显示相同的“while exit”,然后在第 0 页重新进入循环,但最奇怪的是它似乎最终以 2 个循环实例运行。然后最终是 3 个实例,然后是 4 个。然后它抛出一个内存耗尽异常。日志看起来像。
local.INFO: Page Count:1
local.INFO: Page Count:2
local.INFO: Page Count:3
local.INFO: Page Count:4
local.INFO: Page Count:5
local.INFO: Page Count:6
local.INFO: Page Count:7
local.INFO: Page Count:8
local.INFO: Page Count:0
local.INFO: Page Count:9
local.INFO: Page Count:1
local.INFO: Page Count:10
local.INFO: Page Count:2
local.INFO: Page Count:11
local.INFO: Page Count:3
local.INFO: Page Count:12
...等等...
格式错误的 JSON API 响应是否可能导致此问题?也许我会尝试将分页限制在 25 左右,这样我就可以访问导致循环中断的响应?
【问题讨论】:
【参考方案1】:我猜从第 7 页开始,您的处理行数已用完,以下 API 调用以某种方式失败:
try
$res = $client->post(env('NETO_API_URL'), [ 'headers' => $headers , 'body' => $body ]);
catch (RequestException $e)
echo $e->getRequest();
Log::error($e->getRequest());
if ($e->hasResponse())
echo $e->getResponse();
Log::error($e->getResponse());
至于您的循环如何重新进入很可能是因为您将 store 方法包装在另一个重新尝试的 try catch 中?因为我在函数内部看不到任何表示循环重新启动的 try catch。
我的建议是将您的方法重写为 do-while 循环并将您的 while 条件修改为:
while ($prodcount === 500)
这将确保您不会进行任何您知道没有意义的后续 API 调用,并减少代码中出现问题的可能性。
另一个不错的检查是在您的响应对象上:
if (!isset($items["Item"]))
echo 'Response contains no "Item" value';
exit;
除此之外,如果不添加更多日志记录和更多 var_dump() / print_r() 来逐步执行您的逻辑,这很难调试。
祝你好运。
【讨论】:
嗨,丹。非常感谢您的回复。我已将循环修改为 do-while,这是一个好主意,谢谢!我还添加了空数组循环出口。当然,我仍然被困在循环问题上。在第 7 页之后还有更多产品页面。我已将 Eloquent 修改为 firstOrNew,它将更新或创建数据库记录。这已经解决了重复密钥问题,并将让进程继续运行,然后查看日志以查看是否可以进一步说明问题。再次感谢。以上是关于PHP过早退出while循环的主要内容,如果未能解决你的问题,请参考以下文章