diff --git a/src/AbstractOptional.php b/src/AbstractOptional.php index 59ca093..acf1995 100644 --- a/src/AbstractOptional.php +++ b/src/AbstractOptional.php @@ -63,6 +63,25 @@ public function equals(mixed $obj): bool return ($obj === null || static::isSupported($obj)) && $this->value == $obj; } + /** + * @param callable(T): bool $predicate + * + * @return static + */ + public function filter(callable $predicate): static + { + if ($this->value !== null) { + $matches = $predicate($this->value); + if (!is_bool($matches)) { + throw new InvalidArgumentException('Predicate must return boolean.'); + } + if (!$matches) { + return static::empty(); + } + } + return $this; + } + /** * @template U of mixed * diff --git a/tests/OptionalTest.php b/tests/OptionalTest.php index 516eccc..df23d15 100644 --- a/tests/OptionalTest.php +++ b/tests/OptionalTest.php @@ -76,6 +76,23 @@ public static function dataMethodEqualsWorks(): array ]; } + #[DataProvider('dataMethodFilterWorks')] + public function testMethodFilterWorks(Optional $optional, bool $expected): void + { + self::assertEquals( + $expected ? $optional : Optional::empty(), + $optional->filter(static fn (string $value): bool => $value === self::VALUE), + ); + } + + public static function dataMethodFilterWorks(): array + { + return [ + self::VALUE => [Optional::of(self::VALUE), true], + self::OTHER => [Optional::of(self::OTHER), false], + ]; + } + #[DataProvider('dataMethodFlatMapWorks')] public function testMethodFlatMapWorks(Optional $optional, Optional $expectedResult): void {