有时我的代码会崩溃并且超出我的控制范围
我将如何执行以下操作?
try {
//do my stuff
}
catch {
//sleep and try again
}
代码不多,所以都是一个函数,所以如果不需要的话我不想创建和调用另一个函数
你可以尝试这样的事情:
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 次迭代中出现的错误不太可能得到解决,从而导致脚本“冻结”。通常,最好重新评估您希望在出现错误时多次运行的代码,并对其进行改进以正确处理出现的任何错误。
简单地说:
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;
}
}
}
这是一个简单的算法:
$trys = 5;
do {
try {
// YOUR CODE
// YOUR CODE
// YOUR CODE
// YOUR CODE
// YOUR CODE
break;
}
catch(Exception $e) {
$trys--;
}
} while($trys > 0);
另外,为了无限次尝试,请删除
$trys--
行:)
这个库看起来很酷,它有不同的退避策略可供您选择,并且可以让您不必每次都实现重试逻辑。
https://github.com/stechstudio/backoff
示例代码:
$result = backoff(function() {
return doSomeWorkThatMightFail();
});
我不完全理解你为什么想要这样做,因为你很可能会创建一个无限循环。但是,如果代码在短暂的睡眠后可能会成功,无论出于何种原因,下面是一个解决方案
while(true){
// execute the code you are attempting
if(some condition to signal success){
break; // exit the loop
}
sleep(2); // 2 seconds
}
我推荐这个库:PHP Backoff
它允许他们执行代码,如果由于某种原因发生某些事情并失败,它会自动作为任务重新运行。它有多种配置,因此您可以根据您的需求进行调整。
安装:
composer require stechstudio/backoff
快速入门
$result = backoff(function() {
// Here is the function they want to execute.
return doSomeWorkThatMightFail();
});
所有文档都在这里: https://github.com/stechstudio/backoff
针对此类问题,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;
}
}
为了能够捕获异常,您必须首先抛出异常。 像这样的东西。
<?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";
?>