PHP提前退出while循环

4

我对PHP比较陌生,目前遇到了一个奇怪的问题。这个文件是从多个函数中拼接而成的,为了测试和更容易地解释问题。

这是Laravel中的基本while循环,并且似乎过早地退出了,但奇怪的是没有在循环之后退出,而是在循环之前退出,然后再次进入。我不知道原因。我已经在整个函数中添加了一些日志事件,以便尝试理解发生了什么。

直到第7页,它正确地获取并写入产品到数据库,然后我在日志中得到了“Start API Helper”事件,但从未得到“End API Helper”。所以在第7页的某个地方,某些东西导致while循环退出到上面的行,将页面计数器重置为0。然后重新进入循环,获取第一批产品,并在写入时抛出SQL重复键异常。我知道它是在循环之前退出的,因为在日志的“New Client”之后,我得到了 “Before while”。当然,页面计数器也被重置了。这是怎么发生的?

非常感谢任何帮助。

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,以避免任何潜在的重复键错误。现在日志显示相同的“while exit”在第7页(偶尔第8页),然后重新进入循环在第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个回答

0
我猜到第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());
        }
    }

关于你的循环如何重新进入,可能是因为你在另一个try catch中包裹了store方法,以便重新尝试?因为我看不到函数内部有任何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,它将更新或创建DB记录。这解决了重复键问题,并将使进程继续运行,然后检查日志是否能够更好地解决问题。再次感谢。 - Jason Hill

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