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