diff --git a/src/Option.php b/src/Option.php index 22be639..cdb61ee 100644 --- a/src/Option.php +++ b/src/Option.php @@ -23,7 +23,7 @@ public static function some($value): Some return new Some($value); } - /**y + /** * @return None */ public static function none(): None @@ -31,6 +31,18 @@ public static function none(): None return self::$none ??= new None(); } + /** + * @template TNew + * @param TNew|null $value + * @return Option + */ + public static function fromNullable($value): Option + { + return $value === null + ? self::none() + : self::some($value); + } + /** * @template T * @param list> $options @@ -124,4 +136,12 @@ public function toResultLazy(callable $else): ResultInterface ->map(fn($t) => new Success($t)) ->getOr(fn() => new Error($else())); } + + /** + * @return TValue|null + */ + public function toNullable() + { + return $this->getOrElse(null); + } } diff --git a/test/OptionTest.php b/test/OptionTest.php index 8928534..3c48d24 100644 --- a/test/OptionTest.php +++ b/test/OptionTest.php @@ -94,4 +94,34 @@ public function testGetOrThrowNone(): void /** @psalm-suppress UnusedMethodCall */ $option->getOrThrow(new \RuntimeException('expected')); } + + public function testFromNullableGivenValue(): void + { + $option = Option::fromNullable(123); + $mapped = $option->map(fn(int $val) => $val + 1); + self::assertEquals(124, $mapped->getOrElse(-1)); + } + + public function testFromNullableGivenNull(): void + { + /** @var Option $option */ + $option = Option::fromNullable(null); + $mapped = $option->map(fn(int $val) => $val + 1); + self::assertEquals(-1, $mapped->getOrElse(-1)); + } + + public function testToNullableSome(): void + { + $option = Option::some(123); + $nullable = $option->toNullable(); + self::assertEquals(123, $nullable); + } + + public function testToNullableNone(): void + { + /** @var Option $option */ + $option = Option::none(); + $nullable = $option->toNullable(); + self::assertNull($nullable); + } }