一、Db類庫巧妙結(jié)合連接器、查詢器、sql生成器使用
在上目錄中咔咔使用了query作為案例演示,這個使用在框架中是不建議使用的,因為在維護的方面會有一定的難度。
本節(jié)案例將會使用框架常用的查詢數(shù)據(jù)庫方式進行查詢。
在上圖中可以看到使用了平時最常用的查詢方式,接下來將會對這組案例進行詳細分析。
同樣代碼會來到Db類的__callStatic這個方法,這個方法就是在調(diào)用沒有聲明的靜態(tài)方法會進行執(zhí)行的。
這個方法跟__call方法是有區(qū)別的,__call方法是調(diào)用不存在的方法會進行調(diào)用,一定要注意倆者的區(qū)別。
對于上圖方法中static::connect()執(zhí)行最后會返回?object(thinkdbQuery)這個對象,至于內(nèi)部流程的執(zhí)行可以參考第二目錄的內(nèi)容。
所以執(zhí)行流程會來到thinkphp/library/think/db/Query.php這個類的table方法。
參數(shù)就是table中傳遞的數(shù)據(jù)庫表名tp_test。
按照上圖提供的代碼會對傳遞過來的表名進行三次判斷。
-
第一次判斷是否為字符串 -
第二次判斷是否存在 ) -
第三次判斷是否存在 ,
根據(jù)傳遞過來的字符串以上三個判斷均不成立,于是會執(zhí)行到下面流程。
在table這個方法中可以看到最后的執(zhí)行流程就是將傳遞過來的表名存放在屬性options這個里邊。
并且最后會將thinkdbQuery Object這個對象進行返回。
立即學(xué)習(xí)“PHP免費學(xué)習(xí)筆記(深入)”;
where方法解析
table方法分析完成后會緊接著執(zhí)行where方法,同樣還是在類thinkphp/library/think/db/Query.php
上圖中在這個類中可以看到一個方法func_get_args,這個方法會返回一個包含函數(shù)參數(shù)列表的數(shù)組。
這個方法平時都是跟call_user_func_array同時使用,之前咔咔也使用這倆個方法進行過一次案例實驗。
然后會使用函數(shù)array_shift刪除數(shù)組中的第一個元素(red),并返回被刪除元素的值。
下圖第一個結(jié)果為func_get_args這個方法獲取出來的數(shù)據(jù),第二組結(jié)果為array_shift這個方法返回的結(jié)果。
倆組結(jié)果返回的值可以進行對比一下,可以更好的理解array_shift的使用場景。
緊接著會進行分析查詢表達式,也就是方法parseWhereExp做的事情。
在這個方法中需要注意一個點就是關(guān)于傳遞過來的這倆個參數(shù)。
參數(shù)一為查詢邏輯,參數(shù)二就是在使用案例時傳入的參數(shù)。
在代碼的第一行就需要我們來學(xué)習(xí)的一個知識點instanceof。
instanceof可以判斷某個對象是否是某個類的實例,判斷一個對象是否實現(xiàn)了某個接口。
關(guān)于這個的使用案例在文章ThinkPHP源碼解析之控制器這一文中做了詳細的說明。
根據(jù)學(xué)習(xí)instanceof的作用可以清晰的明白第一個判斷不會進行執(zhí)行。
在繼續(xù)學(xué)習(xí)以下的執(zhí)行流程,根據(jù)咔咔圈出來的框來進行對代碼進行簡單的解析。
根據(jù)上圖首先會對查詢邏輯的符號全部轉(zhuǎn)為小寫
然后在進行判斷$field instanceof Where傳遞過來的參數(shù)是否為Where類的實例。
最后一個判斷就是$field instanceof Expression跟上一步是判斷同樣的功能。
所以說代碼最終的執(zhí)行邏輯就是下圖圈到的部分。
還記得在案例過程中給where傳遞的參數(shù)就是一個數(shù)組。
如果將參數(shù)改為where(‘t_id’,1)則就會走is_string($field)的這個流程,這個流程就交給大家了,咔咔就不去解析。
這里咔咔還是使用數(shù)組作為參數(shù)進行解析,那么代碼依然會執(zhí)行本類的parseArrayWhereItems這個方法
在這個方法中先需要知道key會返回什么,從當(dāng)前內(nèi)部指針位置返回元素鍵名。
所以代碼會去執(zhí)行if語句的判斷,根據(jù)上邊的所有判斷都不符合所以會執(zhí)行這段代碼$where[] = [$key, is_array($val) ? ‘IN’ : ‘=’, $val];
這段代碼會判斷循環(huán)數(shù)組的value值是否為數(shù)組,如果為數(shù)組就是in,反之為=,由于value為1所以數(shù)組的第二個值為=。
那么最終where的值就是下圖打印的數(shù)據(jù)。
由于where不為空,代碼執(zhí)行流程會執(zhí)行到下圖位置,最終在返回本類實例。
find()執(zhí)行流程
接著代碼會還是執(zhí)行本類的find方法,查找單條記錄。
由于find中是沒有傳遞參數(shù)的,所以代碼會執(zhí)行到$this->parseOptions();分析表達式(可用于查詢或者寫入操作)
就目前寫的案例而言,這段看似很長的代碼大家好好看看都可以看明白,最終依然是返回當(dāng)前的所有參數(shù)。
以下就是返回的所以結(jié)果
真正的查詢數(shù)據(jù)是這塊代碼$result = $this->connection->find($this);,這段代碼會執(zhí)行到文件thinkphp/library/think/db/Connection.php
從這塊代碼可以看到當(dāng)查詢一條數(shù)據(jù)時框架默認給加上了limit為1,至于為什么這么加你就需要查看一下sql優(yōu)化方面的知識了。
在這里就是關(guān)于sql語句的生成,代碼自己好好看看就會明白,咔咔解析的只是執(zhí)行流程和具體代碼簡單的了解一下即可。
至于具體實現(xiàn)流程咔咔在后期如果有機會會單獨把每個方法進行深度解析,那時就是主要針對代碼的解析。
最終返回結(jié)果如下