3v4l.org

run code in 500+ PHP versions simultaneously
<?php /** * @psalm-immutable * @template-covariant TValue */ abstract class Option { /** * @template T * @param list<Option<T>> $options * @return Option<list<T>> */ public static function all(array $options): Option { return array_reduce( $options, /** * @param Option<list<T>> $carry * @param Option<T> $o * @return Option<list<T>> */ fn(Option $carry, Option $o) => $carry->flatMap( /** * @param list<T> $ts * @return Option<list<T>> */ fn(array $ts) => $o instanceof None ? new Some($ts) : $o->map( /** * @param T $t * @return list<T> */ fn($t) => array_merge($ts, [ $t ]) ) ), new Some([]), ); } /** * @template TMap * @param callable(TValue):TMap $map * @return Option<TMap> */ abstract public function map(callable $map): Option; /** * @template TMap * @param callable(TValue):Option<TMap> $map * @return Option<TMap> */ abstract public function flatMap(callable $map): Option; } /** * @psalm-immutable * @template-covariant T * @template-extends Option<T> */ final class Some extends Option { /** @var T */ private $value; /** @param T $value */ public function __construct($value) { $this->value = $value; } public function map(callable $map): Option { /** @psalm-suppress ImpureFunctionCall */ return new Some($map($this->value)); } public function flatMap(callable $map): Option { /** @psalm-suppress ImpureFunctionCall */ return $map($this->value); } } /** * @psalm-immutable * @template-extends Option<never> */ final class None extends Option { public function map(callable $map): Option { return $this; } public function flatMap(callable $map): Option { return $this; } } $opts = [new Some(1), new None(), new Some(2), new None(), new None(), new Some(3)]; var_dump(Option::all($opts));
Output for 7.4.0 - 7.4.33, 8.0.1 - 8.0.30, 8.1.0 - 8.1.34, 8.2.0 - 8.2.30, 8.3.0 - 8.3.30, 8.4.1 - 8.4.18, 8.5.0 - 8.5.3
object(Some)#9 (1) { ["value":"Some":private]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } }

preferences:
82.2 ms | 1288 KiB | 4 Q