在上目錄中咔咔使用了query作為案例演示,這個使用在框架中是不建議使用的,因為在維護的方面會有一定的難度。
本節案例將會使用框架常用的查詢資料庫方式來查詢。
在上圖中可以看到使用了平時最常用的查詢方式,接下來將會對這組案例進行詳細分析。
同樣程式碼會來到Db類別的__callStatic
這個方法,這個方法就是在呼叫沒有宣告的靜態方法會執行的。
這個方法跟__call方法是有差別的,__call方法是呼叫不存在的方法會被調用,一定要注意兩個人的差別。
對於上圖方法中static::connect()
執行最後會傳回 object(think \db\Query)
這個對象,至於內部流程的執行可以參考第二目錄的內容。
所以執行流程會來到thinkphp/library/think/db/Query.php
這個類別的table
方法。
參數就是table中傳遞的資料庫表名tp_test
#。
依照上圖提供的程式碼會對傳遞過來的表名進行三次判斷。
根據傳遞過來的字串以上三個判斷皆不成立,於是會執行到下面流程。
在table這個方法中可以看到最後的執行流程就是將傳遞過來的表名存放在屬性options
這個裡邊。
並且最後會將think\db\Query Object
這個物件進行傳回。
#where方法解析
table方法分析完成後會緊接著執行where方法,同樣還是在類別thinkphp/library/think/db/Query.php
上圖中在這個類別中可以看到一個方法func_get_args
,這個方法會傳回一個包含函數參數清單的陣列。
這個方法平常都是跟call_user_func_array
同時使用,之前咔咔也使用這兩個方法進行過一次案例實驗。
接著會使用函數array_shift
刪除陣列中的第一個元素(red),並傳回被刪除元素的值。
下圖第一個結果為func_get_args
這個方法取得出來的數據,第二組結果為array_shift
這個方法傳回的結果。
兩個群組結果回傳的值可以比較一下,可以更好的理解array_shift
的使用場景。
# 緊接著會進行分析查詢表達式,也就是方法parseWhereExp
做的事情。
在這個方法中需要注意一個點就是關於傳遞過來的這兩個參數。
參數一為查詢邏輯,參數二就是使用案例時傳入的參數。
在程式碼的第一行就需要我們來學習的一個知識點instanceof
。
instanceof
可以判斷某個物件是否是某個類別的實例,判斷一個物件是否實作了某個介面。
關於這個的使用案例在文章ThinkPHP源碼解析之控制器
這一文中做了詳細的說明。
根據學習instanceof
的作用可以清楚的明白第一個判斷不會執行。
在繼續學習以下的執行流程,根據咔咔圈出來的框框來進行對程式碼進行簡單的解析。
根據上圖首先會對查詢邏輯的符號全部轉為小寫
然後在判斷$field instanceof Where
傳遞過來的參數是否為Where類別的實例。
最後一個判斷就是$field instanceof Expression
跟上一步是判斷同樣的功能。
所以說程式碼最終的執行邏輯就是下圖圈到的部分。
#還記得在案例過程中傳遞給where的參數就是一個陣列。
如果將參數改為where('t_id',1)
則就會走is_string($field)
的這個流程,這個流程就交給大家了,咔咔就不去解析。
這裡咔咔咔還是使用陣列作為參數來解析,那麼程式碼還是會執行本類的parseArrayWhereItems
這個方法
在這個方法中先需要知道key
會傳回什麼,從目前內部指標位置傳回元素鍵名。
所以程式碼會去執行if語句的判斷,根據上邊的所有判斷都不符合所以會執行這段程式碼$where[] = [$key, is_array($val) ? 'IN ' : '=', $val];
這段程式碼會判斷循環數組的value值是否為數組,如果為數組就是in,反之為=,由於value為1所以數組的第二個值為=。
那麼最終where的值就是下圖列印的資料。
#由於where不為空,程式碼執行流程會執行到下圖位置,最終在傳回本類實例。
find()執行流程
接著程式碼會還是執行本類別的find方法,找出單一記錄。
由於find中是沒有傳遞參數的,所以程式碼會執行到$this->parseOptions();
分析表達式(可用於查詢或寫入操作)
就目前寫的案例而言,這段看似很長的程式碼大家好好看看都可以看明白,最終依然是返回目前的所有參數。
#以下就是回傳的所以結果
真正的查詢資料是這塊程式碼$result = $this->connection->find($this);
,這段程式碼會執行到檔案thinkphp/library/think/db/Connection.php
從這塊程式碼可以看到當查詢一條資料時框架預設為加上了limit為1,至於為什麼這麼加你就需要查看一下sql優化方面的知識了。
在這裡就是關於sql語句的生成,程式碼自己好好看看就會明白,咔咔解析的只是執行流程和具體程式碼簡單的了解即可。
至於具體實作流程咔咔在後期如果有機會會單獨把每個方法進行深度解析,那時就是主要針對程式碼的解析。
最終傳回結果如下
以上就是關於Db在結合連接器,查詢器,產生器實作的資料庫查詢功能。
截止到這裡關於Db的場景就分析到這裡,接下來喀喀將會對Model進行簡單的分析。
#還是之前的案例,我們來用這個方法列印一下結果來看看是什麼。
看到上圖就知道是框架最終給生成的SQL語句,那麼接下來咔咔就會帶大家一起來探討一下,這個sql語句是如何產生的。
下圖為本次示範的案例,也就是喀喀爾下圖圈出來的地方。
從上圖圈出來的地方進行程式碼追蹤會到檔案thinkphp/library/think/Db. php
,並且會去執行本類別的__callStatic方法,這個方法就不在進行解釋了,在上文和之前也已經提到過多次了。
並且回傳結果也不去做宣告了,上文也提到了,這裡只需要知道最終回傳結果為回傳object(think\db\Query)
#根據上圖的傳回結果可以知道最終回去呼叫object(think\ db\Query)
這個類別的getLastSql
這個方法
根據這個方法可以知道是取得最近一次查詢的sql語句。
#這裡就會有點疑問了,關於屬性connection
到底是什麼,這裡正在進行簡單的簡析。
關於這種屬性的聲明一般都會在本類別的建構子或父類別的建構子中進行聲明,這也是在閱讀原始碼時的一個小技巧。
於是我們首先需要來到本類別的建構子來看一眼。
透過上圖可以得知,這裡使用了依賴注入的方式,所以Connection
就是一個對象,也是框架中所謂的連接器。
所以說這個Connection
物件就是下圖印出來的。
#根據上圖得知使用的類別檔案應該是think\db \connector\Mysql
那麼就會執行這個類別裡邊的getLastSql
方法。
但是來到這個類別執行你會發現這個類別裡邊根本是沒有這個方法。
根據上圖的繼承關係,我們就知道這個方法是在thinkphp/library/think/db /Connection.php
這個類別文件裡邊。
下圖即是這個方法執行過程,可以看到存在兩個參數,但是這兩個參數還是一頭霧水根本不知道是什麼。
#根據程式碼追蹤我們對上圖所出現的兩個參數先進行簡單的說明
$this->queryStr
目前SQL指令$this->bind
綁定參數追蹤$this->queryStr這個屬性值
##走到這裡估計有點蒙了吧!對於這個值有點確定不了了,指定不是靠列印可以取得到結果的。 當然還有另一個辦法就是進行debug來斷點偵錯。 但是既然喀喀帶大家看源碼呢!就不會用上邊的倆種方式,會直接從源碼中找到蛛絲馬跡。 根據喀喀爾上邊給提供的案例,執行的最後一步就是find方法,這個方法也是在thinkphp/library/think/db/Connection.php這個類別裡邊,尋找單條記錄。
那我們就在這個方法中進行一點點的尋找,這裡咔咔已經給大家圈好了,就是下圖咔咔圈其起來的地方。
根據上圖咔咔給的程式碼註釋,第一個參數就是產生的SQL語句,來繼續追蹤這個方法看一下,此時這個方法依然會在本類別thinkphp/library/think/db/Connection.php
這個檔案中實作query
方法。
在這個方法中一眼就可以看見對於這個queryStr
屬性的設置,是直接給這個屬性賦值,那麼也就是說這個屬性的值就是上一個SQL語句產生的SQL語句。
所以說這個getLastSql
取得的就是在這個語句之前執行的SQL語句,也只能取得出最近執行的那個SQL語句。
以上就是關於getLastSql
的實作原理,這裡要注意的就是關於SQL的生成,而這塊屬實有點複雜。
截止到這裡關於資料庫中Db類別的操作場景分析以及關於結合連接器,查詢器,生成器就到這裡結束了。
這裡喀喀爾主要是使用了兩個種案例來執行,第一種為原生案例,第二種為框架封裝的案例。
使用了這兩個種案例來對源碼進行了深度解析,但是在文檔還有很多的實現方法,其它的方法只需要根據咔咔給的提示然後一點點解析即可。
不需要對所有的方法都執行,不管任何方法走的都是上文分析的方法,也是很簡單。
最後在示範了一下關於使用getLastSql
來取得最後一次執行的SQL語句查詢,這裡的實作原理主要就是在Db類別操作資料庫時,不管是使用find方法還是select方法最終都會走向一個方法那就是query方法。
同樣在這個方法中存在一個屬性值queryStr
,也就是在這個時候將SQL語句賦值進去的,然後在使用getLastSql
這個方法使用queryStr和bind
屬性在對SQL進行拼接,最總回傳SQL語句。
堅持學習、堅持寫博、堅持分享是咔咔從業以來一直所秉持的信念。希望在偌大互聯網中咔咔的文章能帶給你一絲絲幫助。我是喀喀,下期見。
以上是ThinkPHP之Db類庫結合連接器、查詢器、sql生成器使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!