deferredInstance = null; } /** * Retrieve the cached instance or create a new one and cache it. * * Note: this method only caches a single instance. If you need to change * the underlying construction inputs, call {@see clearDeferredInstance} * to force recreation. * * @throws \ReflectionException */ private function getDeferredInstance(): object { if ($this->deferredInstance !== null) { return $this->deferredInstance; } $classString = $this->deferredClassString(); $constructArgs = $this->deferredConstructArguments(); $reflectionClass = new \ReflectionClass($classString); $instance = $reflectionClass->newInstanceArgs($constructArgs); $this->deferredInstance = $instance; return $instance; } /** * Magic method to forward method calls to the deferred instance. * @return mixed * @throws \ReflectionException */ public function __call(string $name, array $arguments) { $instance = $this->getDeferredInstance(); // If the method is public and callable, call it directly for speed. if (is_callable([$instance, $name])) { return $instance->$name(...$arguments); } $reflectionClass = new \ReflectionClass($instance); $method = $reflectionClass->getMethod($name); return $method->invokeArgs($instance, $arguments); } }