<T>
extends |
IteratorAggregate<T> |
---|
Type Option
represents an optional value: every Option
is either
Option\Some
and contains a value, or Option\None
, and does not. Option
types have a number of uses:
None
is returned on errorOption
s are commonly paired with instanceof Option\{Some|None}
to query the
presence of a value and take action, always accounting for the None
case.
// @return Option<float>
function divide(float $numerator, float $denominator): Option {
if ($denominator === 0.0) {
return Option\none();
}
return Option\some($numerator / $denominator);
}
// The return value of the function is an option
$result = divide(2.0, 3.0);
// Use instanceof to differentiate between Some & None
if ($result instanceof Option\Some) {
// The division was valid
echo "Result: {$result->unwrap()}";
} else {
echo "Cannot divide by 0";
}
// @prints Result: 0.66666666666667
public
isSome(): (T is never ? false : bool)
Returns true
if the option is the Some
variant.
// @var Option<int,string> $x
$x = Option\Some(2);
self::assertTrue($x->isSome());
// @var Option<int,string> $x
$x = Option\none();
self::assertFalse($x->isSome());
public
isNone(): (T is never ? true : bool)
Returns true
if the option is the None
variant.
// @var Option<int,string> $x
$x = Option\Some(2);
self::assertFalse($x->isNone());
// @var Option<int,string> $x
$x = Option\none();
self::assertTrue($x->isNone());
public
isSomeAnd(callable(T): bool $predicate): (T is never ? false : bool)
Returns true
if the option is the Some
variant and the value inside of it matches a predicate.
// @var Option<int,string> $x
$x = Option\Some(2);
self::assertTrue($x->isSomeAnd(fn ($n) => $n < 5));
self::assertFalse($x->isSomeAnd(fn ($n) => $n > 5));
// @var Option<int,string> $x
$x = Option\none();
self::assertFalse($x->isSomeAnd(fn ($n) => $n < 5));
self::assertFalse($x->isSomeAnd(fn ($n) => $n > 5));
public
expect(string $message): T
Extract the contained value in an Option<T>
when it is the Some
variant.
Throw a RuntimeException
with a custum provided message if the Option
is None
.
$x = Option\some("value");
self::assertSame($x->expect("fruits are healthy"), "value");
// @var Option<string> $x
$x = Option\none();
$x->expect("fruits are healthy");
// @throws RuntimeException fruits are healthy
RuntimeException |
public
unwrap(): T
Extract the contained value in an Option<T>
when it is the Some
variant.
Throw a RuntimeException
with a generic message if the Option
is None
.
$x = Option\some("value");
self::assertSame($x->unwrap(), "value");
// @var Option<string> $x
$x = Option\none();
$x->unwrap(); // @throws RuntimeException Unwrapping a `None` value
RuntimeException |
public
unwrapOr<U>(U $default): T|U
Extract the contained value in an Option<T>
when it is the Some
variant.
Or $default
if the Option
is None
.
self::assertSame(Option\some("car")->unwrapOr("bike"), "car");
self::assertSame(Option\none()->unwrapOr("bike"), "bike");
public
unwrapOrElse<U>(callable(): U $default): T|U
Returns the contained Some
value or computes it from a closure.
$k = 10;
self::assertSame(Option\some(4)->unwrapOrElse(fn () => 2 * $k), 4);
self::assertSame(Option\none()->unwrapOrElse(fn () => 2 * $k), 20);
public
inspect(callable(T): mixed $callback): $this
Calls the provided closure with a reference to the contained value (if Some
)
and (always) returns the same option.
$option = Option\some(4);
self::assertSame($option->inspect(fn (int $n) => printf("got: %d", $n)), $option); // @prints got: 4
// @var Option<int> $option
$option = Option\none();
self::assertSame($option->inspect(fn (int $n) => printf("%d", $n)), $option); // prints nothing
public
and<U>(Option<U> $right): (T is never ? None : Option<U>)
Returns None
if the option is None
, otherwise returns $right
.
$x = Option\some(2);
// @var Option<string> $y
$y = Option\none();
self::assertSame($x->and($y), Option\none());
// @var Option<string> $x
$x = Option\none();
$y = Option\some("foo");
self::assertSame($x->and($y), Option\none());
$x = Option\some(2);
$y = Option\some("foo");
self::assertEq($x->and($y), Option\some("foo"));
// @var Option<string> $x
$x = Option\none();
// @var Option<string> $y
$y = Option\none();
self::assertSame($x->and($y), Option\none());
public
andThen<U>(callable(T): Option<U> $right): (T is never ? None : Option<U>)
Returns None
if the option is None
, otherwise calls $right
with the wrapped value and returns the result.
// @return Option<int>
function to_exact_int(float $f): Option {
$i = (int) $f;
return ((float) $i) === $f ? Option\some($i) : Option\none();
}
self::assertEq(Option\some(2.0)->andThen(to_exact_int(...)), Option\some(2));
self::assertSame(Option\some(1.2)->andThen(to_exact_int(...)), Option\none());
self::assertSame(Option\none()->andThen(to_exact_int(...)), Option\none());
public
or<U>(Option<U> $right): Option<T|U>
Returns the option if it contains a value, otherwise returns $right
.
$x = Option\some(2);
// @var Option<int> $y
$y = Option\none();
self::assertEq($x->or($y), Option\some(2));
// @var Option<int> $x
$x = Option\none();
$y = Option\some(100);
self::assertEq($x->or($y), Option\some(100));
$x = Option\some(2);
$y = Option\some(100);
self::assertEq($x->or($y), Option\some(2));
// @var Option<int> $x
$x = Option\none();
// @var Option<int> $y
$y = Option\none();
self::assertSame($x->or($y), Option\none());
public
orElse<U>(callable(): Option<U> $right): Option<T|U>
Returns the option if it contains a value, otherwise calls $right
and returns the result.
// @return Option<string>
function nobody(): Option {
return Option\none();
}
// @return Option<string>
function vikings(): Option {
return Option\some("vikings");
}
self::assertEq(Option\some("barbarians")->orElse(vikings(...)), Option\some("barbarians"));
self::assertEq(Option\none()->orElse(vikings(...)), Option\some("vikings"));
self::assertSame(Option\none()->orElse(nobody(...)), Option\none());
public
xor<U>(Option<U> $right): Option<T|U>
Returns the some option if exactly one is a Some
, return None
otherwise.
$x = Option\some(2);
// @var Option<int> $y
$y = Option\none();
self::assertEq($x->xor($y), Option\some(2));
// @var Option<int> $x
$x = Option\none();
$y = Option\some(2);
self::assertEq($x->xor($y), Option\some(2));
$x = Option\some(2);
$y = Option\some(2);
self::assertSame($x->xor($y), Option\none());
// @var Option<int> $x
$x = Option\none();
// @var Option<int> $y
$y = Option\none();
self::assertSame($x->xor($y), Option\none());
public
contains(mixed $value, bool $strict = true): (T is never ? false : bool)
Returns true if the option is a Some
value containing the given value.
$x = Option\some(2);
self::assertTrue($x->contains(2));
$x = Option\some(3);
self::assertFalse($x->contains(2));
// @var Option<int> $x
$x = Option\none();
self::assertFalse($x->contains(2));
public
filter(callable(T): bool $predicate): Option<T>
Returns None
if the option is None
, otherwise calls $predicate
with the wrapped value and returns:
Some(t)
if $predicate
returns true
(where t
is the wrapped value), andNone
if predicate returns false
.$isEven = fn(int $n) => $n % 2 === 0;
self::assertSame(Option\none()->filter($isEven), Option\none());
self::assertSame(Option\some(3)->filter($isEven), Option\none());
self::assertEq(Option\some(4)->filter($isEven), Option\some(4));
public
map<U>(callable(T): U $callback): (T is never ? None : Option<U>)
Maps an Option<T>
to Option<U>
by applying a function to a contained value.
$maybeSomeString = Option\some("Hello, World!");
$maybeSomeLen = $maybeSomeString->map(strlen(...));
self::assertEq($maybeSomeLen, Option\some(13));
public
mapOr<U, V>(callable(T): U $callback, V $default): (T is never ? V : U)
Returns the provided default result (if None
), or applies a function to
the contained value (if Some
).
$x = Option\some("foo");
self::assertSame($x->mapOr(strlen(...), 42), 3);
// @var Option<string> $x
$x = Option\none();
self::assertSame($x->mapOr(strlen(...), 42), 42);
public
mapOrElse<U, V>(callable(T): U $callback, callable(): V $default): (T is never ? V : U)
Computes a default function result (if None
), or applies a different
function to the contained value (if Some
).
$k = 21;
$x = Option\some("foo");
self::assertSame($x->mapOrElse(strlen(...), fn () => 2 * $k), 3);
// @var Option<string> $x
$x = Option\none();
self::assertSame($x->mapOrElse(strlen(...), fn () => 2 * $k), 42);
public
zip<U>(Option<U> $option): (T is never ? None : (U is never ? None : Option<array{T, U}>))
Zips $this
with another Option
.
If $this
is Some(s)
and other is Some(o)
, this method returns Some([s, o])
.
Otherwise, None
is returned.
$x = Option\some(1);
$y = Option\some("hi");
// @var Option<int> $z
$z = Option\none();
self::assertEq($x->zip($y), Option\some([1, "hi"]));
self::assertSame($x->zip($z), Option\none());
public
zipWith<U, V>(Option<U> $option, callable(T, U): V $callback): (T is never ? None : (U is never ? None : Option<V>))
Zips $this
and another Option
with a function.
If $this
is Some(s)
and other is Some(o)
, this method returns Some(f([s, o]))
.
Otherwise, None
is returned.
$x = Option\some(new \DateTime('2025-02-08T23:15:07+00:00'));
$y = Option\some(new \DateInterval('P1M0D'));
// @var Option<int> $z
$z = Option\none();
self::assertEq($x->zipWith($y, date_add(...)), Option\some(new \DateTimeImmutable('2025-03-08T23:15:07+00:00')));
self::assertSame($x->zipWith($z, date_add(...)), Option\none());
self::assertSame($z->zipWith($y, date_add(...)), Option\none());
public
okOr<E>(E $err): (T is never ? Err<E> : Result<T, E>)
Transforms the Option<T>
into a Result<T, E>
, mapping Some(v)
to Ok(v)
and None
to Err(err)
.
use TH\Maybe\Result;
self::assertEq(Option\some("foo")->okOr(0), Result\ok("foo"));
self::assertEq(Option\none()->okOr(0), Result\err(0));
public
okOrElse<E>(callable(): E $err): (T is never ? Err<E> : Result<T, E>)
Transforms the Option<T>
into a Result<T, E>
, mapping Some(v)
to Ok(v)
and None
to Err(err())
.
use TH\Maybe\Result;
self::assertEq(Option\some("foo")->okOrElse(fn () => 0), Result\ok("foo"));
self::assertEq(Option\none()->okOrElse(fn () => 0), Result\err(0));
Methods inherited from IteratorAggregate |
---|
getIterator() |