@value 注入静态属性_TP6依赖注入是如何实现的
TP6依賴注入是如何實(shí)現(xiàn)的
先看下app/provider容器文件,此文件會(huì)在thinkAPP實(shí)例化的時(shí)候
直接從新綁定類到的容器上。復(fù)制原有容器中的類
可以先看下thinkAPP 構(gòu)造方法中的處理邏輯
?/**? * 架構(gòu)方法? * @access public? * @param string $rootPath 應(yīng)用根目錄? */?public function __construct(string $rootPath = '')?{? //設(shè)置thinkphp擴(kuò)展的目錄? $this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;? //項(xiàng)目更目錄? $this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR? //應(yīng)用根目錄? $this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;? //runtime根目錄? $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATO? //檢測(cè)app/provider.php文件進(jìn)行替換容器綁定? if (is_file($this->appPath . 'provider.php')) {? $this->bind(include $this->appPath . 'provider.php');? }? //將當(dāng)前容器實(shí)例保存到成員變量「$instance」中,也就是容器自己保存自己的一個(gè)? static::setInstance($this);? 保存綁定的實(shí)例到「$instances」數(shù)組中,見對(duì)應(yīng)分析? $this->instance('app', $this);? $this->instance('thinkContainer', $this);?}在控制中可以使用app()->db 可以看到thinkApp中根本沒有此屬性,php的類中,調(diào)用一個(gè)類的不存在的屬性就會(huì)自動(dòng)進(jìn)入魔術(shù)方法__get(),再來(lái)看看app類當(dāng)中的__get方法,app類中沒有找到集成的類中也就是thinkContainer 中直接搜索__get方法,就能找到。
?thinkContainer?//$name就是就是沒有定義的屬性的名稱?public function __get($name)?{? return $this->get($name);?}找到當(dāng)前類的get方法,首先是檢查了以下容器中有沒有,沒有就直接實(shí)例化,進(jìn)行調(diào)用make方法進(jìn)行創(chuàng)建類的實(shí)例化。
?/**? ?* 獲取容器中的對(duì)象實(shí)例? ?* @access public? ?* @param string $abstract 類名或者標(biāo)識(shí)? ?* @return object? ?*/?public function get($abstract)?{? if ($this->has($abstract)) {? return $this->make($abstract);? }? throw new ClassNotFoundException('class not exists: ' . $abstract, $a?}make主要檢測(cè)有沒實(shí)例化過由實(shí)例化過后就直接返回使用就行,沒有就需要利用類的反射來(lái)創(chuàng)建類的實(shí)例化,可以看到調(diào)用了本類的invokeClass方法
?public function make(string $abstract, array $vars = [], bool $newInstance =?{? ? ?? //如果已經(jīng)存在實(shí)例,且不強(qiáng)制創(chuàng)建新的實(shí)例,直接返回已存在的實(shí)例? if (isset($this->instances[$abstract]) && !$newInstance) {? return $this->instances[$abstract];? }? ? ?? //如果有綁定,比如 'http'=> 'thinkHttp',則 $concrete = 'thinkHttp'? if (isset($this->bind[$abstract])) {? $concrete = $this->bind[$abstract];? if ($concrete instanceof Closure) {? $object = $this->invokeFunction($concrete, $vars);? } else {? //重走一遍make函數(shù),比如上面http的例子,則會(huì)調(diào)到后面「invokeClass? return $this->make($concrete, $vars, $newInstance);? }? } else {? //實(shí)例化需要的類,比如'thinkHttp'? $object = $this->invokeClass($abstract, $vars);? }? if (!$newInstance) {? $this->instances[$abstract] = $object;? }? return $object;?}invokeClass方法主要為了綁定參數(shù)然后進(jìn)行實(shí)例化類,綁定參數(shù)由bindParams方法實(shí)現(xiàn),而bindParams方法中的getObjectParam方法中又會(huì)回調(diào)make方法。
?/**? ?* 調(diào)用反射執(zhí)行類的實(shí)例化 支持依賴注入? ?* @access public? ?* @param string $class 類名? ?* @param array $vars 參數(shù)? ?* @return mixed? ?*/?public function invokeClass(string $class, array $vars = [])?{? try {? //通過反射實(shí)例化類? $reflect = new ReflectionClass($class);? //檢查是否有「__make」方法? if ($reflect->hasMethod('__make')) {? $method = new ReflectionMethod($class, '__make');? //檢查是否是公有方法且是靜態(tài)方法? if ($method->isPublic() && $method->isStatic()) {? //綁定參數(shù)? $args = $this->bindParams($method, $vars);? ? ? ? ? ? ? ? ?//調(diào)用該方法(__make),因?yàn)槭庆o態(tài)的,所以第一個(gè)參數(shù)是null? ? ? ? ? ? ? ? ?//因此,可得知,一個(gè)類中,如果有__make方法,在類實(shí)例化之前會(huì)首? ? ? ? ? ? ? ? ?return $method->invokeArgs(null, $args);? }? }? ? ? ? ?//獲取類的構(gòu)造函數(shù)? ? ? ? ?$constructor = $reflect->getConstructor();? ? ? ? ?//有構(gòu)造函數(shù)則綁定其參數(shù)? ? ? ? ?$args = $constructor ? $this->bindParams($constructor, $vars) : [? ? ? ? ?//根據(jù)傳入的參數(shù),通過反射,實(shí)例化類? ? ? ? ?$object = $reflect->newInstanceArgs($args);? ? ? ? ?// 執(zhí)行容器回調(diào)? ? ? ? ?$this->invokeAfter($class, $object);? ? ? ? ?return $object;? } catch (ReflectionException $e) {? throw new ClassNotFoundException('class not exists: ' . $class, $? }?}getObjectParam方法中是拿到當(dāng)前類實(shí)例化的參數(shù),找到當(dāng)前參數(shù)是否是類,如果是就會(huì)直接再次調(diào)用make方法,如果下個(gè)參數(shù)還是個(gè)類的實(shí)例化結(jié)果,會(huì)再次進(jìn)行回調(diào),這就是一個(gè)類中可以無(wú)限制的注入多個(gè)類的原理,所以在使用的當(dāng)中運(yùn)用app()->make()來(lái)進(jìn)行獲取類的例化,更加方便簡(jiǎn)潔
?/**? ?* 獲取對(duì)象類型的參數(shù)值? ?* @access protected? ?* @param string $className 類名? ?* @param array $vars 參數(shù)? ?* @return mixed? ?*/?protected function getObjectParam(string $className, array &$vars)?{? ? ?$array = $vars;? ? ?$value = array_shift($array);? ? ?if ($value instanceof $className) {? ? ? ? ?$result = $value;? ? ? ? ?array_shift($vars);? ? } else {? ? ? ? ?$result = $this->make($className);? ? }? ? ?return $result;?}總的來(lái)說(shuō),整個(gè)過程大概是這樣的:需要實(shí)例化 Db 類 ==> 提取構(gòu)造函數(shù)發(fā)現(xiàn)其依賴App 類==> 開始實(shí)例化 App 類(如果發(fā)現(xiàn)還有依賴,則一直提取下去,直到依賴全部加載完)==>將實(shí)例化好的依賴(App 類的實(shí)例)傳入 Db類來(lái)實(shí)例化 Db類。
感謝您的閱讀,如果對(duì)您有幫助,歡迎關(guān)注"CRMEB"頭條號(hào)。碼云上有我們開源的商城項(xiàng)目,知識(shí)付費(fèi)項(xiàng)目,均是基于PHP開發(fā),學(xué)習(xí)研究歡迎使用,關(guān)注我們保持聯(lián)系!
總結(jié)
以上是生活随笔為你收集整理的@value 注入静态属性_TP6依赖注入是如何实现的的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html提交表单使用python计算_教
- 下一篇: cesium加载entity图片缩放_C