slashequip/attempt

Attempt是一个简单、流畅的类,用于尝试多次运行代码同时处理异常。

1.0.0 2022-01-16 10:00 UTC

This package is auto-updated.

Last update: 2024-09-16 16:05:22 UTC


README

Attempt是一个简单、流畅的类,用于尝试多次运行代码同时处理异常。它在可能的情况下尝试模仿PHP内置的try/catch语法,但在此基础上增加了一些额外的魔法。

安装

Attempt已添加到packagist,可以通过composer安装

composer require slashequip/attempt

获取实例

根据您的偏好,您可以通过几种方式获取Attempt实例

use SlashEquip\Attempt\Attempt;

$attempt = new Attempt();

$attempt = Attempt::make();

构建Attempt

一旦您有了实例,就可以开始构建您的Attempt。

尝试

这是唯一必需的方法,try方法接受一个可调用参数,即您想要运行的代码。

$attempt
    ->try(function () {
        // My code that may or may not work.
    })
    ->thenReturn();

然后返回

您可能已经注意到上面的示例中的thenReturn方法,这个方法告诉Attempt运行。它还会返回您传递给try方法的可调用的返回值。

还有一个then方法,它也接受一个可调用参数,该参数将被执行,并将传递给try可调用的返回值。

如果您喜欢,Attempt也是可调用的,这意味着在任何时候都可以调用Attempt,并且它将运行。

// $valueOne will be true
$valueOne = $attempt
    ->try(function () {
        return true;
    })
    ->thenReturn();

// $valueTwo will be false
$valueTwo = $attempt
    ->try(function () {
        return true;
    })
    ->then(function ($result) {
        return !$result;
    });

// $valueThree will be true
$valueThree = $attempt
    ->try(function () {
        return true;
    })();

次数

您可以在遇到异常时设置Attempt应该尝试的次数见catch

$valueOne = $attempt
    ->try(function () {
        throw new RuntimeException();
    })
    ->times(5)
    ->thenReturn();
// The above code would be run 5 times before throwing the RuntimeException

捕获

catch方法允许您定义在尝试过程中可能遇到的异常,当将异常传递给catch方法时,Attempt将提前抛出它遇到的任何其他类型的异常,而不是执行所有尝试。

catch方法可以多次调用以添加多个预期的异常。

如果您没有通过catch方法提供任何预期的异常,那么Attempt将忽略所有异常,直到所有尝试都完成。

$attempt
    ->try(function () {
        throw new UnexpectedException;
    })
    ->catch(TheExceptionWeAreExpecting::class)
    ->catch(AnotherExceptionWeAreExpecting::class)
    ->thenReturn();

// In this example; only one attempt would be made and a UnexpectedException would be thrown

catch方法还允许您定义一个回调,当指定的异常最终抛出时将被调用。这可以用于错误记录,或者如果您的代码需要继续,您还可以返回默认值。

$attempt
    ->try(function () {
        throw new AnExpectedException;
    })
    ->catch(AnExpectedException::class, function (AnExpectedException $e) {
        error_log($e->getMessage());
        return new NullBlogPost();
    })
    ->thenReturn();

不抛出

Attempt可以被配置为永不抛出异常,有些情况下您需要执行一些代码,但仍然继续执行您的逻辑。对于这些情况,您可以使用noThrow

$attempt
    ->try(function () {
        throw new RuntimeException();
    })
    ->noThrow()
    ->thenReturn();
// The above exception would not bubble up and instead, simply, be swallowed.

最终

finally方法允许您在尝试结束时运行一个回调无论结果如何,无论尝试是否成功或抛出了异常,finally回调始终会被运行。

$attempt
    ->try(function () {
        throw new UnexpectedException;
    })
    ->finally(function () {
        // run some clean up.
    })
    ->thenReturn();

// In this example; the finally callback would be run before the UnexpectedException is thrown

等待间隔

waitBetween方法接受一个整数,表示尝试之间的期望毫秒数。暂停发生在代码运行之前,但不会延迟Attempt的开始。

$attempt
    ->try(function () use ($data) {
        throw new UnexpectedException;
    })
    ->times(3)
    ->waitBetween(250)
    ->thenReturn();

// In this example, there would be a pause of 250 milliseconds between each attempt.

示例用例

use SlashEquip\Attempt\Attempt;
use GuzzleHttp\Exception\ClientException;

$blogPost = Attempt::make()
    ->try(function () use ($data) {
        return UnstableBlogApiServiceUsingGuzzle::post([
           'data' => $data,
        ]);
    })
    ->times(3)
    ->waitBetween(250)
    ->catch(ClientException::class, function (ClientException $e) {
        error_log("Unstable blog api service is causing issues again.")
        return new BlogPost::nullableObject();
    })
    ->then(function ($apiResponse) {
        return BlogPost::fromApiResponse($apiResponse);
    });