## 容器的基本概念
容器主要的其實就是實現了注冊樹模式。注冊樹像是一個盒子,將要用或者正在調用的實例放在盒子中,同一進程中的下次請求進入,就不會再去實例化。而是直接在盒子里面進行查找返回。
容器是主要通過`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();`