💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## [【thinkphp6源码分析三】 APP类之父, 容器Container类](https://www.cnblogs.com/dk1988/p/14513837.html) 上一篇关于APP类的构造函数 最后还有三句话 ~~~ 1 static::setInstance($this); 2 $this->instance('app', $this); 3 $this->instance('think\Container', $this); ~~~ ![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") ~~~ 1 /** 2 * 绑定一个类实例到容器 3 * @access public 4 * @param string $abstract 类名或者标识 5 * @param object $instance 类的实例 6 * @return $this 7 */ 8 public function instance(string $abstract, $instance) 9 { 10 $abstract = $this->getAlias($abstract); 11 12 $this->instances[$abstract] = $instance; 13 14 return $this; 15 } ~~~ [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") 这里基本都涉及到APP的父类**Container**\[tp6\\vendor\\topthink\\framework\\src\\think\\Container.php\]了 第一句话 是设置了Container类的$instance属性 把这个属性设置为APP类的实例 这里可以理解为 Container是一个比较抽象的容器类,它可以作用于任何框架,而APP类则相当于这个抽象容器的实现,也就是适合TP框架的一个容器类 \[对应前面说过的注册树模式 这里是实例化一个适用于TP框架的 TP容器注册树\] 第二句和第三句 是设置容器里面的东西 将具体的类实例放到容器中仔细看 它们是设置了一个叫  instances数组(这里多了一个s)的内容 \[对应前面说过的注册树模式 这里是开始给这棵树挂苹果了 目前挂了两个苹果 一个叫app 一个叫think\\Container 俩苹果的内容是相同的 后面 框架一定会给这棵树挂更多的苹果 如db config cache等等\] 我们继续看Container类 Container类本身代码并不复杂 但是看得相当懵逼,因为太抽象了 ,光看这个代码根本不知道这些代码干嘛的? 但实际上 这个基本 可以说是所有框架的基石不为过 它的细节作用 其实从它的第一句话可以看出来 ***class Container implements ContainerInterface, ArrayAccess, IteratorAggregate, Countable*** 它分别实现了***ContainerInterface(容器) ;***ArrayAccess(数组式访问); ***IteratorAggregate(聚合迭代器);***Countable(可计数的)************ 上面()里面的中文只是这些单词的翻译,实际上也的确就是这些翻译的字面意思 ***第一个ContainerInterfac**e*先放一放 它自己都叫容器 那么容器接口的实现当然是它最主要的功能 ***我们看第二个ArrayAccess*** 这东西叫数组式访问 那么是把啥当数组式访问呢 也就对象了 我们在用TP框架的时候 应该没少写或者见过这样的东西 $user=new UserModel() $user\['username'\]  =  "卢小霏"; 按照我们正统语法 这样写是错误的  $user 是个对象 要使用它的属性 应该用$user->username呀? 但由于数组和对象这俩有比较多的共同点,PHP就提供了******ArrayAccess******接口  只要我们实现它 上面例子 UserModel就实现了ArrayAccess  就能把对象当做数组来使用了 ArrayAccess类我们可以看一下 实际很简短 [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") ~~~ interface ArrayAccess { public function offsetExists($offset); public function offsetGet($offset); public function offsetSet($offset, $value); public function offsetUnset($offset); } ~~~ [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") 就这么四个方法  分别是判断是否存在,获取,设置,删除,(也数组的增删改查) 那么我们想一下一个对象,肯定可有对一个对象的属性进行增删改查的行为吧 在这里Container这个类里面  这四个方法 对应的实现是 [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") ~~~ public function offsetExists($key) { return $this->exists($key); } public function offsetGet($key) { return $this->make($key); } public function offsetSet($key, $value) { $this->bind($key, $value); } public function offsetUnset($key) { $this->delete($key); } ~~~ [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") 其中 $this->bind我们前面说过 它有两个作用 关于第二个作用 就是把一个类实例塞到容器中, 也就是一开始那个instances数组里面插入一条 以便后面使用 make暂不解释,delete和exists比较简单,分别从instances数组里面删除一个元素;判断instances数组里面是否存在等 这里既然Contaner类实现了ArrayAccesss 且给四个方法实现了具备自己特色的功能 那么在实际场景中 我们该如何去使用呢 我们可以在TP原来的index控制器 \[tp6\\app\\controller\\Index.php\]文件下 写点测试代码 ![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)View Code 由于APP这个类继承了Container Container这个类又实现了ArrayAccess 那么我们就可以像玩数组一样去 玩$app类 $app\[\] =  xxx ====》这样就等同于去执行$app类里面的bind方法 最终效果是$instances 里面 会多出user 和user2 两个对象实例 然后既然是数组 unset这个函数也可以使用   unset($app\['user2'\])   ===>这个就等同于去执行$app类里面的delete方法  最终就是把$instances里面的对应元素进行删除 这样使用的话 是不是就发现很方便呢 *********第三个IteratorAggregate(聚合迭代器)*********这个目前框架上的应用不是很多 配合yield关键字 可以达到一种省内存的目的,一般可以用于Excel大数据导出之类 如果以后遇到例子再细讲 *********************第四个Countable(可计数的)*********************对象里面的统计功能,在Container类里面 它统计了instaces里面的元素个数,也就是有多少“东西”已经在容器中 最后 我们再回到容器类的核心部分   它首先实现了***ContainerInterface***这个接口 这个接口的作用很简单 一个get 一个has get 的实现  实际我们第一章就遇到过  它们通过make函数 来创建容器里面的实例(存在就直接读取 不重复创建)    has则是判断容器里面某个实例是否存在 \[关于make函数我们先大体上了解它的作用记性  极其简单的可以先认为 它等同于New关键字  即实例化一个类从而获得一个对象;  它有些其它的功能相当复杂 主要是涉及到依赖注入和反射相关知识 这个后面的章节会仔细讲到的\] make函数里面有 $this->instances\[$abstract\] = $object;  这一句话 这玩意那实际就和bind函数一样了  这里就是make先创建出一个实例 然后塞到容器里面  关于bind和make 我们可以在index控制 随意写点测试代码 [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") ~~~ 1 public function index() 2 { 3 $app =new App(); 4 5 $userModel =new User(); 6 //先注释之前 先捋一下类 和实例的关系 app\model\User是类 new app\model\User()是实例 7 //给app\model\User 加一个别名 myUserClass 这个别名会在app-> $bind属性里面 8 $app->bind("myUserClass","app\model\User"); 9 10 //将User类的实例 $userModel 放到容器中 并且给个别名 myUser 这个myUser会在app -> $instances里面 11 $app->bind("myUser",$userModel); 12 13 //利用make函数 去实例化User类 这里完全等同于 new app\model\User() 14 $userModel1 =$app->make("app\model\User"); 15 //由于 app\model\User 类有个别名 myUserClass 所以这里可以直接这样去make 16 $userModel2 =$app->make("myUserClass"); 17 //由于上面的类实例 $userModel 也有别名了 这里也可以直接使用myUser 相当于去$instances数组里面 直接找到它来使用 18 $userModel3 =$app->make("myUser"); 19 20 dump($app); 21 dump($userModel1); 22 dump($userModel2); 23 dump($userModel3);die; 24 //return $str ; 25 26 } ~~~ [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") 可以观察下打印结果$app类里面 $bind 属性和  $instances 属性的变化 ![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif) [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码") ~~~ ^ think\App {#50 ▼ #appDebug: false #beginTime: null #beginMem: null #namespace: "app" #rootPath: "D:\php\wamp64_3.17\www\tp6\" #thinkPath: "D:\php\wamp64_3.17\www\tp6\vendor\topthink\framework\src\" #appPath: "D:\php\wamp64_3.17\www\tp6\app\" #runtimePath: "D:\php\wamp64_3.17\www\tp6\runtime\" #routePath: "" #configExt: ".php" #initializers: array:3 [▶] #services: [] #initialized: false #bind: array:27 [▼ "app" => "think\App" "cache" => "think\Cache" "config" => "think\Config" "console" => "think\Console" "cookie" => "think\Cookie" "db" => "think\Db" "env" => "think\Env" "event" => "think\Event" "http" => "think\Http" "lang" => "think\Lang" "log" => "think\Log" "middleware" => "think\Middleware" "request" => "think\Request" "response" => "think\Response" "route" => "think\Route" "session" => "think\Session" "validate" => "think\Validate" "view" => "think\View" "filesystem" => "think\Filesystem" "think\DbManager" => "think\Db" "think\LogManager" => "think\Log" "think\CacheManager" => "think\Cache" "Psr\Log\LoggerInterface" => "think\Log" "think\Request" => "app\Request" "think\exception\Handle" => "app\ExceptionHandle" "myRequest" => "app\Request" "myUserClass" => "app\model\User" ] #instances: array:4 [▼ "think\App" => think\App {#50} "think\Container" => think\App {#50} "myUser" => app\model\User {#51} "app\model\User" => app\model\User {#53} ] #invokeCallback: [] } ^ app\model\User {#53} ^ app\model\User {#53} ^ app\model\User {#51} ~~~ [![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); "复制代码")