PHPでResult型を使って成功・失敗を値として扱う
https://speakerdeck.com/kajitack/result-type-in-php
@templateを使ってジェネリクス型を表現
constructの引数の型はmixedとしてなんでも受け入れるようにしつつ、ジェネリクスによる成約で型を限定的にしている
code:php
<?php
/**
* @template T 成功時の値の型
* @template E 失敗時のエラーの型
*/
abstract readonly class Result
{}
/**
* @template T
* @extends Result<T, never>
*/
final readonly class Ok extends Result
{
/**
* @param T $value
*/
public function __construct(private mixed $value) {}
}
/**
* @template E
* @extends Result<never, E>
*/
final readonly class Err extends Result
{
/**
* @param E $value
*/
public function __construct(private mixed $value) {}
}
成功・失敗時の値の扱い
unwrap・unwrapErrメソッドを持つことで、その値が必要になったタイミングで取り出せるようにしている
成功・失敗かかわらずResult型に包んで処理できるのでmapやResult型に包んだまま値を変更することができる
code:php
// OK class
/**
* @return T
*/
public function unwrap(): mixed {return $this->value;}
public function unwrapErr(): never {throw new LogicException('hoge');}
public function map(callable $fn): Result {return new Ok($fn($this->value));}
public function mapErr(callable $fn): Result {return $this;}
// Err class
public function unwrap(): never {throw new LogicException('hoge');}
/**
* @return E
*/
public function unwrapErr(): mixed {return $this->value;}
public function map(callable $fn): Result {return $this;}
public function mapErr(callable $fn): Result {return new Ok($fn($this->value));}
ドメインロジックのエラーをResult型で扱う
エラーもドメインモデルと同様にモデル化し値として扱うことで、文脈をたもったまま処理をかけるのでビジネス要件を正確に表現できる
例外を投げるとcatchされるまで、処理が一気にワープするため文脈が失われる。どこで投げられた例外か特定する必要がある
関連
Eitherモナド
#PHP