diff --git a/src/Psl/Option/Option.php b/src/Psl/Option/Option.php index 1d99e64c..3f60962c 100644 --- a/src/Psl/Option/Option.php +++ b/src/Psl/Option/Option.php @@ -204,6 +204,29 @@ public function contains(mixed $value): bool return false; } + /** + * Matches the contained option value with the provided closures and returns the result. + * + * @template Ts + * + * @param (Closure(T): Ts) $some A closure to be called when the option is some. + * The closure must accept the option value as its only argument and can return a value. + * Example: `fn($value) => $value + 10` + * @param (Closure(): Ts) $none A closure to be called when the option is none. + * The closure must not accept any arguments and can return a value. + * Example: `fn() => 'Default value'` + * + * @return Ts The result of calling the appropriate closure. + */ + public function proceed(Closure $some, Closure $none): mixed + { + if ($this->option !== null) { + return $some($this->option[0]); + } + + return $none(); + } + /** * Maps an `Option` to `Option` by applying a function to a contained value. * diff --git a/tests/static-analysis/Option/proceed.php b/tests/static-analysis/Option/proceed.php new file mode 100644 index 00000000..f8e38fa1 --- /dev/null +++ b/tests/static-analysis/Option/proceed.php @@ -0,0 +1,21 @@ + $option + * + * @return non-empty-string + */ + function test_proceed(Option\Option $option): string + { + return $option->proceed( + static fn (int $value) => "There is $value of them.", + static fn () => 'There are none.', + ); + } +} diff --git a/tests/unit/Option/NoneTest.php b/tests/unit/Option/NoneTest.php index 7ccc6cdb..43481f31 100644 --- a/tests/unit/Option/NoneTest.php +++ b/tests/unit/Option/NoneTest.php @@ -10,6 +10,7 @@ use Psl\Comparison\Order; use Psl\Option; use Psl\Option\Exception\NoneException; +use Psl\Str; final class NoneTest extends TestCase { @@ -84,6 +85,16 @@ public function testContains(): void static::assertFalse($option->contains(4)); } + public function testProceed(): void + { + $result = Option\none()->proceed( + static fn ($i) => Str\format('Value is %d', $i), + static fn () => 'There is no value', + ); + + static::assertSame('There is no value', $result); + } + public function testMap(): void { $option = Option\none(); diff --git a/tests/unit/Option/SomeTest.php b/tests/unit/Option/SomeTest.php index 4b4b3dca..3c0d2c3e 100644 --- a/tests/unit/Option/SomeTest.php +++ b/tests/unit/Option/SomeTest.php @@ -9,6 +9,7 @@ use Psl\Comparison\Equable; use Psl\Comparison\Order; use Psl\Option; +use Psl\Str; use Psl\Tests\Fixture; use Psl\Type; @@ -83,6 +84,16 @@ public function testContains(): void static::assertTrue($option->contains(2)); } + public function testProceed(): void + { + $result = Option\some(1)->proceed( + static fn ($i) => Str\format('Value is %d', $i), + static fn () => 'There is no value', + ); + + static::assertSame('Value is 1', $result); + } + public function testMap(): void { $option = Option\some(2);