skd / result
在PHP中实现结果对象模式
Requires
- php: >=8.1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.28
- infection/infection: ^0.27.7
- phpunit/phpunit: ^10.3
- psalm/plugin-phpunit: ^0.18.4
- vimeo/psalm: ^5.15
README
此包允许您以面向对象的方式处理操作的结果,包括错误,而不使用异常。例如,当使用“始终有效的领域模型”方法时。结果对象允许您一次性累积错误并返回它们(在通知模式内部)。同时,代码变得更加易懂和逻辑。
安装
composer require skd/result
结果
Result 类是一个不可变的泛型类(使用 @template 注解),具有两种状态:Ok 和 Error。OK 状态表示内部没有错误,并且存在一些值(成功操作结果)。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(): bool 或 Result::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())); }