ThinkPHP容器之容器是如何返回实例的
时间:2022-03-03 11:48
在之前的文章中我们简单的梳理了一下容器类,接下来就是对其中一个细节进行深度分析。 Container实例调用make方法 本文没有太多文字解析,都在代码注释中说明了执行过程。 代码 在开始阅读make方法里边的源码之前,我们需要先对几个属性进行简单的梳理一下。 这四个属性一定要有点印象,并且一定要区别instance和instances。 这俩个属性一个是单例模式返回当前类的实例,一个是容器中的所有的实例。 第一次执行结果 这是第二次执行流程 执行流程图 既然把代码都理清楚了,这时来理一下执行的流程图可以看的更清晰。 坚持学习、坚持写博、坚持分享是咔咔从业以来一直所秉持的信念。希望在偌大互联网中咔咔的文章能带给你一丝丝帮助。我是咔咔,下期见。“
static::getInstance()
返回了Container的实例后,就会去调用本类的make方法,接下来就是对make方法进行详解了。 /**
* 创建类的实例
* @access public
* @param string $abstract 类名或者标识
* @param array|true $vars 变量
* @param bool $newInstance 是否每次创建新的实例
* @return object
*/
public function make($abstract, $vars = [], $newInstance = false)
{
// 判断$vars这个变量是否为true
if (true === $vars) {
// 总是创建新的实例化对象
$newInstance = true;
$vars = [];
}
// app 这里就是在容器别名里获取传递过来的app 如果没有则就是app
$abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;
// 从容器实例中获取 如果存在则直接返回对应的实例 也就是使用注册树模式
if (isset($this->instances[$abstract]) && !$newInstance) {
return $this->instances[$abstract];
}
// think\App 从容器标识中获取
if (isset($this->bind[$abstract])) {
// 将think\App 复制给$concrete变量
$concrete = $this->bind[$abstract];
// 用于代表匿名函数的类 判断是不是闭包
if ($concrete instanceof Closure) {
$object = $this->invokeFunction($concrete, $vars);
} else {
// $this->name['app'] = think\App
$this->name[$abstract] = $concrete;
// 在执行一次本类的make方法,也就是本方法
return $this->make($concrete, $vars, $newInstance);
}
} else {
$object = $this->invokeClass($abstract, $vars);
}
if (!$newInstance) {
$this->instances[$abstract] = $object;
}
return $object;
} public function make($abstract, $vars = [], $newInstance = false)
{
// 判断$vars这个变量是否为true
if (true === $vars) {
// 总是创建新的实例化对象
$newInstance = true;
$vars = [];
}
// app 这里就是在容器别名里获取传递过来的app 如果没有则就是app
// 第二次执行时 $abstract = think\App
$abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;
// 从容器实例中获取 如果存在则直接返回对应的实例 也就是使用注册树模式
if (isset($this->instances[$abstract]) && !$newInstance) {
return $this->instances[$abstract];
}
// think\App 从容器标识中获取
// 第二次执行$this->bind['think\App']不存在走else
if (isset($this->bind[$abstract])) {
// 将think\App 复制给$concrete变量
$concrete = $this->bind[$abstract];
// 用于代表匿名函数的类 判断是不是闭包
if ($concrete instanceof Closure) {
$object = $this->invokeFunction($concrete, $vars);
} else {
// $this->name['app'] = think\App
$this->name[$abstract] = $concrete;
// 在执行一次本类的make方法,也就是本方法
// think\App
return $this->make($concrete, $vars, $newInstance);
}
} else {
// think\App
$object = $this->invokeClass($abstract, $vars);
}
if (!$newInstance) {
// 把创建的容器存起来
//$this->instances['think\App'] = $object;
$this->instances[$abstract] = $object;
}
return $object;
}public function invokeClass($class, $vars = [])
{
try {
/**
* ReflectionClass Object
(
[name] => think\App
)
*/
// 这里就是之前文章提到的反射
$reflect = new ReflectionClass($class);
if ($reflect->hasMethod('__make')) {
$method = new ReflectionMethod($class, '__make');
if ($method->isPublic() && $method->isStatic()) {
$args = $this->bindParams($method, $vars);
return $method->invokeArgs(null, $args);
}
}
// 通过反射获取think\App的构造函数
$constructor = $reflect->getConstructor();
$args = $constructor ? $this->bindParams($constructor, $vars) : [];
// 从给出的参数创建一个新的类实例
return $reflect->newInstanceArgs($args);
} catch (ReflectionException $e) {
throw new ClassNotFoundException('class not exists: ' . $class, $class);
}
}“
以上就是ThinkPHP容器之容器是如何返回实例的的详细内容,更多请关注www.gxlsystem.com其它相关文章!