159 lines
5.5 KiB
PHP
159 lines
5.5 KiB
PHP
|
<?php
|
||
|
namespace nur\b\values;
|
||
|
|
||
|
use ArrayAccess;
|
||
|
use Throwable;
|
||
|
|
||
|
class ProxyValue implements IProxyValue, ArrayAccess {
|
||
|
/** @var IProxyValue */
|
||
|
private static $undef;
|
||
|
|
||
|
static function undef(): IProxyValue {
|
||
|
if (self::$undef === null) {
|
||
|
self::$undef = new class implements IProxyValue {
|
||
|
function allowUndef(): bool { return true; }
|
||
|
function allowNull(): bool { return false; }
|
||
|
function allowError(): bool { return false; }
|
||
|
function isUndef(): bool { return true; }
|
||
|
function isNull(): bool { return false; }
|
||
|
function isError(): bool { return false; }
|
||
|
function isValue(): bool { return false; }
|
||
|
function isMutable(): bool { return false; }
|
||
|
function get($default=null) { return $default; }
|
||
|
function getError(): Throwable { throw ProxyValueException::notAnError(); }
|
||
|
function set($value) { throw ProxyValueException::undefIsImmutable(); }
|
||
|
function reset() { throw ProxyValueException::undefIsImmutable(); }
|
||
|
};
|
||
|
}
|
||
|
return self::$undef;
|
||
|
}
|
||
|
|
||
|
/** @var IProxyValue */
|
||
|
private static $null;
|
||
|
|
||
|
static function null(): IProxyValue {
|
||
|
if (self::$null === null) {
|
||
|
self::$null = new class implements IProxyValue {
|
||
|
function allowUndef(): bool { return false; }
|
||
|
function allowNull(): bool { return true; }
|
||
|
function allowError(): bool { return false; }
|
||
|
function isUndef(): bool { return false; }
|
||
|
function isNull(): bool { return true; }
|
||
|
function isError(): bool { return false; }
|
||
|
function isValue(): bool { return false; }
|
||
|
function isMutable(): bool { return false; }
|
||
|
function get($default=null) { return null; }
|
||
|
function getError(): Throwable { throw ProxyValueException::notAnError(); }
|
||
|
function set($value) { throw ProxyValueException::nullIsImmutable(); }
|
||
|
function reset() { throw ProxyValueException::nullIsImmutable(); }
|
||
|
};
|
||
|
}
|
||
|
return self::$null;
|
||
|
}
|
||
|
|
||
|
/** Retourner une instance de IProxyValue */
|
||
|
static function with($value, bool $ensure_mutable=false): IProxyValue {
|
||
|
if ($value instanceof IProxyValue) {
|
||
|
if (!$ensure_mutable || $value->isMutable()) return $value;
|
||
|
if ($value->isValue()) return new static($value->get());
|
||
|
elseif ($value->isError()) return new static($value->getError());
|
||
|
elseif ($value->isNull()) return new static(null);
|
||
|
elseif ($value->isUndef()) return new static(false);
|
||
|
} elseif (!$ensure_mutable) {
|
||
|
if ($value === null) return self::null();
|
||
|
elseif ($value === false) return self::undef();
|
||
|
}
|
||
|
return new static($value);
|
||
|
}
|
||
|
|
||
|
#############################################################################
|
||
|
|
||
|
function __construct($value) {
|
||
|
$this->_set($value);
|
||
|
}
|
||
|
|
||
|
function get($default=null) {
|
||
|
$value = $this->value;
|
||
|
if ($this->allowUndef()) {
|
||
|
if ($value === false) return $default;
|
||
|
} elseif ($this->allowError()) {
|
||
|
if ($value instanceof Throwable) throw $value;
|
||
|
}
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
function getError(): Throwable {
|
||
|
if ($this->allowError()) {
|
||
|
$value = $this->value;
|
||
|
if ($value instanceof Throwable) return $value;
|
||
|
}
|
||
|
throw ProxyValueException::notAnError();
|
||
|
}
|
||
|
|
||
|
function set($value) {
|
||
|
if (!$this->isMutable()) {
|
||
|
throw ProxyValueException::valueIsImmutable();
|
||
|
} elseif ($value === null && !$this->allowNull()) {
|
||
|
throw ProxyValueException::nullNotAllowed();
|
||
|
} elseif ($value === false && !$this->allowUndef()) {
|
||
|
throw ProxyValueException::undefNotAllowed();
|
||
|
}
|
||
|
$old_value = $this->value;
|
||
|
$this->_set($value);
|
||
|
return $old_value;
|
||
|
}
|
||
|
|
||
|
function reset() {
|
||
|
if ($this->allowUndef()) {
|
||
|
$this->value = false;
|
||
|
} else {
|
||
|
throw ProxyValueException::undefNotAllowed();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function __toString(): string { return strval($this->value); }
|
||
|
function __invoke(...$args) { $func = $this->value; return $func(...$args); }
|
||
|
function __set(string $name, $value) { $this->value->$name = $value; }
|
||
|
function __get(string $name) { return $this->value->$name; }
|
||
|
function __isset(string $name): bool { return isset($this->value->$name); }
|
||
|
function __unset(string $name) { unset($this->value->$name); }
|
||
|
function __call(string $name, array $args) { return $this->value->$name(...$args); }
|
||
|
function offsetExists($offset) { return isset($this->value[$offset]); }
|
||
|
function offsetGet($offset) { return isset($this->value[$offset])? $this->value[$offset]: null; }
|
||
|
function offsetSet($offset, $value) { if ($offset === null) $this->value[] = $value; else $this->value[$offset] = $value; }
|
||
|
function offsetUnset($offset) { unset($this->value[$offset]); }
|
||
|
|
||
|
#############################################################################
|
||
|
|
||
|
const ALLOW_UNDEF = true;
|
||
|
function allowUndef(): bool { return static::ALLOW_UNDEF; }
|
||
|
|
||
|
const ALLOW_NULL = true;
|
||
|
function allowNull(): bool { return static::ALLOW_NULL; }
|
||
|
|
||
|
const ALLOW_ERROR = true;
|
||
|
function allowError(): bool { return static::ALLOW_ERROR; }
|
||
|
|
||
|
const IS_MUTABLE = true;
|
||
|
function isMutable(): bool { return static::IS_MUTABLE; }
|
||
|
|
||
|
protected $value;
|
||
|
|
||
|
protected function _set($value) {
|
||
|
$this->value = $value;
|
||
|
}
|
||
|
|
||
|
function isUndef(): bool {
|
||
|
return $this->allowUndef() && $this->value === false;
|
||
|
}
|
||
|
function isNull(): bool {
|
||
|
return $this->allowNull() && $this->value === null;
|
||
|
}
|
||
|
function isError(): bool {
|
||
|
return $this->allowError() && $this->value instanceof Throwable;
|
||
|
}
|
||
|
function isValue(): bool {
|
||
|
return !$this->isUndef() && !$this->isNull() && !$this->isError();
|
||
|
}
|
||
|
}
|