{$offset} = $this->cached_offsets[$offset] = $value; } public function offsetExists($offset): bool { return isset($this->{$offset}) || method_exists($this, $this->offsetMethod($offset)); } public function offsetUnset($offset): void { unset($this->{$offset}); } public function offsetMethod($offset) { return 'fetch'.ucfirst($offset); } public function offsetGet($offset): mixed { if (array_key_exists($offset, $this->cached_offsets)) { return $this->cached_offsets[$offset]; } $method = $this->offsetMethod($offset); if (method_exists($this, $method)) { $res = call_user_func([$this, $method]); $this->cached_offsets[$offset] = $res; return $res; } if (isset($this->{$offset})) { return $this->{$offset}; } return null; } public function injectCache($offset, $value) { return $this->cached_offsets[$offset] = $value; } public function jsonSerialize(): mixed { $data = get_object_vars($this); $data['_cache'] = $data['cached_offsets']; unset($data['cached_offsets']); $methods = array_filter(get_class_methods($this), function ($x) { return substr($x, 0, 5) == 'fetch'; }); $methods = array_values(array_map(function ($x) { return lcfirst(substr($x, 5)); }, $methods)); return $data + ['_attributes' => $methods]; } }