bindings[$abstract] = $concrete; $this->singletons[$abstract] = $singleton; } public function singleton(string $abstract, mixed $concrete = null): void { $this->bind($abstract, $concrete, true); } public function make(string $abstract, array $parameters = []): mixed { // 如果已存在实例且为单例 if (isset($this->instances[$abstract])) { return $this->instances[$abstract]; } $concrete = $this->bindings[$abstract] ?? $abstract; // 如果是闭包 if ($concrete instanceof \Closure) { $object = $concrete($this, $parameters); } else { $object = $this->build($concrete, $parameters); } // 如果是单例,缓存实例 if (isset($this->singletons[$abstract]) && $this->singletons[$abstract]) { $this->instances[$abstract] = $object; } return $object; } private function build(string $concrete, array $parameters): mixed { try { $reflector = new ReflectionClass($concrete); } catch (ReflectionException $e) { throw new BusinessException(500, 'CLASS_NOT_FOUND', ['class' => $concrete]); } if (!$reflector->isInstantiable()) { throw new BusinessException(500, 'CLASS_NOT_INSTANTIABLE', ['class' => $concrete]); } $constructor = $reflector->getConstructor(); if ($constructor === null) { return new $concrete(); } $dependencies = $constructor->getParameters(); $instances = $this->getDependencies($dependencies, $parameters); return $reflector->newInstanceArgs($instances); } private function getDependencies(array $parameters, array $primitives): array { $dependencies = []; foreach ($parameters as $parameter) { $type = $parameter->getType(); if ($type === null || $type->isBuiltin()) { $name = $parameter->getName(); $dependencies[] = $primitives[$name] ?? $parameter->getDefaultValue(); } else { $dependencies[] = $this->make($type->getName()); } } return $dependencies; } public function has(string $abstract): bool { return isset($this->bindings[$abstract]); } public function forget(string $abstract): void { unset($this->bindings[$abstract], $this->instances[$abstract], $this->singletons[$abstract]); } public function flush(): void { $this->bindings = []; $this->instances = []; $this->singletons = []; } }