## 容器的基本概念
容器主要的其实就是实现了注册树模式。注册树像是一个盒子,将要用或者正在调用的实例放在盒子中,同一进程中的下次请求进入,就不会再去实例化。而是直接在盒子里面进行查找返回。
容器是主要通过`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();`