instances[$id] = $concrete; } public function get(string $id): mixed { if (isset($this->instances[$id])) { if ($this->instances[$id] instanceof \Closure) { $this->instances[$id] = ($this->instances[$id])($this); } return $this->instances[$id]; } return $this->resolve($id); } public function resolve(string $id): mixed { if (!class_exists($id)) { throw new Exception("Class {$id} cannot be resolved."); } $reflection = new ReflectionClass($id); if (!$reflection->isInstantiable()) { throw new Exception("Class {$id} is not instantiable."); } $constructor = $reflection->getConstructor(); if (is_null($constructor)) { return new $id(); } $parameters = $constructor->getParameters(); $dependencies = []; foreach ($parameters as $parameter) { $type = $parameter->getType(); if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) { if ($parameter->isDefaultValueAvailable()) { $dependencies[] = $parameter->getDefaultValue(); continue; } throw new Exception("Unable to resolve parameter '{$parameter->getName()}' in class {$id}"); } $dependencies[] = $this->get($type->getName()); } $instance = $reflection->newInstanceArgs($dependencies); $this->instances[$id] = $instance; return $instance; } }