## [【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);
~~~

[](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 }
~~~
[](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類我們可以看一下 實際很簡短
[](javascript:void(0); "復制代碼")
~~~
interface ArrayAccess {
public function offsetExists($offset);
public function offsetGet($offset);
public function offsetSet($offset, $value);
public function offsetUnset($offset);
}
~~~
[](javascript:void(0); "復制代碼")
就這么四個方法? 分別是判斷是否存在,獲取,設置,刪除,(也數組的增刪改查)
那么我們想一下一個對象,肯定可有對一個對象的屬性進行增刪改查的行為吧
在這里Container這個類里面? 這四個方法 對應的實現是
[](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);
}
~~~
[](javascript:void(0); "復制代碼")
其中 $this->bind我們前面說過 它有兩個作用 關于第二個作用 就是把一個類實例塞到容器中, 也就是一開始那個instances數組里面插入一條 以便后面使用
make暫不解釋,delete和exists比較簡單,分別從instances數組里面刪除一個元素;判斷instances數組里面是否存在等
這里既然Contaner類實現了ArrayAccesss 且給四個方法實現了具備自己特色的功能 那么在實際場景中 我們該如何去使用呢
我們可以在TP原來的index控制器 \[tp6\\app\\controller\\Index.php\]文件下 寫點測試代碼
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控制 隨意寫點測試代碼
[](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 }
~~~
[](javascript:void(0); "復制代碼")
可以觀察下打印結果$app類里面 $bind 屬性和? $instances 屬性的變化

[](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}
~~~
[](javascript:void(0); "復制代碼")
- thinkphp6執行流程(一)
- php中use關鍵字用法詳解
- Thinkphp6使用騰訊云發送短信步驟
- 路由配置
- Thinkphp6,static靜態資源訪問路徑問題
- ThinkPHP6.0+ 使用Redis 原始用法
- smarty在thinkphp6.0中的最佳實踐
- Thinkphp6.0 搜索器使用方法
- 從已有安裝包(vendor)恢復 composer.json
- tp6with的用法,表間關聯查詢
- thinkphp6.x多對多如何添加中間表限制條件
- thinkphp6 安裝JWT
- 緩存類型
- 請求信息和HTTP頭信息
- 模型事件用法
- 助手函數匯總
- tp6集成Alipay 手機和電腦端支付的方法
- thinkphp6使用jwt
- 6.0session cookie cache
- tp6筆記
- TP6(thinkphp6)隊列與延時隊列
- thinkphp6 command(自定義指令)
- command(自定義指令)
- 本地文件上傳
- 緩存
- 響應
- 公共函數配置
- 七牛云+文件上傳
- thinkphp6:訪問多個redis數據源(thinkphp6.0.5 / php 7.4.9)
- 富文本編輯器wangEditor3
- IP黑名單
- 增刪改查 +文件上傳
- workerman 定時器操作控制器的方法
- 上傳文件到阿里云oss
- 短信或者郵箱驗證碼防刷代碼
- thinkphp6:訪問redis6(thinkphp 6.0.9/php 8.0.14)
- 實現關聯多個id以逗號分開查詢數據
- thinkphp6實現郵箱注冊功能的細節和代碼(點擊鏈接激活方式)
- 用mpdf生成pdf文件(php 8.1.1 / thinkphp v6.0.10LTS )
- 生成帶logo的二維碼(php 8.1.1 / thinkphp v6.0.10LTS )
- mysql數據庫使用事務(php 8.1.1 / thinkphp v6.0.10LTS)
- 一,創建過濾IP的中間件
- 源碼解析請求流程
- 驗證碼生成
- 權限管理
- 自定義異常類
- 事件監聽event-listene
- 安裝與使用think-addons
- 事件與多應用
- Workerman 基本使用
- 查詢用戶列表按拼音字母排序
- 擴展包合集
- 查詢用戶數據,但是可以通過輸入用戶昵稱來搜索用戶同時還要統計用戶的文章和粉絲數
- 根據圖片的minetype類型獲取文件真實拓展名思路
- 到處excel
- 用imagemagick庫生成縮略圖
- 生成zip壓縮包并下載
- API 多版本控制
- 用redis+lua做限流(php 8.1.1 / thinkphp v6.0.10LTS )
- 【thinkphp6源碼分析三】 APP類之父, 容器Container類
- thinkphp6表單重復提交解決辦法
- 小程序授權
- 最簡單的thinkphp6導出Excel
- 根據訪問設備不同訪問不同模塊
- 服務系統
- 前置/后置中間件
- 給接口api做簽名驗證(php 8.1.1 / thinkphp v6.0.10LTS )
- 6實現郵箱注冊功能的細節和代碼(點擊鏈接激活方式)
- 使用前后端分離的驗證碼(thinkphp 6.0.9/php 8.0.14/vue 3.2.26)
- 前后端分離:用jwt+middleware做用戶登錄驗證(php 8.1.1 / thinkphp v6.0.10LTS )
- vue前后端分離多圖上傳
- thinkphp 分組、頁面跳轉與ajax
- thinkphp6 常用方法文檔
- 手冊里沒有的一些用法
- Swagger 3 API 注釋
- PHP 秒級定時任務
- thinkphp6集成gatewayWorker(workerman)實現實時監聽
- thinkphp6按月新增數據表
- 使用redis 實現消息隊列
- api接口 統一結果返回處理類
- 使用swoole+thinkphp6.0+redis 結合開發的登錄模塊
- 給接口api做簽名驗證
- ThinkPHP6.0 + UniApp 實現小程序的 微信登錄
- ThinkPHP6.0 + Vue + ElementUI + axios 的環境安裝到實現 CURD 操作!
- 異常$e
- 參數請求驗證自定義和異常錯誤自定義