collection = $collection; } /** * Forward all other calls to the collection, stripping callable arguments first. */ public function __call($method, $parameters) { if (in_array(strtolower($method), $this->blockedMethods)) { return $this; } $normalized = strtolower($method); foreach ($parameters as &$param) { $param = $this->stripCallables($param, $normalized); } unset($param); return $this->forwardCallTo($this->collection, $method, $parameters); } /** * Recursively null out any callable value at any depth. Hybrid methods keep string * values (used as attribute names) but still drop non-string callables. */ protected function stripCallables($value, string $method) { if (is_array($value)) { foreach ($value as $key => $item) { $value[$key] = $this->stripCallables($item, $method); } return $value; } if ( is_callable($value) && (!in_array($method, $this->hybridCallableArgs) || !is_string($value)) ) { return null; } return $value; } public function getIterator(): Traversable { return $this->collection->getIterator(); } public function offsetExists($offset): bool { return $this->collection instanceof ArrayAccess ? $this->collection->offsetExists($offset) : false; } #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->collection instanceof ArrayAccess ? $this->collection->offsetGet($offset) : null; } public function offsetSet($offset, $value): void { if ($this->collection instanceof ArrayAccess) { $this->collection->offsetSet($offset, $value); } } public function offsetUnset($offset): void { if ($this->collection instanceof ArrayAccess) { $this->collection->offsetUnset($offset); } } public function count(): int { return $this->collection->count(); } public function toArray() { return $this->collection->toArray(); } public function toJson($options = 0) { return $this->collection->toJson($options); } public function __toString(): string { return $this->collection->toJson(); } }