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