TP5.1的核心代码解析之容器

it2022-05-07  3

最近看了看ThinkPHP5.1的核心代码,使用了容器的思想,简单解析一下具体实现:

首先看到

\thinkphp\base.php 1

文件中的初始化绑定类到容器的方法:

// 注册核心类到容器 Container::getInstance()->bind([ 'app' => App::class, 'build' => Build::class, 'cache' => Cache::class, 'config' => Config::class, 'cookie' => Cookie::class, 'debug' => Debug::class, 'env' => Env::class, 'hook' => Hook::class, 'lang' => Lang::class, 'log' => Log::class, 'request' => Request::class, 'response' => Response::class, 'route' => Route::class, 'session' => Session::class, 'url' => Url::class, 'validate' => Validate::class, 'view' => View::class, 'middlewareDispatcher' => http\middleware\Dispatcher::class, // 接口依赖注入 'think\LoggerInterface' => Log::class, ]); 1234567891011121314151617181920212223

Container类就是所说的容器类,绑定的本质其实就是绑定了类的简称和类的真实名称(方便后面用简称实例化类):

/** * 绑定一个类、闭包、实例、接口实现到容器 * @access public * @param string|array $abstract 类标识、接口 * @param mixed $concrete 要绑定的类、闭包或者实例 * @return $this */ public function bind($abstract, $concrete = null) { if (is_array($abstract)) { $this->bind = array_merge($this->bind, $abstract); } elseif ($concrete instanceof Closure) { $this->bind[$abstract] = $concrete; } elseif (is_object($concrete)) { $this->instances[$abstract] = $concrete; } else { $this->bind[$abstract] = $concrete; } return $this; } 1234567891011121314151617181920

可以看到如上面的代码(这里先不考虑闭包也就是Closure)的情况,可以看到其实就是将这个绑定的数组传到类中的$this->bind参数中,方便使用,具体使用方式如下:

$app = Container::get('app'); 1

如上面的代码实际上调用了Container类中的下面方法:

/** * 获取容器中的对象实例 * @access public * @param string $abstract 类名或者标识 * @param array|true $vars 变量 * @param bool $newInstance 是否每次创建新的实例 * @return object */ public static function get($abstract, $vars = [], $newInstance = false) { return static::getInstance()->make($abstract, $vars, $newInstance); } 123456789101112

也就是make方法:

/** * 创建类的实例 * @access public * @param string $abstract 类名或者标识 * @param array|true $args 变量 * @param bool $newInstance 是否每次创建新的实例 * @return object */ public function make($abstract, $vars = [], $newInstance = false) { if (true === $vars) { // 总是创建新的实例化对象 $newInstance = true; $vars = []; } if (isset($this->instances[$abstract]) && !$newInstance) { $object = $this->instances[$abstract]; } else { if (isset($this->bind[$abstract])) { $concrete = $this->bind[$abstract]; if ($concrete instanceof Closure) { $object = $this->invokeFunction($concrete, $vars); } else { $object = $this->make($concrete, $vars, $newInstance); } } else { $object = $this->invokeClass($abstract, $vars); } if (!$newInstance) { $this->instances[$abstract] = $object; } } return $object; } 1234567891011121314151617181920212223242526272829303132333435

其他可以忽略,其实质就是:

如果$newInstance不为true, 直接就会调用$object = $this->invokeClass($abstract, $vars);方法来实例化类, 而$abstract的名称本质就是用$this->bind的上面绑定的数组获取的类(这里是app) 的真实命名(上面传的App::class) 1234

当然中间可能绕了一下,实际上就是这样。

invokeClass方法如下:

/** * 调用反射执行类的实例化 支持依赖注入 * @access public * @param string $class 类名 * @param array $vars 变量 * @return mixed */ public function invokeClass($class, $vars = []) { $reflect = new ReflectionClass($class); $constructor = $reflect->getConstructor(); if ($constructor) { $args = $this->bindParams($constructor, $vars); } else { $args = []; } return $reflect->newInstanceArgs($args); } 123456789101112131415161718

至于容器,我的理解就是借助一个第三方类统一管理并获取你需要的类的实例。

以上

转载自:https://blog.csdn.net/u014359108/article/details/79556538


最新回复(0)