💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 容器的基本概念 容器主要的其实就是实现了注册树模式。注册树像是一个盒子,将要用或者正在调用的实例放在盒子中,同一进程中的下次请求进入,就不会再去实例化。而是直接在盒子里面进行查找返回。 容器是主要通过`think\Container`类来实现的。我们分析一下app类通过容器进行实例化的过程,`Container::get('app')`; ``` public static function get($abstract, $vars = [], $newInstance = false){ return static::getInstance()->make($abstract, $vars, $newInstance); } ``` 可以看出,主要是通过Container类的make方法进行实例化。 ``` public function make($abstract, $vars = [], $newInstance = false){ if (true === $vars) { // 总是创建新的实例化对象 $newInstance = true; $vars = []; } $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract; // 若对象树中有该对象的实例,则直接返回 if (isset($this->instances[$abstract]) && !$newInstance) { return $this->instances[$abstract]; } // 是否有容器绑定标识。然后通过容器标识来找到最终实例化的类 if (isset($this->bind[$abstract])) { $concrete = $this->bind[$abstract]; if ($concrete instanceof Closure) { $object = $this->invokeFunction($concrete, $vars); } else { return $this->make($concrete, $vars, $newInstance); } } else { $object = $this->invokeClass($abstract, $vars); } if (!$newInstance) { $this->instances[$abstract] = $object; } return $object; } ``` make先根据参数,判断是否总是创建新的实例。在根据容器对象实例数组$instances,判断是否有该实例,若有则直接返回。如果无,则进行实例化。先根据绑定标识找到需要实例化的类。若无绑定标识,则直接实例化类。 是通过invokeClass类调用反射执行实例化,和支持依赖注入的。若需要实例化的类中有__make方法,则先执行__make方法。在执行构造方法 进行实例化。 ``` public function invokeClass($class, $vars = []){ try { // 利用反射机制,获取到需要实例化的反射类 $reflect = new ReflectionClass($class); // 若有__make方法,则先执行 if ($reflect->hasMethod('__make')) { $method = new ReflectionMethod($class, '__make'); if ($method->isPublic() && $method->isStatic()) { // 绑定函数的参数,支持依赖注入 $args = $this->bindParams($method, $vars); return $method\->invokeArgs(null, $args); } } // 通过反射类获取到类的构造函数 $constructor = $reflect->getConstructor(); // 绑定构造函数的参数,支持依赖注入 $args = $constructor ? $this->bindParams($constructor, $vars) : []; // 执行构造函数,并返回实例化对象 return $reflect->newInstanceArgs($args); } catch (ReflectionException $e) { throw new ClassNotFoundException('class not exists: ' . $class, $class); } } ``` > Container类继承了ArrayAccess接口。我们可以通过访问数组的方式,来获取类的实例。如index.php中代码可以改写成`$container = new Container; $cntainer['app']->run()->send();`