nur-sery/nur_src/b/values/ProxyValue.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();
}
}