php - 尝试、捕获和重试

问题描述 投票:0回答:8

有时我的代码会崩溃并且超出我的控制范围

我将如何执行以下操作?

try {
//do my stuff
}
catch {
//sleep and try again
}

代码不多,所以都是一个函数,所以如果不需要的话我不想创建和调用另一个函数

php try-catch
8个回答
89
投票

你可以尝试这样的事情:

function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");

$NUM_OF_ATTEMPTS = 5;
$attempts = 0;

do {

    try
    {
        executeCode();
    } catch (Exception $e) {
        $attempts++;
        sleep(1);
        continue;
    }
    
    break;

} while($attempts < $NUM_OF_ATTEMPTS);

function executeCode(){
    echo "Hello world!";
}

在这里,我们执行一个

do...while
循环,以便代码至少执行一次。如果
executeCode()
函数遇到错误,它将抛出
Exception
try...catch
块将捕获该错误。然后,
catch
块会将变量
$attempt
加 1,并调用
continue
来测试下一次迭代的
while
条件。如果已经进行了五次尝试,则循环将退出并且脚本可以继续。如果没有错误,即
continue
块中的
catch
语句未执行,则循环将
break
,从而完成脚本。

请注意

set_error_handler
函数的使用,取自here。我们这样做是为了捕获
executeCode()
函数中的所有错误,即使我们自己不手动抛出错误。

如果您认为您的代码可能会多次失败,则在 sleep()

 语句之前使用 
continue
 函数可能会有所帮助。 “减慢”可能的无限循环将有助于降低您的 
CPU Usage

让脚本无限运行直到成功并不是一个好主意,因为循环的前 100 次迭代中出现的错误不太可能得到解决,从而导致脚本“冻结”。通常,最好重新评估您希望在出现错误时多次运行的代码,并对其进行改进以正确处理出现的任何错误。


11
投票

简单地说:

function doSomething($params, $try = 1){
    try{
        //do something
        return true;
    }
    catch(Exception $e){
        if($try <5){
             sleep(10);
             //optionnaly log or send notice mail with $e and $try
             doSomething($params, $try++);
        }
        else{ 
             return false;
        }
    }
}

8
投票

这是一个简单的算法:

$trys = 5;
do {
    try {
        // YOUR CODE
        // YOUR CODE
        // YOUR CODE
        // YOUR CODE
        // YOUR CODE

        break;
    }
    catch(Exception $e) {
        $trys--;
    }
} while($trys > 0);

另外,为了无限次尝试,请删除

$trys--
行:)


2
投票

这个库看起来很酷,它有不同的退避策略可供您选择,并且可以让您不必每次都实现重试逻辑。

https://github.com/stechstudio/backoff

示例代码:

$result = backoff(function() {
    return doSomeWorkThatMightFail();
});

1
投票

我不完全理解你为什么想要这样做,因为你很可能会创建一个无限循环。但是,如果代码在短暂的睡眠后可能会成功,无论出于何种原因,下面是一个解决方案

while(true){
    // execute the code you are attempting
    if(some condition to signal success){
        break; // exit the loop
    }

    sleep(2); // 2 seconds
}

0
投票

我推荐这个库:PHP Backoff

它允许他们执行代码,如果由于某种原因发生某些事情并失败,它会自动作为任务重新运行。它有多种配置,因此您可以根据您的需求进行调整。

安装:

composer require stechstudio/backoff

快速入门

$result = backoff(function() {
    // Here is the function they want to execute.
    return doSomeWorkThatMightFail();
});

所有文档都在这里: https://github.com/stechstudio/backoff


0
投票

针对此类问题,Laravel 中嵌入了一个非常优雅的解决方案,可以轻松移植到任何 php 框架/项目。

它使用控制结构 goto 循环回到异常发生之前再次运行代码,除非满足条件。

https://www.php.net/manual/en/control-structs.goto.php

更多信息: https://laravel.com/docs/10.x/helpers#method-retry

function retry($times, callable $callback, $sleepMilliseconds = 0, $when = null)
    {
        $attempts = 0;

        $backoff = [];

        if (is_array($times)) {
            $backoff = $times;

            $times = count($times) + 1;
        }

        beginning:
        $attempts++;
        $times--;

        try {
            return $callback($attempts);
        } catch (Exception $e) {
            if ($times < 1 || ($when && ! $when($e))) {
                throw $e;
            }

            $sleepMilliseconds = $backoff[$attempts - 1] ?? $sleepMilliseconds;

            if ($sleepMilliseconds) {
                usleep(value($sleepMilliseconds, $attempts, $e) * 1000);
            }

            goto beginning;
        }
    }

-2
投票

为了能够捕获异常,您必须首先抛出异常。 像这样的东西。

<?php
function inverse($x) {
    if (!$x) {
        throw new Exception('Division by zero.');
    }
    return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}

// Continue execution
echo "Hello World\n";
?>

有某些内置异常:http://php.net/manual/en/spl.exceptions.php

© www.soinside.com 2019 - 2024. All rights reserved.