skd/result

在PHP中实现结果对象模式

v0.1 2024-01-01 10:53 UTC

This package is auto-updated.

Last update: 2024-09-03 19:21:22 UTC


README

此包允许您以面向对象的方式处理操作的结果,包括错误,而不使用异常。例如,当使用“始终有效的领域模型”方法时。结果对象允许您一次性累积错误并返回它们(在通知模式内部)。同时,代码变得更加易懂和逻辑。

安装

composer require skd/result

结果

Result 类是一个不可变的泛型类(使用 @template 注解),具有两种状态:OkErrorOK 状态表示内部没有错误,并且存在一些值(成功操作结果)。Error 状态表示在操作过程中收到了错误或多个错误。

使用 @return Result<type_or_class> 注解来告诉 IDE 和静态分析工具内部值的类型;

Ok 状态

使用静态方法 Result::ok 来返回包含某些值的成功操作结果

use Skd\Result\Result;

// some code
return Skd\Result\Result::ok($value);

使用方法 Result::getValue(): T 来获取值。注意,在错误状态下调用此方法将抛出异常。为了防止这种情况,您必须通过调用 Result::isOk(): boolResult::isError(): bool 中的任意一个方法来检查结果状态。

if($result->isOk()) {
    $value = $result->getValue();
}

Error 状态

使用静态方法 Result:error(Notification $errors) 来返回包含错误(错误)的结果。必须将非空 Notification 对象作为参数传递。传递空 Notification 对象(内部没有错误)将抛出异常。

use Skd\Result\Result;
use Skd\Result\Error\Notification;

// some code

$error = new Error(...);
$errors = new Notification($error);

return Skd\Result\Result::error($errors);

使用方法 Result::getErrors(): Notification 来获取错误(错误)。注意,在 Ok 状态下调用该方法将抛出异常。您不能在 Result 对象初始化后更改 Notification 对象。

$result = Result::error(new Notification(...))

// $errors here is a cloned copy, you cannot change the list of errors in the $result object
$errors = $result->getErrors();

通知

Notification 类是通知模式的实现。它可以以两种方式初始化:作为一个空列表或包含一个错误的列表

use Skd\Result\Error\Notification;
use Skd\Result\Error\Error;

// empty
$emptyNotification = new Notification();

// with one error
$error = new Error('code', 'message');
$notificationWithOneError = new Notification($error);

使用方法 Notification::hasErrors(): bool 来检查通知对象内部是否有错误/错误

use Skd\Result\Error\Notification;

$errors = new Notification();
$errors->hasErrors(); // false

$errors = new Notification($error);
$errors->hasErrors(); // true

使用方法 Notification::hasError(Error $error): bool 来检查特定的错误是否在通知对象内部。这在单元测试中可能很有用。

use Skd\Result\Error\Notification;

$errors = new Notification($error);

$errors->hasError($error); // true
$errors->hasError($anotherError); // false

错误累积

错误可以累积在 Notification 对象中。

使用 Notification::addError(Error $error): void 来将一些错误添加到列表中

use Skd\Result\Error\Error;
use Skd\Result\Error\Notification;

$errors = new Notification();
// it can be initialized in both ways
$errors = new Notification($someError);

$errors->addError($anotherError);

Notification 对象也可以合并。这在您需要累积两个或多个包含错误的结果时很有用。请注意,只有左侧对象将发生变化。

use Skd\Result\Error\Notification;

$notification = new Notification($error);
$anotherNotification = new Notification($anotherError);

$notification->merge($anotherNotification);

$notification->hasError($error); // true
$notification->hasError($anotherError); // true

// but
$anotherNotification->hasError($error); // false

示例

一些值对象类

use Skd\Result\Error\Error;
use Skd\Result\Error\Notification;
use Skd\Result\Result;

class SomeClass
{
    private function __construct(public readonly mixed $someField)
    {
    }

    /**
     * @return Result<SomeClass>
     */
    public static function create(mixed $someValue): Result
    {
        $errors = new Notification();
        
        // some validation
        if (...) {
            $errors->addError();
        }
        
        // another validation (multiple errors)
        if (...) {
            $errors->addError(new Error('anotherCode', 'Another error message'));
        }
        
        if ($errors->hasErrors()) {
            return Result::error($errors)
        }
        
        return Result::ok(new self($someValue));
    }
}

您可以用静态工厂替换 new Error('code', 'Error message')

final class SomeErrorsFactory
{
  public static function invalidValue(): DomainError
  {
    return new Error('code', 'Error message');
  }
}

单元测试

public function testInvalidValue(): void
{
  $result = SomeClass::create($invalidValue);

  $this->assertTrue($result->isError());
  $this->assertTrue($result->getErrors()->hasError(SomeErrorsFactory::invalidValue()));
}