ThinkPHP5 閉包查詢

看了一下源碼(Query.php)之后,總結(jié)一下簸喂,所有的查詢執(zhí)行方法(select,find等),在傳入一個(gè)匿名函數(shù)進(jìn)行閉包查詢時(shí)燎潮,需要傳入一個(gè)參數(shù)(名字隨意),在源碼中喻鳄,該參數(shù)為當(dāng)前數(shù)據(jù)庫(kù)連接實(shí)例本身的引用(&this),即在匿名函數(shù)內(nèi)所有的條件操作(where,order等)确封,本質(zhì)上都是給本次查詢實(shí)例添加查詢條件除呵,與基本查詢的鏈?zhǔn)讲僮鳑]有本質(zhì)區(qū)別,好處是爪喘,在閉包內(nèi)進(jìn)行操作颜曾,可以創(chuàng)建一個(gè)封閉的作用域,一定程度上解決可能出現(xiàn)的變量沖突問題秉剑,關(guān)于如何將外部的查詢條件導(dǎo)入到閉包內(nèi)部泛豪,可以使用function()use(){},在use()中導(dǎo)入外部參數(shù)。

? ? ? ? 在閉包查詢的時(shí)候诡曙,至少要指定一次查詢表名臀叙,但不限位置,

可以:

\think\Db::select(function($query){

? ? $query->name('tableName')->where();

});

也可以:

\think\Db::name('tableName')->select(function($query){

? ? $query->where();

});

可以在閉包內(nèi)對(duì)不同實(shí)例進(jìn)行閉包查詢价卤,但請(qǐng)勿在閉包內(nèi)多次對(duì)同一實(shí)例嵌套使用閉包查詢劝萤,因?yàn)樵谠创a中,在處理完匿名函數(shù)之后荠雕,只是清空了查詢條件稳其,并沒有終止本次查詢,因此在對(duì)同一實(shí)例進(jìn)行嵌套閉包查詢時(shí)炸卑,在所有嵌套閉包中添加的查詢條件雖然都會(huì)生效既鞠,但是僅有最內(nèi)層閉包可以根據(jù)嵌套中添加的條件進(jìn)行查詢,在最內(nèi)層查詢結(jié)束之后盖文,將清空查詢條件($data = null)嘱蛋,并且不會(huì)終止查詢,因此會(huì)根據(jù)對(duì)應(yīng)方法(find,select等)的默認(rèn)條件五续,由內(nèi)至外洒敏,逐層進(jìn)行查詢,直到單個(gè)實(shí)例所有嵌套的閉包查詢完畢疙驾,其中凶伙,僅有最內(nèi)層查詢集合了嵌套查詢中所有的條件。


2017/07/04 14:59補(bǔ)充

? ? 看了一下混合查詢部分它碎,個(gè)人感覺這個(gè)TP5的閉包查詢就是一個(gè)比較晦澀的鏈?zhǔn)讲僮骱伲徊贿^把實(shí)例變成變成了一個(gè)參數(shù)的形式,除此之外就對(duì)這個(gè)參數(shù)進(jìn)行普通的鏈?zhǔn)讲僮骷纯砂飧兀琫mmmm…

? ? ? 仔細(xì)研究了一下where方法對(duì)閉包條件的處理傻挂,他是在Builder.php里面對(duì)閉包方法進(jìn)行處理的,思路和select方法的處理思路相同挖息,在地258行開始金拒,判斷是否閉包條件,如果是就去調(diào)用閉包套腹,并傳入一個(gè)query類實(shí)例作為操作載體绪抛,回環(huán)調(diào)用直到處理完所有嵌套閉包。

使用思路差不多电禀,單純和select的閉包一樣用就行了睦疫,只是TP在處理的時(shí)候有細(xì)節(jié)上的差異。


2017/07/04 20:01補(bǔ)充

? ? ? 為什么這樣的寫法無效鞭呕?

西湖

因?yàn)樵赒uery類的where方法中,where在針對(duì)閉包函數(shù)的處理方式并非像select這種方法一樣立刻對(duì)閉包進(jìn)行處理,而是把閉包扔進(jìn)$this->options['where']里面做為一個(gè)待處理的對(duì)象放在那里葫松,因此閉包內(nèi)容并不會(huì)立即執(zhí)行瓦糕,所以閉包內(nèi)的find()其實(shí)是沒用的,換句話說里面怎么嵌套查詢語句都沒用,必須要在最外層手動(dòng)調(diào)用一次查詢操作腋么,在調(diào)用到查詢方法的時(shí)候咕娄,才會(huì)去處理where閉包里面的內(nèi)容,生成sql語句(詳情見Builder.php)珊擂。


2017/07/04 21:36補(bǔ)充

? ? ? 在測(cè)試中發(fā)現(xiàn)如果在where()中使用閉包修改表名似乎是無效的圣勒,還是會(huì)根據(jù)初始的表名來查詢;而在select()之類的查詢方法中使用name()修改表名則有效摧扇,在代碼中發(fā)現(xiàn)如下兩段:

Query的select方法圣贸,$query使用當(dāng)前實(shí)例的引用


Builder處理where閉包的地方,$query使用當(dāng)前連接實(shí)例化的新對(duì)象

? ? ? 如果下面處理where閉包的$query非select的$query扛稽,那么又是如何將條件成功注入到查詢中去的呢吁峻?

談一下我的理解:

