ThinkPHP容器之容器是如何返回实例的

发布时间 - 2020-10-12 00:00:00    点击率:

在之前的文章中我们简单的梳理了一下容器类,接下来就是对其中一个细节进行深度分析。

Container实例调用make方法

本文没有太多文字解析,都在代码注释中说明了执行过程。

代码static::getInstance()返回了Container的实例后,就会去调用本类的make方法,接下来就是对make方法进行详解了。

在开始阅读make方法里边的源码之前,我们需要先对几个属性进行简单的梳理一下。

这四个属性一定要有点印象,并且一定要区别instance和instances。

这俩个属性一个是单例模式返回当前类的实例,一个是容器中的所有的实例。

第一次执行结果

   /**
* 创建类的实例
* @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  # Static  # 编辑器  # 本类  # 咔咔  # 如果没有  # 这是  # 我是  # 几个  # 就是在  # 给你  # 都在 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 魔方云NAT建站如何实现端口转发?  如何快速生成橙子建站落地页链接?  Laravel定时任务怎么设置_Laravel Crontab调度器配置  电商网站制作价格怎么算,网上拍卖流程以及规则?  北京网站制作的公司有哪些,北京白云观官方网站?  Laravel怎么实现API接口鉴权_Laravel Sanctum令牌生成与请求验证【教程】  Laravel Debugbar怎么安装_Laravel调试工具栏配置指南  教学论文网站制作软件有哪些,写论文用什么软件 ?  Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康  如何确认建站备案号应放置的具体位置?  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  ,南京靠谱的征婚网站?  做企业网站制作流程,企业网站制作基本流程有哪些?  JS去除重复并统计数量的实现方法  JavaScript模板引擎Template.js使用详解  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全  javascript中的try catch异常捕获机制用法分析  如何确保FTP站点访问权限与数据传输安全?  微信小程序 闭包写法详细介绍  Laravel如何实现文件上传和存储?(本地与S3配置)  VIVO手机上del键无效OnKeyListener不响应的原因及解决方法  Laravel如何使用集合(Collections)进行数据处理_Laravel Collection常用方法与技巧  Laravel怎么在Blade中安全地输出原始HTML内容  Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)  nodejs redis 发布订阅机制封装实现方法及实例代码  如何快速搭建虚拟主机网站?新手必看指南  如何在万网ECS上快速搭建专属网站?  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  Python高阶函数应用_函数作为参数说明【指导】  Edge浏览器如何截图和滚动截图_微软Edge网页捕获功能使用教程【技巧】  大学网站设计制作软件有哪些,如何将网站制作成自己app?  HTML 中动态设置元素 name 属性的正确语法详解  uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  详解Oracle修改字段类型方法总结  如何快速搭建高效服务器建站系统?  广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?  Laravel N+1查询问题如何解决_Eloquent预加载(Eager Loading)优化数据库查询  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  瓜子二手车官方网站在线入口 瓜子二手车网页版官网通道入口  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  Laravel怎么在Controller之外的地方验证数据  JavaScript中的标签模板是什么_它如何扩展字符串功能  Laravel如何实现事件和监听器?(Event & Listener实战)  Laravel如何实现用户角色和权限系统_Laravel角色权限管理机制  如何在IIS中新建站点并配置端口与物理路径?  在线制作视频的网站有哪些,电脑如何制作视频短片?  如何用5美元大硬盘VPS安全高效搭建个人网站?  node.js报错:Cannot find module 'ejs'的解决办法  Windows10如何更改计算机工作组_Win10系统属性修改Workgroup