Interface TH\Maybe\Option <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:

  • Initial values
  • Return values for functions that are not defined over their entire input range (partial functions)
  • Return value for otherwise reporting simple errors, where None is returned on error
  • Optional class properties
  • Swapping things out of difficult situations

Options are commonly paired with instanceof Option\{Some|None} to query the presence of a value and take action, always accounting for the None case.

Examples

// @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

Methods

public isSome(): (T is never ? false : bool)

Returns true if the option is the Some variant.

Examples

// @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.

Examples

// @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.

Examples

// @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.

Examples

$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

Throws

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.

Examples

$x = Option\some("value");
self::assertSame($x->unwrap(), "value");
// @var Option<string> $x
$x = Option\none();

$x->unwrap(); // @throws RuntimeException Unwrapping a `None` value

Throws

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.

Examples

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.

Examples

$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.

Examples

$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.

Examples

$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.

Examples

// @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.

Examples

$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.

Examples

// @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.

Examples

$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.

Examples

$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), and
  • None if predicate returns false.

Examples

$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.

Examples

$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).

Examples

$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).

Examples

$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.

Examples

$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.

Examples

$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).

Examples

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()).

Examples

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()