? ? ? 這里實(shí)例化一個(gè)新的Query類的作用,并不是和select那樣做一個(gè)怎么樣的處理在张,只是為了照顧到語法的便捷性用含,為了讓里面和select閉包一樣寫的方法能夠成功調(diào)用,如where帮匾,join等方法啄骇,本身就是存在于Query類中的,而非處理where閉包的Builder類中。

為什么不用this:

? ? 上面說了瘟斜,處理where閉包的(Builder)類和處理select閉包的(Query)類是兩個(gè)類缸夹,在Query類的select方法中,生成查詢sql的方法其實(shí)調(diào)用的是Builder類:


Query類的select操作中生成SQL的步驟哼转,這個(gè)select()并非我們?cè)诖a里寫的select()明未,注意咯

$this->builder正是繼承于Builder類的數(shù)據(jù)庫(kù)驅(qū)動(dòng)類Mysql:

繼承于Builder類的數(shù)據(jù)庫(kù)驅(qū)動(dòng)類

? ? ? 因此在處理where閉包的時(shí)候使用this,那么這個(gè)this并非Query類的實(shí)例,而是繼承于Builder的Mysql驅(qū)動(dòng)類的實(shí)例壹蔓,然而這個(gè)類里并沒有操作數(shù)據(jù)庫(kù)的方法(在Query類里面)趟妥,所以只能直接new一個(gè)新的Query類來處理where閉包里面的操作。

直接new一個(gè)Query類為什么還能查到正確的sql結(jié)果:

? ? ? 因?yàn)榈竭@里都是生成SQL查詢語句了佣蓉,返回的直接就是個(gè)拿去用的SQL字符串披摄,到底給誰用,不是在這里確定的勇凭,所以這個(gè)方法只要能夠正確的解析出where的閉包條件就算搞定收工疚膊,在SQL語句里面,查什么表也不是在where里面確定的說虾标,唯一不方便的寓盗,就是和select閉包相比,無法改變和設(shè)置查詢的表名,還是讓人有點(diǎn)糾結(jié)的說傀蚌。

為什么不把Query實(shí)例的的$this引用到Builder類作$query:

? ? ? 因?yàn)镼uery實(shí)例中基显,使用本身保存的Builder的實(shí)例,在調(diào)用時(shí)如同在一個(gè)類里面自己引用自己,然而PHP類實(shí)例不能自己引用自己善炫。好糾結(jié)的玩意......


2017/07/05 08:57補(bǔ)充

? ? ? ? 以上只是說明where閉包和select閉包的一點(diǎn)差異:select可以用name改表而where閉包不能撩幽。


2017/07/05 10:39補(bǔ)充

? ? ? union操作閉包,這個(gè)操作的閉包必須單獨(dú)設(shè)置一個(gè)name或table箩艺,這里根select和where都不一樣窜醉。處理這個(gè)閉包的地方和where一樣,在Builder類里面艺谆,也是實(shí)例化一個(gè)新的Query類來處理榨惰,和where生成SQL語句不同的是,where類生成的SQL語句只是查詢語句的where部分擂涛,這個(gè)是用Builder類的builderWhere方法(嵌套時(shí)回環(huán)調(diào)用)來生成的读串,而union在生成的查詢SQL中是一個(gè)子查詢,而子查詢是獨(dú)立與主查詢的撒妈,因此需要在每個(gè)union閉包中設(shè)置自己的name或table恢暖,在代碼中,雖然union閉包也是在Builder類里去處理的狰右,但是不是調(diào)用的Builder類的方法生成子查詢杰捂,而是調(diào)用的該閉包中Query實(shí)例的select(false)去生成的子查詢,union閉包需要查詢那張表棋蚌,必須在union閉包里寫出來嫁佳。在處理union閉包的時(shí)候,使用的是foreach循環(huán)谷暮,如果有多個(gè)union閉包蒿往,則每個(gè)閉包都需要寫name或table,因?yàn)槊看窝h(huán)中處理union閉包時(shí)都會(huì)創(chuàng)建一個(gè)新的Query實(shí)例來生成子查詢湿弦,每個(gè)union閉包之間沒有關(guān)系瓤漏。

Builder類生成union閉包SQL的地方

Query類生成SQL的方法

多個(gè)union閉包
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市颊埃,隨后出現(xiàn)的幾起案子蔬充,更是在濱河造成了極大的恐慌,老刑警劉巖班利,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饥漫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡罗标,警方通過查閱死者的電腦和手機(jī)庸队,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門积蜻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人彻消,你說我怎么就攤上這事浅侨。” “怎么了证膨?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)鼓黔。 經(jīng)常有香客問我央勒,道長(zhǎng),這世上最難降的妖魔是什么澳化? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任崔步,我火速辦了婚禮,結(jié)果婚禮上缎谷,老公的妹妹穿的比我還像新娘井濒。我一直安慰自己,他們只是感情好列林,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布瑞你。 她就那樣靜靜地躺著,像睡著了一般希痴。 火紅的嫁衣襯著肌膚如雪者甲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天砌创,我揣著相機(jī)與錄音虏缸,去河邊找鬼。 笑死嫩实,一個(gè)胖子當(dāng)著我的面吹牛刽辙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甲献,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宰缤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了竟纳?” 一聲冷哼從身側(cè)響起撵溃,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锥累,沒想到半個(gè)月后缘挑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桶略,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年语淘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诲宇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惶翻,死狀恐怖姑蓝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吕粗,我是刑警寧澤纺荧,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站颅筋,受9級(jí)特大地震影響宙暇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜议泵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一占贫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧先口,春花似錦型奥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至收夸,卻和暖如春坑匠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卧惜。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工厘灼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咽瓷。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓设凹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親茅姜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闪朱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容