<?php
namespace ElementPack\Base\Support;
use ArrayAccess;
use ArrayObject;
class Optional implements ArrayAccess {
/**
* The underlying object.
*
* @var mixed
*/
protected $value;
/**
* Create a new optional instance.
*
* @param mixed $value
* @return void
*/
public function __construct($value) {
$this->value = $value;
}
/**
* Dynamically access a property on the underlying object.
*
* @param string $key
* @return mixed
*/
public function __get($key) {
if (is_object($this->value)) {
return isset($this->value->{$key}) ? $this->value->{$key} : null;
}
}
/**
* Dynamically check a property exists on the underlying object.
*
* @param mixed $name
* @return bool
*/
public function __isset($name) {
if (is_object($this->value)) {
return isset($this->value->{$name});
}
if (is_array($this->value) || $this->value instanceof ArrayObject) {
return isset($this->value[$name]);
}
return false;
}
/**
* Determine if an item exists at an offset.
*
* @param mixed $key
* @return bool
*/
public function offsetExists($key): bool {
return $this->accessible($this->value) && $this->exists($this->value, $key);
}
protected function accessible($value) {
return is_array($value) || $value instanceof ArrayAccess;
}
protected function exists($array, $key) {
if ($array instanceof ArrayAccess) {
return $array->offsetExists($key);
}
return array_key_exists($key, $array);
}
/**
* Get an item at a given offset.
*
* @param mixed $key
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($key) {
return $this->get($this->value, $key);
}
protected function get($array, $key, $default = null) {
if (!$this->accessible($array)) {
return $this->value($default);
}
if (is_null($key)) {
return $array;
}
if ($this->exists($array, $key)) {
return $array[$key];
}
if (strpos($key, '.') === false) {
return isset($array[$key]) ? $array[$key] : $this->value($default);
}
foreach (explode('.', $key) as $segment) {
if ($this->accessible($array) && $this->exists($array, $segment)) {
$array = $array[$segment];
} else {
return $this->value($default);
}
}
return $array;
}
protected function value($value) {
return $value instanceof \Closure ? $value() : $value;
}
/**
* Set the item at a given offset.
*
* @param mixed $key
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value): void {
if ($this->accessible($this->value)) {
$this->value[$key] = $value;
}
}
/**
* Unset the item at a given offset.
*
* @param string $key
* @return void
*/
public function offsetUnset($key): void {
if ($this->accessible($this->value)) {
unset($this->value[$key]);
}
}
}