Files
core/src/Option/Option.php
T
2026-07-01 18:35:39 +03:00

242 lines
5.5 KiB
PHP

<?php
namespace Modules\Core\Option;
use ArrayAccess;
use IteratorAggregate;
/**
* @template T
*
* @implements IteratorAggregate<T>
*/
abstract class Option implements IteratorAggregate
{
/**
* @template S
*
* @param S $value
* @param S $noneValue
*
* @return Option<S>
*/
public static function fromValue($value, $noneValue = null)
{
if ($value === $noneValue) {
return None::create();
}
return new Some($value);
}
/**
* @template S
*
* @param array<string|int,S>|ArrayAccess<string|int,S>|null $array
* @param string|int|null $key
*
* @return Option<S>
*/
public static function fromArraysValue($array, $key)
{
if (
$key === null ||
!(is_array($array) || $array instanceof ArrayAccess) ||
!isset($array[$key])
) {
return None::create();
}
return new Some($array[$key]);
}
/**
* @template S
*
* @param callable $callback
* @param array $arguments
* @param S $noneValue
*
* @return LazyOption<S>
*/
public static function fromReturn(
$callback,
array $arguments = [],
$noneValue = null,
) {
return new LazyOption(static function () use (
$callback,
$arguments,
$noneValue,
) {
/** @var mixed */
$return = call_user_func_array($callback, $arguments);
if ($return === $noneValue) {
return None::create();
}
return new Some($return);
});
}
/**
* @template S
*
* @param Option<S>|callable|S $value
* @param S $noneValue
*
* @return Option<S>|LazyOption<S>
*/
public static function ensure($value, $noneValue = null)
{
if ($value instanceof self) {
return $value;
} elseif (is_callable($value)) {
return new LazyOption(static function () use ($value, $noneValue) {
/** @var mixed */
$return = $value();
if ($return instanceof self) {
return $return;
} else {
return self::fromValue($return, $noneValue);
}
});
} else {
return self::fromValue($value, $noneValue);
}
}
/**
* @template S
*
* @param callable $callback
* @param mixed $noneValue
*
* @return callable
*/
public static function lift($callback, $noneValue = null)
{
return static function () use ($callback, $noneValue) {
/** @var array<int, mixed> */
$args = func_get_args();
$reduced_args = array_reduce(
$args,
/** @param bool $status */
static function ($status, self $o) {
return $o->isEmpty() ? true : $status;
},
false,
);
if ($reduced_args) {
return None::create();
}
$args = array_map(static function (self $o) {
return $o->get();
}, $args);
return self::ensure(
call_user_func_array($callback, $args),
$noneValue,
);
};
}
/** @return T */
abstract public function get();
/**
* @template S
* @param S $default
* @return T|S
*/
abstract public function getOrElse($default);
/**
* @template S
* @param callable():S $callable
* @return T|S
*/
abstract public function getOrCall($callable);
/** @return T */
abstract public function getOrThrow(\Exception $ex);
abstract public function isEmpty(): bool;
abstract public function isDefined(): bool;
/**
* @param Option<T> $else
* @return Option<T>
*/
abstract public function orElse(self $else);
/** @deprecated Use forAll() instead. */
abstract public function ifDefined($callable);
/**
* @param callable(T):mixed $callable
* @return Option<T>
*/
abstract public function forAll($callable);
/**
* @template S
* @param callable(T):S $callable
* @return Option<S>
*/
abstract public function map($callable);
/**
* @template S
* @param callable(T):Option<S> $callable
* @return Option<S>
*/
abstract public function flatMap($callable);
/**
* @param callable(T):bool $callable
* @return Option<T>
*/
abstract public function filter($callable);
/**
* @param callable(T):bool $callable
* @return Option<T>
*/
abstract public function filterNot($callable);
/**
* @param T $value
* @return Option<T>
*/
abstract public function select($value);
/**
* @param T $value
* @return Option<T>
*/
abstract public function reject($value);
/**
* @template S
* @param S $initialValue
* @param callable(S, T):S $callable
* @return S
*/
abstract public function foldLeft($initialValue, $callable);
/**
* @template S
* @param S $initialValue
* @param callable(T, S):S $callable
* @return S
*/
abstract public function foldRight($initialValue, $callable);
}