基礎(chǔ): 1. 基礎(chǔ)概念 LAMP LAMP是基于Linux,Apache,MySQL和PHP的開(kāi)放資源網(wǎng)絡(luò)開(kāi)發(fā)平臺(tái)。這個(gè)術(shù)語(yǔ)來(lái)自歐洲,在那里這些程序常用來(lái)作為一種標(biāo)準(zhǔn)開(kāi)發(fā)環(huán)境。名字來(lái)源于每個(gè)程序的第一個(gè)字母。每個(gè)程序在所有權(quán)里都符合開(kāi)放源代碼標(biāo)準(zhǔn):Linux是開(kāi)放系統(tǒng);Apache是最通用的網(wǎng)絡(luò)服務(wù)器;MySQL是帶有基于網(wǎng)絡(luò)管理附加工具的關(guān)系數(shù)據(jù)庫(kù);PHP是流行的對(duì)象腳本語(yǔ)言,它包含了多數(shù)其它語(yǔ)言的優(yōu)秀特征來(lái)使得它的網(wǎng)絡(luò)開(kāi)發(fā)更加有效。開(kāi)發(fā)者在Windows操作系統(tǒng)下使用這些Linux環(huán)境里的工具稱為使用WAMP。 雖然這些開(kāi)放源代碼程序本身并不是專門設(shè)計(jì)成同另外幾個(gè)程序一起工作的,但由于它們都是影響較大的開(kāi)源軟件,擁有很多共同特點(diǎn),這就導(dǎo)致了這些組件經(jīng)常在一起使用。在過(guò)去的幾年里,這些組件的兼容性不斷完善,在一起的應(yīng)用情形變得更加普遍。并且它們?yōu)榱烁纳撇煌M件之間的協(xié)作,已經(jīng)創(chuàng)建了某些擴(kuò)展功能。目前,幾乎在所有的Linux發(fā)布版中都默認(rèn)包含了這些產(chǎn)品。Linux操作系統(tǒng)、Apache服務(wù)器、MySQL數(shù)據(jù)庫(kù)和Perl、PHP或者 Python語(yǔ)言,這些產(chǎn)品共同組成了一個(gè)強(qiáng)大的Web應(yīng)用程序平臺(tái)。 隨著開(kāi)源潮流的蓬勃發(fā)展,開(kāi)放源代碼的LAMP已經(jīng)與J2EE和.Net商業(yè)軟件形成三足鼎立之勢(shì),并且該軟件開(kāi)發(fā)的項(xiàng)目在軟件方面的投資成本較低,因此受到整個(gè)IT界的關(guān)注。從網(wǎng)站的流量上來(lái)說(shuō),70%以上的訪問(wèn)流量是LAMP來(lái)提供的,LAMP是最強(qiáng)大的網(wǎng)站解決方案. OOP 面向?qū)ο缶幊?#xff08;Object Oriented Programming,OOP,面向?qū)ο蟪绦蛟O(shè)計(jì))是一種計(jì)算機(jī)編程架構(gòu)。OOP 的一條基本原則是計(jì)算機(jī)程序是由單個(gè)能夠起到子程序作用的單元或?qū)ο蠼M合而成。OOP 達(dá)到了軟件工程的三個(gè)主要目標(biāo):重用性、靈活性和擴(kuò)展性。為了實(shí)現(xiàn)整體運(yùn)算,每個(gè)對(duì)象都能夠接收信息、處理數(shù)據(jù)和向其它對(duì)象發(fā)送信息。OOP 主要有以下的概念和組件:?組件 ?- 數(shù)據(jù)和功能一起在運(yùn)行著的計(jì)算機(jī)程序中形成的單元,組件在 OOP 計(jì)算機(jī)程序中是模塊和結(jié)構(gòu)化的基礎(chǔ)。?抽象性 ?- 程序有能力忽略正在處理中信息的某些方面,即對(duì)信息主要方面關(guān)注的能力。?封裝 ?- 也叫做信息封裝:確保組件不會(huì)以不可預(yù)期的方式改變其它組件的內(nèi)部狀態(tài);只有在那些提供了內(nèi)部狀態(tài)改變方法的組件中,才可以訪問(wèn)其內(nèi)部狀態(tài)。每類組件都提供了一個(gè)與其它組件聯(lián)系的接口,并規(guī)定了其它組件進(jìn)行調(diào)用的方法。?多態(tài)性 ?- 組件的引用和類集會(huì)涉及到其它許多不同類型的組件,而且引用組件所產(chǎn)生的結(jié)果得依據(jù)實(shí)際調(diào)用的類型。?繼承性 ?- 允許在現(xiàn)存的組件基礎(chǔ)上創(chuàng)建子類組件,這統(tǒng)一并增強(qiáng)了多態(tài)性和封裝性。典型地來(lái)說(shuō)就是用類來(lái)對(duì)組件進(jìn)行分組,而且還可以定義新類為現(xiàn)存的類的擴(kuò)展,這樣就可以將類組織成樹(shù)形或網(wǎng)狀結(jié)構(gòu),這體現(xiàn)了動(dòng)作的通用性。? 由于抽象性、封裝性、重用性以及便于使用等方面的原因,以組件為基礎(chǔ)的編程在腳本語(yǔ)言中已經(jīng)變得特別流行。 MVC MVC是一個(gè)設(shè)計(jì)模式,它強(qiáng)制性的使應(yīng)用程序的輸入、處理和輸出分開(kāi)。使用MVC應(yīng)用程序被分成三個(gè)核心部件:模型(M)、視圖(V)、控制器(C),它們各自處理自己的任務(wù)。?視圖 : 視圖是用戶看到并與之交互的界面。對(duì)老式的Web應(yīng)用程序來(lái)說(shuō),視圖就是由HTML元素組成的界面,在新式的Web應(yīng)用程序中,HTML依舊在視圖中扮演著重要的角色,但一些新的技術(shù)已層出不窮,它們包括Adobe Flash和象XHTML,XML/XSL,WML等一些標(biāo)識(shí)語(yǔ)言和Web services。如何處理應(yīng)用程序的界面變得越來(lái)越有挑戰(zhàn)性。MVC一個(gè)大的好處是它能為你的應(yīng)用程序處理很多不同的視圖。在視圖中其實(shí)沒(méi)有真正的處理發(fā)生,不管這些數(shù)據(jù)是聯(lián)機(jī)存儲(chǔ)的還是一個(gè)雇員列表,作為視圖來(lái)講,它只是作為一種輸出數(shù)據(jù)并允許用戶操縱的方式。?模型 : 模型表示企業(yè)數(shù)據(jù)和業(yè)務(wù)規(guī)則。在MVC的三個(gè)部件中,模型擁有最多的處理任務(wù)。例如它可能用象EJBs和ColdFusion Components這樣的構(gòu)件對(duì)象來(lái)處理數(shù)據(jù)庫(kù)。被模型返回的數(shù)據(jù)是中立的,就是說(shuō)模型與數(shù)據(jù)格式無(wú)關(guān),這樣一個(gè)模型能為多個(gè)視圖提供數(shù)據(jù)。由于應(yīng)用于模型的代碼只需寫一次就可以被多個(gè)視圖重用,所以減少了代碼的重復(fù)性。?控制器 : 控制器接受用戶的輸入并調(diào)用模型和視圖去完成用戶的需求。所以當(dāng)單擊Web頁(yè)面中的超鏈接和發(fā)送HTML表單時(shí),控制器本身不輸出任何東西和做任何處理。它只是接收請(qǐng)求并決定調(diào)用哪個(gè)模型構(gòu)件去處理請(qǐng)求,然后確定用哪個(gè)視圖來(lái)顯示模型處理返回的數(shù)據(jù)。? 現(xiàn)在我們總結(jié)MVC的處理過(guò)程,首先控制器接收用戶的請(qǐng)求,并決定應(yīng)該調(diào)用哪個(gè)模型來(lái)進(jìn)行處理,然后模型用業(yè)務(wù)邏輯來(lái)處理用戶的請(qǐng)求并返回?cái)?shù)據(jù),最后控制器用相應(yīng)的視圖格式化模型返回的數(shù)據(jù),并通過(guò)表示層呈現(xiàn)給用戶。 ORM 對(duì)象-關(guān)系映射(Object/Relation Mapping,簡(jiǎn)稱ORM),是隨著面向?qū)ο蟮能浖_(kāi)發(fā)方法發(fā)展而產(chǎn)生的。面向?qū)ο蟮拈_(kāi)發(fā)方法是當(dāng)今企業(yè)級(jí)應(yīng)用開(kāi)發(fā)環(huán)境中的主流開(kāi)發(fā)方法,關(guān)系數(shù)據(jù)庫(kù)是企業(yè)級(jí)應(yīng)用環(huán)境中永久存放數(shù)據(jù)的主流數(shù)據(jù)存儲(chǔ)系統(tǒng)。對(duì)象和關(guān)系數(shù)據(jù)是業(yè)務(wù)實(shí)體的兩種表現(xiàn)形式,業(yè)務(wù)實(shí)體在內(nèi)存中表現(xiàn)為對(duì)象,在數(shù)據(jù)庫(kù)中表現(xiàn)為關(guān)系數(shù)據(jù)。內(nèi)存中的對(duì)象之間存在關(guān)聯(lián)和繼承關(guān)系,而在數(shù)據(jù)庫(kù)中,關(guān)系數(shù)據(jù)無(wú)法直接表達(dá)多對(duì)多關(guān)聯(lián)和繼承關(guān)系。因此,對(duì)象-關(guān)系映射(ORM)系統(tǒng)一般以中間件的形式存在,主要實(shí)現(xiàn)程序?qū)ο蟮疥P(guān)系數(shù)據(jù)庫(kù)數(shù)據(jù)的映射。 面向?qū)ο笫菑能浖こ袒驹瓌t(如耦合、聚合、封裝)的基礎(chǔ)上發(fā)展起來(lái)的,而關(guān)系數(shù)據(jù)庫(kù)則是從數(shù)學(xué)理論發(fā)展而來(lái)的,兩套理論存在顯著的區(qū)別。為了解決這個(gè)不匹配的現(xiàn)象,對(duì)象關(guān)系映射技術(shù)應(yīng)運(yùn)而生。 AOP AOP(Aspect-Oriented Programming,面向方面編程),可以說(shuō)是OOP(Object-Oriented Programing,面向?qū)ο缶幊?#xff09;的補(bǔ)充和完善。OOP引入封裝、繼承和多態(tài)性等概念來(lái)建立一種對(duì)象層次結(jié)構(gòu),用以模擬公共行為的一個(gè)集合。當(dāng)我們需要為分散的對(duì)象引入公共行為的時(shí)候,OOP則顯得無(wú)能為力。也就是說(shuō),OOP允許你定義從上到下的關(guān)系,但并不適合定義從左到右的關(guān)系。例如日志功能。日志代碼往往水平地散布在所有對(duì)象層次中,而與它所散布到的對(duì)象的核心功能毫無(wú)關(guān)系。對(duì)于其他類型的代碼,如安全性、異常處理和透明的持續(xù)性也是如此。這種散布在各處的無(wú)關(guān)的代碼被稱為橫切(cross-cutting)代碼,在OOP設(shè)計(jì)中,它導(dǎo)致了大量代碼的重復(fù),而不利于各個(gè)模塊的重用。而AOP技術(shù)則恰恰相反,它利用一種稱為“橫切”的技術(shù),剖解開(kāi)封裝的對(duì)象內(nèi)部,并將那些影響了多個(gè)類的公共行為封裝到一個(gè)可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡(jiǎn)單地說(shuō),就是將那些與業(yè)務(wù)無(wú)關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來(lái),便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來(lái)的可操作性和可維護(hù)性。AOP代表的是一個(gè)橫向的關(guān)系,如果說(shuō)“對(duì)象”是一個(gè)空心的圓柱體,其中封裝的是對(duì)象的屬性和行為;那么面向方面編程的方法,就仿佛一把利刃,將這些空心圓柱體剖開(kāi),以獲得其內(nèi)部的消息。而剖開(kāi)的切面,也就是所謂的“方面”了。然后它又以巧奪天功的妙手將這些剖開(kāi)的切面復(fù)原,不留痕跡。 使用“橫切”技術(shù),AOP把軟件系統(tǒng)分為兩個(gè)部分:核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)。業(yè)務(wù)處理的主要流程是核心關(guān)注點(diǎn),與之關(guān)系不大的部分是橫切關(guān)注點(diǎn)。橫切關(guān)注點(diǎn)的一個(gè)特點(diǎn)是,他們經(jīng)常發(fā)生在核心關(guān)注點(diǎn)的多處,而各處都基本相似。比如權(quán)限認(rèn)證、日志、事務(wù)處理。Aop 的作用在于分離系統(tǒng)中的各種關(guān)注點(diǎn),將核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)分離開(kāi)來(lái)。正如Avanade公司的高級(jí)方案構(gòu)架師Adam Magee所說(shuō),AOP的核心思想就是“將應(yīng)用程序中的商業(yè)邏輯同對(duì)其提供支持的通用服務(wù)進(jìn)行分離。” CURD CURD是一個(gè)數(shù)據(jù)庫(kù)技術(shù)中的縮寫詞,一般的項(xiàng)目開(kāi)發(fā)的各種參數(shù)的基本功能都是CURD。它代表創(chuàng)建(Create)、更新(Update)、讀取(Read)和刪除(Delete)操作。CURD 定義了用于處理數(shù)據(jù)的基本原子操作。之所以將CURD 提升到一個(gè)技術(shù)難題的高度是因?yàn)橥瓿梢粋€(gè)涉及在多個(gè)數(shù)據(jù)庫(kù)系統(tǒng)中進(jìn)行CURD操作的匯總相關(guān)的活動(dòng),其性能可能會(huì)隨數(shù)據(jù)關(guān)系的變化而有非常大的差異。 CURD在具體的應(yīng)用中并非一定使用create、update 、read和delete字樣的方法,但是他們完成的功能是一致的。例如,ThinkPHP就是使用add、save、select和delete方法表示模型的CURD操作。 ActiveRecord Active Record(中文名:活動(dòng)記錄)是一種領(lǐng)域模型模式,特點(diǎn)是一個(gè)模型類對(duì)應(yīng)關(guān)系型數(shù)據(jù)庫(kù)中的一個(gè)表,而模型類的一個(gè)實(shí)例對(duì)應(yīng)表中的一行記錄。Active Record 和 Row Gateway (行記錄入口)十分相似,但前者是領(lǐng)域模型,后者是一種數(shù)據(jù)源模式。關(guān)系型數(shù)據(jù)庫(kù)往往通過(guò)外鍵來(lái)表述實(shí)體關(guān)系,Active Record 在數(shù)據(jù)源層面上也將這種關(guān)系映射為對(duì)象的關(guān)聯(lián)和聚集。 Active Record 適合非常簡(jiǎn)單的領(lǐng)域需求,尤其在領(lǐng)域模型和數(shù)據(jù)庫(kù)模型十分相似的情況下。如果遇到更加復(fù)雜的領(lǐng)域模型結(jié)構(gòu)(例如用到繼承、策略的領(lǐng)域模型),往往需要使用分離數(shù)據(jù)源的領(lǐng)域模型,結(jié)合 Data Mapper (數(shù)據(jù)映射器)使用。 Active Record 驅(qū)動(dòng)框架一般兼有 ORM 框架的功能,但 Active Record 不是簡(jiǎn)單的 ORM,正如和 Row Gateway 的區(qū)別。由Rails最早提出,遵循標(biāo)準(zhǔn)的ORM模型:表映射到記錄,記錄映射到對(duì)象,字段映射到對(duì)象屬性。配合遵循的命名和配置慣例,能夠很大程度的快速實(shí)現(xiàn)模型的操作,而且簡(jiǎn)潔易懂。 單一入口 單一入口通常是指一個(gè)項(xiàng)目或者應(yīng)用具有一個(gè)統(tǒng)一(但并不一定是唯一)的入口文件,也就是說(shuō)項(xiàng)目的所有功能操作都是通過(guò)這個(gè)入口文件進(jìn)行的,并且往往入口文件是第一步被執(zhí)行的。 單一入口的好處是項(xiàng)目整體比較規(guī)范,因?yàn)橥粋€(gè)入口,往往其不同操作之間具有相同的規(guī)則。另外一個(gè)方面就是單一入口帶來(lái)的好處是控制較為靈活,因?yàn)閿r截方便了,類似如一些權(quán)限控制、用戶登錄方面的判斷和操作可以統(tǒng)一處理了。 或者有些人會(huì)擔(dān)心所有網(wǎng)站都通過(guò)一個(gè)入口文件進(jìn)行訪問(wèn),是否會(huì)造成太大的壓力,其實(shí)這是杞人憂天的想法。 2. 目錄結(jié)構(gòu) 目錄/文件 說(shuō)明 ThinkPHP.php 框架入口文件 Common 框架公共文件目錄 Conf 框架配置文件目錄 Lang 框架系統(tǒng)語(yǔ)言目錄 Lib 系統(tǒng)核心基類庫(kù)目錄 Tpl 系統(tǒng)模板目錄 Extend 框架擴(kuò)展目錄(關(guān)于擴(kuò)展目錄的詳細(xì)信息請(qǐng)參考后面的擴(kuò)展章節(jié))
注意:如果你下載的是核心版本,有可能Extend目錄是空的,因?yàn)門hinkPHP本身不依賴任何擴(kuò)展。 3. 命名規(guī)范 使用ThinkPHP開(kāi)發(fā)的過(guò)程中應(yīng)該盡量遵循下列命名規(guī)范:
類文件都是以.class.php為后綴(這里是指的ThinkPHP內(nèi)部使用的類庫(kù)文件,不代表外部加載的類庫(kù)文件),使用駝峰法命名,并且首字母大寫,例如DbMysql.class.php; 確保文件的命名和調(diào)用大小寫一致,是由于在類Unix系統(tǒng)上面,對(duì)大小寫是敏感的(而ThinkPHP在調(diào)試模式下面,即使在Windows平臺(tái)也會(huì)嚴(yán)格檢查大小寫); 類名和文件名一致(包括上面說(shuō)的大小寫一致),例如 UserAction類的文件命名是UserAction.class.php, InfoModel類的文件名是InfoModel.class.php, 并且不同的類庫(kù)的類命名有一定的規(guī)范; 函數(shù)、配置文件等其他類庫(kù)文件之外的一般是以.php為后綴(第三方引入的不做要求); 函數(shù)的命名使用小寫字母和下劃線的方式,例如 get_client_ip; 方法的命名使用駝峰法,并且首字母小寫或者使用下劃線“_”,例如 getUserName,_parseType,通常下劃線開(kāi)頭的方法屬于私有方法; 屬性的命名使用駝峰法,并且首字母小寫或者使用下劃線“_”,例如 tableName、_instance,通常下劃線開(kāi)頭的屬性屬于私有屬性; 以雙下劃線“__”打頭的函數(shù)或方法作為魔法方法,例如 __call 和 __autoload; 常量以大寫字母和下劃線命名,例如 HAS_ONE和 MANY_TO_MANY; 配置參數(shù)以大寫字母和下劃線命名,例如HTML_CACHE_ON; 語(yǔ)言變量以大寫字母和下劃線命名,例如MY_LANG,以下劃線打頭的語(yǔ)言變量通常用于系統(tǒng)語(yǔ)言變量,例如 _CLASS_NOT_EXIST_; 對(duì)變量的命名沒(méi)有強(qiáng)制的規(guī)范,可以根據(jù)團(tuán)隊(duì)規(guī)范來(lái)進(jìn)行; ThinkPHP的模板文件默認(rèn)是以.html 為后綴(可以通過(guò)配置修改); 數(shù)據(jù)表和字段采用小寫加下劃線方式命名,并注意字段名不要以下劃線開(kāi)頭,例如 think_user 表和 user_name字段,類似 _username 這樣的數(shù)據(jù)表字段可能會(huì)被過(guò)濾。 在ThinkPHP里面,有一個(gè)函數(shù)命名的特例,就是單字母大寫函數(shù),這類函數(shù)通常是某些操作的快捷定義,或者有特殊的作用。例如,ADSL方法等等。 另外有一點(diǎn)非常關(guān)鍵,ThinkPHP默認(rèn)全部使用UTF-8編碼,所以請(qǐng)確保你的程序文件采用UTF-8編碼格式保存,并且去掉BOM信息頭(去掉BOM頭信息有很多方式,不同的編輯器都有設(shè)置方法,也可以用工具進(jìn)行統(tǒng)一檢測(cè)和處理),否則可能導(dǎo)致很多意想不到的問(wèn)題。 4. CBD架構(gòu) ThinkPHP3.0版本引入了全新的CBD(核心Core+行為Behavior+驅(qū)動(dòng)Driver)架構(gòu)模式,因?yàn)閺牡讓娱_(kāi)始,框架就采用核心+行為+驅(qū)動(dòng)的架構(gòu)體系,核心保留了最關(guān)鍵的部分,并在重要位置設(shè)置了標(biāo)簽用以標(biāo)記,其他功能都采用行為擴(kuò)展和驅(qū)動(dòng)的方式組合,開(kāi)發(fā)人員可以根據(jù)自己的需要,對(duì)某個(gè)標(biāo)簽位置進(jìn)行行為擴(kuò)展或者替換,就可以方便的定制框架底層,也可以在應(yīng)用層添加自己的標(biāo)簽位置和添加應(yīng)用行。而標(biāo)簽位置類似于AOP概念中的“切面”,行為都是圍繞這個(gè)“切面”來(lái)進(jìn)行編程,如果把系統(tǒng)內(nèi)置的核心擴(kuò)展看成是一種標(biāo)準(zhǔn)模式的話,那么用戶可以把這一切的行為定制打包成一個(gè)新的模式,所以在ThinkPHP里面,稱之為模式擴(kuò)展,事實(shí)上,模式擴(kuò)展不僅僅可以替換和增加行為,還可以對(duì)底層的MVC進(jìn)行替換和修改,以達(dá)到量身定制的目的。利用這一新的特性,開(kāi)發(fā)人員可以方便地通過(guò)模式擴(kuò)展為自己量身定制一套屬于自己或者企業(yè)的開(kāi)發(fā)框架,新版的模式擴(kuò)展是框架擴(kuò)展的集大成者,開(kāi)創(chuàng)了新的里程碑,這正是新版的真正魅力所在。
5. 開(kāi)發(fā)流程 使用ThinkPHP創(chuàng)建應(yīng)用的一般開(kāi)發(fā)流程是:
系統(tǒng)設(shè)計(jì)、創(chuàng)建數(shù)據(jù)庫(kù)和數(shù)據(jù)表;(可選) 項(xiàng)目命名并創(chuàng)建項(xiàng)目入口文件,開(kāi)啟調(diào)試模式; 完成項(xiàng)目配置; 創(chuàng)建項(xiàng)目函數(shù)庫(kù);(可選) 開(kāi)發(fā)項(xiàng)目需要的擴(kuò)展(模式、驅(qū)動(dòng)、標(biāo)簽庫(kù)等);(可選) 創(chuàng)建控制器類; 創(chuàng)建模型類;(可選) 創(chuàng)建模板文件; 運(yùn)行和調(diào)試、分析日志; 開(kāi)發(fā)和設(shè)置緩存功能;(可選) 添加路由支持;(可選) 安全檢查;(可選 ) 部署到生產(chǎn)環(huán)境。 6. 入口文件 ThinkPHP采用單一入口模式進(jìn)行項(xiàng)目部署和訪問(wèn),無(wú)論完成什么功能,一個(gè)項(xiàng)目都有一個(gè)統(tǒng)一(但不一定是唯一)的入口。應(yīng)該說(shuō),所有項(xiàng)目都是從入口文件開(kāi)始的,并且所有的項(xiàng)目的入口文件是類似的,入口文件中主要包括:
定義框架路徑、項(xiàng)目路徑和項(xiàng)目名稱(可選) 定義調(diào)試模式和運(yùn)行模式的相關(guān)常量(可選) 載入框架入口文件(必須) 7. 項(xiàng)目目錄 生成的項(xiàng)目目錄結(jié)構(gòu)和系統(tǒng)目錄類似,包括:
目錄說(shuō)明 Common 項(xiàng)目公共文件目錄,一般放置項(xiàng)目的公共函數(shù) Conf 項(xiàng)目配置目錄,項(xiàng)目所有的配置文件都放在這里 Lang 項(xiàng)目語(yǔ)言包目錄(可選?如果不需要多語(yǔ)言支持?可刪除) Lib 項(xiàng)目類庫(kù)目錄,通常包括Action和Model子目錄 Tpl 項(xiàng)目模板目錄,支持模板主題 Runtime 項(xiàng)目運(yùn)行時(shí)目錄,包括Cache(模板緩存)、Temp(數(shù)據(jù)緩存)、Data(數(shù)據(jù)目錄)和Logs(日志文件)子目錄,如果存在分組的話,則首先是分組目錄。
如果需要把index.php 移動(dòng)到App目錄的外面,只需要在入口文件中增加項(xiàng)目名稱和項(xiàng)目路徑定義。
<?php ????//定義項(xiàng)目名稱 ????define('APP_NAME',?'App'); ????//定義項(xiàng)目路徑 ????define('APP_PATH',?'./App/'); ????//加載框架入文件 ????require?'./App/ThinkPHP/ThinkPHP.php'; APP_NAME ?是指項(xiàng)目名稱,注意APP_NAME 不要隨意設(shè)置,通常是項(xiàng)目的目錄名稱,如果你的項(xiàng)目是直接部署在Web根目錄下面的話,那么需要設(shè)置APP_NAME 為空。
APP_PATH ?是指項(xiàng)目路徑(必須以“/”結(jié)束),項(xiàng)目路徑是指項(xiàng)目的Common、Lib目錄所在的位置,而不是項(xiàng)目入口文件所在的位置。
注意:在類Unix或者Linux環(huán)境下面Runtime目錄需要可寫權(quán)限。
8. 部署目錄 目錄/文件說(shuō)明 ThinkPHP 系統(tǒng)目錄(下面的目錄結(jié)構(gòu)同上面的系統(tǒng)目錄) Public 網(wǎng)站公共資源目錄(存放網(wǎng)站的Css、Js和圖片等資源) Uploads 網(wǎng)站上傳目錄(用戶上傳的統(tǒng)一目錄) Home 項(xiàng)目目錄(下面的目錄結(jié)構(gòu)同上面的應(yīng)用目錄) Admin 后臺(tái)管理項(xiàng)目目錄 …… 更多的項(xiàng)目目錄 index.php 項(xiàng)目Home的入口文件 admin.php 項(xiàng)目Admin的入口文件 …… 更多的項(xiàng)目入口文件
項(xiàng)目的模板文件還是放到項(xiàng)目的Tpl目錄下面,只是將外部調(diào)用的資源文件, 包括圖片 JS 和CSS統(tǒng)一放到網(wǎng)站的公共目錄Public下面,分Images、Js和Css子目錄存放,如果有可能的話,甚至也可以把這些資源文件單獨(dú)放一個(gè)外部的服務(wù)器遠(yuǎn)程調(diào)用,并進(jìn)行優(yōu)化。
事實(shí)上,系統(tǒng)目錄和項(xiàng)目目錄可以放到非WEB訪問(wèn)目錄下面,網(wǎng)站目錄下面只需要放置Public公共目錄和入口文件,從而提高網(wǎng)站的安全性。
?
如果希望自己設(shè)置目錄,可以在入口文件里面更改RUNTIME_PATH常量進(jìn)行更改,例如:
define('RUNTIME_PATH','./App/temp/'); 注意RUNTIME_PATH目錄必須設(shè)置為可寫權(quán)限。
除了自定義編譯緩存目錄之外,還支持自定義編譯緩存文件名,例如:
define('RUNTIME_FILE','./App/temp/runtime_cache.php'); ThinkPHP框架中所有配置文件的定義格式均采用返回PHP數(shù)組的方式,格式為:
//項(xiàng)目配置文件 ?return?array( ????'DEFAULT_MODULE'?????=>?'Index',?//默認(rèn)模塊 ????'URL_MODEL'??????????=>?'2',?//URL模式 ????'SESSION_AUTO_START'?=>?true,?//是否開(kāi)啟session ????//更多配置參數(shù) ????//... ?); 配置參數(shù)不區(qū)分大小寫(因?yàn)闊o(wú)論大小寫定義都會(huì)轉(zhuǎn)換成小寫) 還可以在配置文件中可以使用二維數(shù)組來(lái)配置更多的信息,例如:
//項(xiàng)目配置文件 ?return?array( ????'DEFAULT_MODULE'?????=>?'Index',?//默認(rèn)模塊 ????'URL_MODEL'??????????=>?'2',?//URL模式 ????'SESSION_AUTO_START'?=>?true,?//是否開(kāi)啟session ????'USER_CONFIG'????????=>?array( ????????'USER_AUTH'?=>?true, ????????'USER_TYPE'?=>?2, ????), ????//更多配置參數(shù) ????//... ?); 需要注意的是,二級(jí)參數(shù)配置區(qū)分大小寫,也就說(shuō)讀取確保和定義一致。
9. 慣例配置和項(xiàng)目配置,調(diào)試配置 慣例重于配置是系統(tǒng)遵循的一個(gè)重要思想,系統(tǒng)內(nèi)置有一個(gè)慣例配置文件(位于系統(tǒng)目錄下面的Conf\convention.php),按照大多數(shù)的使用對(duì)常用參數(shù)進(jìn)行了默認(rèn)配置。 項(xiàng)目配置文件是最常用的配置文件,項(xiàng)目配置文件位于項(xiàng)目的配置文件目錄Conf下面,文件名是config.php。
在項(xiàng)目配置文件里面除了添加內(nèi)置的參數(shù)配置外,還可以額外添加項(xiàng)目需要的配置參數(shù)。 如果沒(méi)有配置應(yīng)用狀態(tài),系統(tǒng)默認(rèn)則默認(rèn)為debug狀態(tài),也就是說(shuō)默認(rèn)的配置參數(shù)是:
'APP_STATUS'?=>?'debug',?//應(yīng)用調(diào)試模式狀態(tài) debug.php配置文件只需要配置和項(xiàng)目配置文件以及系統(tǒng)調(diào)試配置文件不同的參數(shù)或者新增的參數(shù)。
如果想在調(diào)試模式下面增加應(yīng)用狀態(tài),例如測(cè)試狀態(tài),則可以在項(xiàng)目配置文件中改變?cè)O(shè)置如下:
'APP_STATUS'?=>?'test',?//應(yīng)用調(diào)試模式狀態(tài) 由于調(diào)試模式?jīng)]有任何緩存,因此涉及到較多的文件IO操作和模板實(shí)時(shí)編譯,所以在開(kāi)啟調(diào)試模式的情況下,性能會(huì)有一定的下降,但不會(huì)影響部署模式的性能。 注意:一旦關(guān)閉調(diào)試模式,項(xiàng)目的調(diào)試配置文件即刻失效。 10. 分組配置和讀取配置,動(dòng)態(tài)配置 如果啟用了模塊分組,則可以在對(duì)每個(gè)分組單獨(dú)定義配置文件,分組配置文件位于:
項(xiàng)目配置目錄/分組名稱/config.php
可以通過(guò)如下配置啟用分組:
'APP_GROUP_LIST'?=>?'Home,Admin',?//項(xiàng)目分組設(shè)定 ?'DEFAULT_GROUP'??=>?'Home',?//默認(rèn)分組 現(xiàn)在定義了Home和Admin兩個(gè)分組,則我們可以定義分組配置文件如下:
Conf/Home/config.php
Conf/Admin/config.php
每個(gè)分組的配置文件僅在當(dāng)前分組有效,分組配置的定義格式和項(xiàng)目配置是一樣的。
注意:分組名稱區(qū)分大小寫,必須和定義的分組名一致。 定義了配置文件之后,可以使用系統(tǒng)提供的C方法(如果覺(jué)得比較奇怪的話,可以借助Config單詞來(lái)幫助記憶)來(lái)讀取已有的配置:
C('參數(shù)名稱')//獲取已經(jīng)設(shè)置的參數(shù)值 例如,C('APP_STATUS') 可以讀取到系統(tǒng)的調(diào)試模式的設(shè)置值,如果APP_STATUS尚未存在設(shè)置,則返回NULL。 C方法同樣可以用于讀取二維配置:
C('USER_CONFIG.USER_TYPE')//獲取用戶配置中的用戶類型設(shè)置 因?yàn)榕渲脜?shù)是全局有效的,因此C方法可以在任何地方讀取任何配置,哪怕某個(gè)設(shè)置參數(shù)已經(jīng)生效過(guò)期了。 在具體的Action方法里面,我們?nèi)匀豢梢詫?duì)某些參數(shù)進(jìn)行動(dòng)態(tài)配置,主要是指那些還沒(méi)有被使用的參數(shù)。?
設(shè)置新的值:
C('參數(shù)名稱','新的參數(shù)值'); 例如,我們需要?jiǎng)討B(tài)改變數(shù)據(jù)緩存的有效期的話,可以使用
C('DATA_CACHE_TIME','60'); 也可以支持二維數(shù)組的讀取和設(shè)置,使用點(diǎn)語(yǔ)法進(jìn)行操作,如下:
獲取已經(jīng)設(shè)置的參數(shù)值:
C('USER_CONFIG.USER_TYPE'); 設(shè)置新的值:
C('USER_CONFIG.USER_TYPE','1'); 3.1版本開(kāi)始,C函數(shù)支持配置保存功能,僅對(duì)批量設(shè)置有效,使用方法:
C($array,'name'); 其中array是一個(gè)數(shù)組變量,會(huì)把批量設(shè)置后的配置參數(shù)列表保存到name標(biāo)識(shí)的緩存數(shù)據(jù)中
獲取緩存的設(shè)置列表數(shù)據(jù) 可以用
C('','name');?//或者C(null,'name'); 會(huì)讀取name標(biāo)識(shí)的緩存配置數(shù)據(jù)到當(dāng)前配置數(shù)據(jù)(合并)。
11. 擴(kuò)展配置 項(xiàng)目配置文件在部署模式的時(shí)候會(huì)納入編譯緩存,也就是說(shuō)編譯后再修改項(xiàng)目配置文件就不會(huì)立刻生效,需要?jiǎng)h除編譯緩存后才能生效。擴(kuò)展配置文件則不受此限制影響,即使在部署模式下面,修改配置后可以實(shí)時(shí)生效,并且配置格式和項(xiàng)目配置一樣。
設(shè)置擴(kuò)展配置的方式如下(多個(gè)文件用逗號(hào)分隔):
'LOAD_EXT_CONFIG'?=>?'user,db',?//?加載擴(kuò)展配置文件 項(xiàng)目設(shè)置了加載擴(kuò)展配置文件user.php 和db.php分別用于用戶配置和數(shù)據(jù)庫(kù)配置,那么會(huì)自動(dòng)加載項(xiàng)目配置目錄下面的配置文件Conf/user.php和Conf/db.php。 如果希望采用二級(jí)配置方式,可以設(shè)置如下:
'LOAD_EXT_CONFIG'?=>?array( ????'USER'?=>?'user',?//用戶配置 ????'DB'???=>?'db',?//數(shù)據(jù)庫(kù)配置 ?),?//加載擴(kuò)展配置文件 同樣的user.php 配置文件內(nèi)容,但最終獲取用戶參數(shù)的方式就變成了:
C('USER.USER_AUTH_ID'); 這種方式可以避免大項(xiàng)目情況中的參數(shù)沖突問(wèn)題。 下面的一些配置文件已經(jīng)被系統(tǒng)使用,請(qǐng)不要作為自定義的擴(kuò)展配置重新定義:
文件名說(shuō)明 config.php 項(xiàng)目配置文件 tags.php 項(xiàng)目行為配置文件 alias.php 項(xiàng)目別名定義文件 debug.php 項(xiàng)目調(diào)試模式配置文件(以及項(xiàng)目設(shè)置的APP_STATUS對(duì)應(yīng)的配置文件) core.php 項(xiàng)目追加的核心編譯列表文件(不會(huì)覆蓋核心編譯列表)
12. 函數(shù)庫(kù) ThinkPHP中的函數(shù)庫(kù)可以分為系統(tǒng)函數(shù)庫(kù)和項(xiàng)目函數(shù)庫(kù)。
系統(tǒng)函數(shù)庫(kù) 庫(kù)系統(tǒng)函數(shù)庫(kù)位于系統(tǒng)的Common目錄下面,有三個(gè)文件:
common.php是全局必須加載的基礎(chǔ)函數(shù)庫(kù),在任何時(shí)候都可以直接調(diào)用;
functions.php是框架標(biāo)準(zhǔn)模式的公共函數(shù)庫(kù),其他模式可以替換加載自己的公共函數(shù)庫(kù)或者對(duì)公共函數(shù)庫(kù)中的函數(shù)進(jìn)行重新定義;
runtime.php是框架運(yùn)行時(shí)文件,僅在調(diào)試模式或者編譯過(guò)程才會(huì)被加載,因此其中的方法在項(xiàng)目中不能直接調(diào)用;
項(xiàng)目函數(shù)庫(kù) 庫(kù)項(xiàng)目函數(shù)庫(kù)通常位于項(xiàng)目的Common目錄下面,文件名為common.php,該文件會(huì)在執(zhí)行過(guò)程中自動(dòng)加載,并且合并到項(xiàng)目編譯統(tǒng)一緩存,如果使用了分組部署方式,并且該目錄下存在"分組名稱/function.php"文件,也會(huì)根據(jù)當(dāng)前分組執(zhí)行時(shí)對(duì)應(yīng)進(jìn)行自動(dòng)加載,因此項(xiàng)目函數(shù)庫(kù)的所有函數(shù)也都可以無(wú)需手動(dòng)載入而直接使用。
如果項(xiàng)目配置中使用了動(dòng)態(tài)函數(shù)加載配置的話,項(xiàng)目Common目錄下面可能會(huì)存在更多的函數(shù)文件,動(dòng)態(tài)加載的函數(shù)文件不會(huì)納入編譯緩存。
在特殊的情況下,模式可以改變自動(dòng)加載的項(xiàng)目函數(shù)庫(kù)的位置或者名稱。
擴(kuò)展函數(shù)庫(kù) 庫(kù)我們可以在項(xiàng)目公共目錄下面定義擴(kuò)展函數(shù)庫(kù),方便需要的時(shí)候加載和調(diào)用。擴(kuò)展函數(shù)庫(kù)的函數(shù)定義規(guī)范和項(xiàng)目函數(shù)庫(kù)一致,只是函數(shù)庫(kù)文件名可以隨意命名,一般來(lái)說(shuō),擴(kuò)展函數(shù)庫(kù)并不會(huì)自動(dòng)加載,除非你設(shè)置了動(dòng)態(tài)載入。
函數(shù)加載 系統(tǒng)函數(shù)庫(kù)和項(xiàng)目函數(shù)庫(kù)中的函數(shù)無(wú)需加載就可以直接調(diào)用,對(duì)于項(xiàng)目的擴(kuò)展函數(shù)庫(kù),可以采用下面兩種方式調(diào)用:
動(dòng)態(tài)載入
我們可以在項(xiàng)目配置文件中定義LOAD_EXT_FILE參數(shù),例如:
"LOAD_EXT_FILE"=>"user,db" 通過(guò)上面的設(shè)置,就會(huì)執(zhí)行過(guò)程中自動(dòng)載入項(xiàng)目公共目錄下面的擴(kuò)展函數(shù)庫(kù)文件user.php和db.php,這樣就可以直接在項(xiàng)目中調(diào)用擴(kuò)展函數(shù)庫(kù)user.php和db.php中的函數(shù)了,而且擴(kuò)展函數(shù)庫(kù)的函數(shù)修改是實(shí)時(shí)生效的。
手動(dòng)載入
如果你的函數(shù)只是個(gè)別模塊偶爾使用,則不需要采用自動(dòng)加載方式,可以在需要調(diào)用的時(shí)候采用load方法手動(dòng)載入,方式如下:
load("@.user") @.user表示加載當(dāng)前項(xiàng)目的user函數(shù)文件,這樣就可以直接user.php擴(kuò)展函數(shù)庫(kù)中的函數(shù)了。
13. 類庫(kù) ThinkPHP的類庫(kù)包括基類庫(kù)和應(yīng)用類庫(kù),系統(tǒng)的類庫(kù)命名規(guī)則如下:
類庫(kù)規(guī)則示例 控制器類 模塊名+Action 例如?UserAction、InfoAction 模型類 模型名+Model 例如?UserModel、InfoModel 行為類 行為名+Behavior 例如CheckRouteBehavior Widget類 Widget名+Widget 例如BlogInfoWidget 驅(qū)動(dòng)類 引擎名+驅(qū)動(dòng)名 例如DbMysql表示mysql數(shù)據(jù)庫(kù)驅(qū)動(dòng)、CacheFile表示文件緩存驅(qū)動(dòng)
基類庫(kù) 基類庫(kù)是指符合ThinkPHP類庫(kù)規(guī)范的系統(tǒng)類庫(kù),包括ThinkPHP的核心基類庫(kù)和擴(kuò)展基類庫(kù)。核心基類庫(kù)目錄位于系統(tǒng)的Lib目錄,核心基類庫(kù)也就是Think類庫(kù),擴(kuò)展基類庫(kù)位于Extend/Library目錄,可以擴(kuò)展ORG 、Com擴(kuò)展類庫(kù)。核心基類庫(kù)的作用是完成框架的通用性開(kāi)發(fā)而必須的基礎(chǔ)類和內(nèi)置支持類等,包含有:
目錄調(diào)用路徑說(shuō)明 Lib/Core Think.Core 核心類庫(kù)包 Lib/Behavior Think.Behavior 內(nèi)置行為類庫(kù)包 Lib/Driver Think.Driver 內(nèi)置驅(qū)動(dòng)類庫(kù)包 Lib/Template Think.Template 內(nèi)置模板引擎類庫(kù)包
核心類庫(kù)包下面包含下面核心類庫(kù):
類名說(shuō)明 Action 系統(tǒng)基礎(chǔ)控制器類 App 系統(tǒng)應(yīng)用類 Behavior 系統(tǒng)行為基礎(chǔ)類 Cache 系統(tǒng)緩存類 Db 系統(tǒng)抽象數(shù)據(jù)庫(kù)類 Dispatcher URL調(diào)度類 Log 系統(tǒng)日志類 Model 系統(tǒng)基礎(chǔ)模型類 Think 系統(tǒng)入口和靜態(tài)類 ThinkException 系統(tǒng)基礎(chǔ)異常類 View 視圖類 Widget 系統(tǒng)Widget基礎(chǔ)類
應(yīng)用類庫(kù) 應(yīng)用類庫(kù)是指項(xiàng)目中自己定義或者使用的類庫(kù),這些類庫(kù)也是遵循ThinkPHP的命名規(guī)范。應(yīng)用類庫(kù)目錄位于項(xiàng)目目錄下面的Lib目錄。應(yīng)用類庫(kù)的范圍很廣,包括Action類庫(kù)、Model類庫(kù)或者其他的工具類庫(kù),通常包括:
目錄調(diào)用路徑說(shuō)明 Lib/Action @.Action或自動(dòng)加載 控制器類庫(kù)包 Lib/Model @.Model或自動(dòng)加載 模型類庫(kù)包 Lib/Behavior 用B方法調(diào)用或自動(dòng)加載 應(yīng)用行為類庫(kù)包 Lib/Widget 用W方法在模板中調(diào)用 應(yīng)用Widget類庫(kù)包
項(xiàng)目根據(jù)自己的需要可以在項(xiàng)目類庫(kù)目錄下面添加自己的類庫(kù)包,例如Lib/Common、Lib/Tool等。
類庫(kù)導(dǎo)入 一、Import顯式導(dǎo)入 ThinkPHP模擬了Java的類庫(kù)導(dǎo)入機(jī)制,統(tǒng)一采用import方法進(jìn)行類文件的加載。import方法是ThinkPHP內(nèi)建的類庫(kù)導(dǎo)入方法,提供了方便和靈活的文件導(dǎo)入機(jī)制,完全可以替代PHP的require和include方法。例如:
import("Think.Util.Session"); ?import("App.Model.UserModel"); import方法具有緩存和檢測(cè)機(jī)制,相同的文件不會(huì)重復(fù)導(dǎo)入,如果導(dǎo)入了不同的位置下面的同名類庫(kù)文件,系統(tǒng)也不會(huì)再次導(dǎo)入 注意:在Unix或者Linux主機(jī)下面是區(qū)別大小寫的,所以在使用import方法的時(shí)候要注意目錄名和類庫(kù)名稱的大小寫,否則會(huì)導(dǎo)入失敗。對(duì)于import方法,系統(tǒng)會(huì)自動(dòng)識(shí)別導(dǎo)入類庫(kù)文件的位置,ThinkPHP的約定是Think、ORG、Com包的導(dǎo)入作為基類庫(kù)導(dǎo)入,否則就認(rèn)為是項(xiàng)目應(yīng)用類庫(kù)導(dǎo)入。
import("Think.Util.Session"); ?import("ORG.Util.Page"); 上面兩個(gè)方法分別導(dǎo)入了Think基類庫(kù)的Util/Session.class.php文件和ORG擴(kuò)展類庫(kù)包的Util/Page.class.php文件。 要導(dǎo)入項(xiàng)目的應(yīng)用類庫(kù)文件也很簡(jiǎn)單,使用下面的方式就可以了,和導(dǎo)入基類庫(kù)的方式看起來(lái)差不多:
import("MyApp.Action.UserAction"); ?import("MyApp.Model.InfoModel"); 上面的方式分別表示導(dǎo)入MyApp項(xiàng)目下面的Lib/Action/UserAction.class.php和Lib/Model/InfoModel.class.php類文件。 通常我們都是在當(dāng)前項(xiàng)目里面導(dǎo)入所需的類庫(kù)文件,所以,我們可以使用下面的方式來(lái)簡(jiǎn)化代碼
import("@.Action.UserAction"); ?import("@.Model.InfoModel"); 二,別名導(dǎo)入 除了命名空間的導(dǎo)入方式外,import方法還可以支持別名導(dǎo)入,要使用別名導(dǎo)入,首先要定義別名,我們可以在項(xiàng)目配置目錄下面增加alias.php 用以定義項(xiàng)目中需要用到的類庫(kù)別名,例如:
return?array( ????'rbac'?=>LIB_PATH.'Common/Rbac.class.php', ????'page'?=>LIB_PATH.'Common/Page.class.php', ?); 那么,現(xiàn)在就可以直接使用:
import("rbac"); ?import("page"); 導(dǎo)入Rbac和Page類,別名導(dǎo)入方式禁止使用import方法的第二和第三個(gè)參數(shù),別名導(dǎo)入方式的效率比命名空間導(dǎo)入方式要高效,缺點(diǎn)是需要預(yù)先定義相關(guān)別名。
導(dǎo)入第三方類庫(kù) 第三方類庫(kù)統(tǒng)一放置在系統(tǒng)擴(kuò)展目錄下的Vendor 目錄,并且使用vendor 方法導(dǎo)入,其參數(shù)和 import 方法是 一致的,只是默認(rèn)的值有針對(duì)變化。?例如,我們把 Zend 的 Filter\Dir.php 放到 Vendor 目錄下面,這個(gè)時(shí)候 Dir 文件的路徑就是? Vendor\Zend\Filter\Dir.php,我們使用vendor 方法導(dǎo)入只需要使用:
Vendor('Zend.Filter.Dir'); 就可以導(dǎo)入Dir類庫(kù)了。
Vendor方法也可以支持和import方法一樣的基礎(chǔ)路徑和文件名后綴參數(shù),例如:
Vendor('Zend.Filter.Dir',dirname(__FILE__),'.class.php'); 自動(dòng)加載 在大多數(shù)情況下,我們無(wú)需手動(dòng)導(dǎo)入類庫(kù),而是通過(guò)配置采用自動(dòng)加載機(jī)制即可,自動(dòng)加載機(jī)制是真正的按需加載,可以很大程度的提高性能。自動(dòng)加載有三種情況,按照加載優(yōu)先級(jí)從高到低分別是:別名自動(dòng)加載、系統(tǒng)規(guī)則自動(dòng)加載和自定義路徑自動(dòng)加載。 一、別名自動(dòng)加載 在前面我們提到了別名的定義方式,并且采用了import方法進(jìn)行別名導(dǎo)入,其實(shí)所有定義別名的類庫(kù)都無(wú)需再手動(dòng)加載,系統(tǒng)會(huì)按需自動(dòng)加載。 二、 系統(tǒng)規(guī)則自動(dòng)加載 果你沒(méi)有定義別名的話,系統(tǒng)會(huì)首先按照內(nèi)置的規(guī)則來(lái)判斷加載,系統(tǒng)規(guī)則僅針對(duì)行為類、模型類和控制器類,搜索規(guī)則如下:
類名規(guī)則說(shuō)明 行為類 規(guī)則1 搜索系統(tǒng)類庫(kù)目錄下面的Behavior目錄 規(guī)則2 搜索系統(tǒng)擴(kuò)展目錄下面的Behavior目錄 規(guī)則3 搜索應(yīng)用類庫(kù)目錄下面的Behavior目錄 規(guī)則4 如果啟用了模式擴(kuò)展,則搜索模式擴(kuò)展目錄下面的Behavior目錄 模型類 規(guī)則1 如果啟用分組,則搜索應(yīng)用類庫(kù)目錄的Model/當(dāng)前分組 目錄 規(guī)則2 搜索應(yīng)用類庫(kù)下面的Model目錄 規(guī)則3 搜索系統(tǒng)擴(kuò)展目錄下面的Model目錄 控制器類 規(guī)則1 如果啟用分組,則搜索應(yīng)用類庫(kù)目錄的Action/當(dāng)前分組 目錄 規(guī)則2 搜索項(xiàng)目類庫(kù)目錄下面的Action目錄 規(guī)則3 搜索系統(tǒng)擴(kuò)展目錄下面的Action目錄
注意:搜索的優(yōu)先順序從上至下 ,一旦找到則返回,后面規(guī)則不再檢測(cè)。如果全部規(guī)則檢測(cè)完成后依然沒(méi)有找到類庫(kù),則開(kāi)始進(jìn)行第三個(gè)自定義路徑自動(dòng)加載檢測(cè)。
三、 自定義路徑自動(dòng)加載 當(dāng)你的類庫(kù)比較集中在某個(gè)目錄下面,而且不想定義太多的別名導(dǎo)入的話,可以使用自定義路徑自動(dòng)加載方式,這種方式需要在項(xiàng)目配置文件中添加自動(dòng)加載的搜索路徑,例如:
'APP_AUTOLOAD_PATH'?=>'@.Common,@.Tool', 表示,在當(dāng)前項(xiàng)目類庫(kù)目錄下面的Common和Tool目錄下面的類庫(kù)可以自動(dòng)加載。多個(gè)搜索路徑之間用逗號(hào)分割,并且注意定義的順序也就是自動(dòng)搜索的順序。
注意:自動(dòng)搜索路徑定義只能采用命名空間方式,也就是說(shuō)這種方式只能自動(dòng)加載項(xiàng)目類庫(kù)目錄和基類庫(kù)目錄下面的類庫(kù)文件。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
控制器: 1. URL模式 傳統(tǒng)方式的文件入口訪問(wèn)會(huì)變成由URL的參數(shù)來(lái)統(tǒng)一解析和調(diào)度。 ThinkPHP支持四種URL模式,可以通過(guò)設(shè)置URL_MODEL參數(shù)來(lái)定義,包括普通模式、PATHINFO、REWRITE和兼容模式。
一、普通模式 :設(shè)置URL_MODEL 為0
采用傳統(tǒng)的URL參數(shù)模式
http://serverName/appName/?m=module&a=action&id=1 二、PATHINFO模式(默認(rèn)模式) :設(shè)置URL_MODEL 為1 默認(rèn)情況使用PATHINFO模式,ThinkPHP內(nèi)置強(qiáng)大的PATHINFO支持,提供靈活和友好URL支持。PATHINFO模式自動(dòng)識(shí)別模塊和操作,例如 http://serverName/appName/module/action/id/1/或者 http://serverName/appName/module,action,id,1/ 三、REWRITE模式 : 設(shè)置URL_MODEL 為2
該URL模式和PATHINFO模式功能一樣,除了可以不需要在URL里面寫入口文件,和可以定義.htaccess 文件外。在開(kāi)啟了Apache的URL_REWRITE模塊后,就可以啟用REWRITE模式了,具體參考下面的URL重寫部分。
四、兼容模式 : 設(shè)置URL_MODEL 為3
兼容模式是普通模式和PATHINFO模式的結(jié)合,并且可以讓應(yīng)用在需要的時(shí)候直接切換到PATHINFO模式而不需要更改模板和程序,還可以和URL_WRITE模式整合。兼容模式URL可以支持任何的運(yùn)行環(huán)境。 兼容模式的效果是:
http://serverName/appName/?s=/module/action/id/1/ 并且也可以支持參數(shù)分割符號(hào)的定義,例如在URL_PATHINFO_DEPR為~的情況下,下面的URL有效:
http://serverName/appName/?s=module~action~id~1 其實(shí)是利用了VAR_PATHINFO參數(shù),用普通模式的實(shí)現(xiàn)模擬了PATHINFO的模式。但是兼容模式并不需要自己傳s變量,而是由系統(tǒng)自動(dòng)完成URL部分。正是由于這個(gè)特性,兼容模式可以和PATHINFO模式之間直接切換,而不需更改模板文件里面的URL地址連接。我們建議的方式是采用PATHINFO模式開(kāi)發(fā),如果部署的時(shí)候環(huán)境不支持PATHINFO則改成兼容URL模式部署即可,程序和模板都不需要做任何改動(dòng)。 2. 模塊和操作 http://域名/項(xiàng)目名/分組名/模塊名/操作名/其他參數(shù) Dispatcher會(huì)根據(jù)URL地址來(lái)獲取當(dāng)前需要執(zhí)行的項(xiàng)目、分組(如果有定義的話)模塊、操作以及其他參數(shù),在某些情況下,項(xiàng)目名可能不會(huì)出現(xiàn)在URL地址中(通常情況下入口文件則代表了某個(gè)項(xiàng)目,而且入口文件可以被隱藏)。 每一個(gè)模塊就是一個(gè)控制器類,通常位于項(xiàng)目的Lib\Action目錄下面。 3.1版本開(kāi)始,增加ACTION_SUFFIX配置參數(shù),用于設(shè)置操作方法的后綴。
例如,如果設(shè)置:
'ACTION_SUFFIX'=>'Act' 那么訪問(wèn)某個(gè)模塊的add操作對(duì)應(yīng)讀取模塊類的操作方法則由原來(lái)的add方法變成addAct方法。
3. 定義控制器和空操作,空模塊 一個(gè)應(yīng)用如果不需要和數(shù)據(jù)庫(kù)交互的時(shí)候可以不需要定義模型類,但是必須定義Action控制器,一般位于項(xiàng)目的Lib/Action目錄下面。
Action控制器的定義非常簡(jiǎn)單,只要繼承Action基礎(chǔ)類就可以了,例如:
Class?UserAction?extends?Action{} 控制器文件的名稱是UserAction.class.php。 空操作是指系統(tǒng)在找不到指定的操作方法的時(shí)候,會(huì)定位到空操作(_empty)方法來(lái)執(zhí)行,利用這個(gè)機(jī)制,我們可以實(shí)現(xiàn)錯(cuò)誤頁(yè)面和一些URL的優(yōu)化。 空模塊的概念是指當(dāng)系統(tǒng)找不到指定的模塊名稱的時(shí)候,系統(tǒng)會(huì)嘗試定位空模塊(EmptyAction),利用這個(gè)機(jī)制我們可以用來(lái)定制錯(cuò)誤頁(yè)面和進(jìn)行URL的優(yōu)化。 4. 模塊分組 模塊分組相關(guān)的配置參數(shù)包括:
配置參數(shù)說(shuō)明 APP_GROUP_LIST 項(xiàng)目分組列表(配置即表示開(kāi)啟分組) DEFAULT_GROUP 默認(rèn)分組(默認(rèn)值為Home) TMPL_FILE_DEPR 分組模板下面模塊和操作的分隔符,默認(rèn)值為“/” VAR_GROUP 分組的URL參數(shù)名,默認(rèn)為g(普通模式URL才需要)
例如我們把當(dāng)前的項(xiàng)目分成Home和Admin兩個(gè)組,分別表示前臺(tái)和后臺(tái)功能,那么只需要在項(xiàng)目配置中添加下面的配置:
'APP_GROUP_LIST'?=>?'Home,Admin',?//項(xiàng)目分組設(shè)定 ?'DEFAULT_GROUP'??=>?'Home',?//默認(rèn)分組 多個(gè)分組之間用逗號(hào)分隔即可,默認(rèn)分組只允許設(shè)置一個(gè)。
5. URL偽靜態(tài) ThinkPHP支持偽靜態(tài)URL設(shè)置,可以通過(guò)設(shè)置URL_HTML_SUFFIX參數(shù)隨意在URL的最后增加你想要的靜態(tài)后綴,而不會(huì)影響當(dāng)前操作的正常執(zhí)行。例如,我們?cè)O(shè)置
'URL_HTML_SUFFIX'=>'shtml' 的話,我們可以把下面的URL
http://serverName/Blog/read/id/1 變成
http://serverName/Blog/read/id/1.shtml 后者更具有靜態(tài)頁(yè)面的URL特征,但是具有和前面的URL相同的執(zhí)行效果,并且不會(huì)影響原來(lái)參數(shù)的使用。
注意:偽靜態(tài)后綴設(shè)置時(shí)可以不包含后綴中的“.”。所以,下面的配置其實(shí)是等效的:
'URL_HTML_SUFFIX'=>'.shtml' 偽靜態(tài)設(shè)置后,如果需要?jiǎng)討B(tài)生成一致的URL,可以使用U方法在模板文件里面生成URL。 3.1版本開(kāi)始,默認(rèn)情況下,可以支持所有的靜態(tài)后綴,并且會(huì)記錄當(dāng)前的偽靜態(tài)后綴到常量__EXT__,但不會(huì)影響正常的頁(yè)面訪問(wèn)。如果要獲取當(dāng)前的偽靜態(tài)后綴,通過(guò)常量
__EXT__ 獲取即可。 如果只是希望支持配置的偽靜態(tài)后綴,可以直接設(shè)置成可以支持多個(gè)后綴,例如:
'URL_HTML_SUFFIX'=>'html|shmtl|xml'?//?多個(gè)用?|?分割 如果設(shè)置了多個(gè)偽靜態(tài)后綴的話,使用U函數(shù)生成的URL地址中會(huì)默認(rèn)使用第一個(gè)后綴,也支持指定后綴生成url地址。 6. URL路由 ThinkPHP支持URL路由功能,要啟用路由功能,需要設(shè)置URL_ROUTER_ON 參數(shù)為true。開(kāi)啟路由功能后,并且配置URL_ROUTE_RULES參數(shù)后,系統(tǒng)會(huì)自動(dòng)進(jìn)行路由檢測(cè),如果在路由定義里面找到和當(dāng)前URL匹配的路由名稱,就會(huì)進(jìn)行路由解析和重定向。 詳情見(jiàn): http://doc.thinkphp.cn/manual/url_route.html
7. URL重寫 詳情見(jiàn): http://doc.thinkphp.cn/manual/url_rewrite.html
8. URL生成 為了配合所使用的URL模式,我們需要能夠動(dòng)態(tài)的根據(jù)當(dāng)前的URL設(shè)置生成對(duì)應(yīng)的URL地址,為此,ThinkPHP內(nèi)置提供了U方法,用于URL的動(dòng)態(tài)生成,可以確保項(xiàng)目在移植過(guò)程中不受環(huán)境的影響。 U方法的定義規(guī)則如下(方括號(hào)內(nèi)參數(shù)根據(jù)實(shí)際應(yīng)用決定): U('[分組/模塊/操作]?參數(shù)'?[,'參數(shù)','偽靜態(tài)后綴','是否跳轉(zhuǎn)','顯示域名']) 如果不定義項(xiàng)目和模塊的話 就表示當(dāng)前項(xiàng)目和模塊名稱,下面是一些簡(jiǎn)單的例子: U('User/add')?//?生成User模塊的add操作的URL地址 U('Blog/read?id=1')?//?生成Blog模塊的read操作?并且id為1的URL地址 U('Admin/User/select')?//?生成Admin分組的User模塊的select操作的URL地址 U方法的第二個(gè)參數(shù)支持?jǐn)?shù)組和字符串兩種定義方式,如果只是字符串方式的參數(shù)可以在第一個(gè)參數(shù)中定義,例如: U('Blog/cate',array('cate_id'=>1,'status'=>1)) U('Blog/cate','cate_id=1&status=1') U('Blog/cate?cate_id=1&status=1') 三種方式是等效的,都是 生成Blog模塊的cate操作 并且cate_id為1 status為1的URL地址 但是不允許使用下面的定義方式來(lái)傳參數(shù) U('Blog/cate/cate_id/1/status/1') 根據(jù)項(xiàng)目的不同URL設(shè)置,同樣的U方法調(diào)用可以智能地對(duì)應(yīng)產(chǎn)生不同的URL地址效果,例如針對(duì)
U('Blog/read?id=1')這個(gè)定義為例。 如果當(dāng)前URL設(shè)置為普通模式的話,最后生成的URL地址是:?
http://serverName/index.php?m=Blog&a=read&id=1
如果當(dāng)前URL設(shè)置為PATHINFO模式的話,同樣的方法最后生成的URL地址是:?
http://serverName/index.php/Blog/read/id/1
如果當(dāng)前URL設(shè)置為REWRITE模式的話,同樣的方法最后生成的URL地址是:?
http://serverName/Blog/read/id/1
如果當(dāng)前URL設(shè)置為REWRITE模式,并且設(shè)置了偽靜態(tài)后綴為.html的話,同樣的方法最后生成的URL地址是:?
http://serverName/Blog/read/id/1.html
U方法還可以支持路由,如果我們定義了一個(gè)路由規(guī)則為:
?'news/:id\d'=>'News/read' 那么可以使用
U('/news/1') 最終生成的URL地址是:
http://serverName/index.php/news/1 注意:如果你是在模板文件中直接使用U方法的話,需要采用 {:U('參數(shù)1', '參數(shù)2'…)} 的方式,具體參考模板引擎章節(jié)的8.3 使用函數(shù)內(nèi)容。
如果你的應(yīng)用涉及到多個(gè)子域名的操作地址,那么也可以在U方法里面指定需要生成地址的域名,例如:
U('Blog/read@blog.thinkphp.cn','id=1'); @后面?zhèn)魅胄枰付ǖ挠蛎纯伞?br /> 此外,U方法的第5個(gè)參數(shù)如果設(shè)置為true,表示自動(dòng)識(shí)別當(dāng)前的域名,并且會(huì)自動(dòng)根據(jù)子域名部署設(shè)置APP_SUB_DOMAIN_DEPLOY和APP_SUB_DOMAIN_RULES自動(dòng)匹配生成當(dāng)前地址的子域名。 如果開(kāi)啟了URL_CASE_INSENSITIVE,則會(huì)統(tǒng)一生成小寫的URL地址。
?
9. URL大小寫 只要在項(xiàng)目配置中,增加:
?
'URL_CASE_INSENSITIVE'?=>true 就可以實(shí)現(xiàn)URL訪問(wèn)不再區(qū)分大小寫了。
這里需要注意一個(gè)地方,如果我們定義了一個(gè)UserTypeAction的模塊類,那么URL的訪問(wèn)應(yīng)該是:
http://serverName/index.php/user_type/list ?//而不是 http://serverName/index.php/usertype/list 利用系統(tǒng)提供的U方法可以為你自動(dòng)生成相關(guān)的URL地址。 如果設(shè)置
'URL_CASE_INSENSITIVE'?=>false 的話,URL就又變成:
http://serverName/index.php/UserType/list 注意:URL不區(qū)分大小寫并不會(huì)改變系統(tǒng)的命名規(guī)范,并且只有按照系統(tǒng)的命名規(guī)范后才能正確的實(shí)現(xiàn)URL不區(qū)分大小寫。
?
10. 前置和后置操作 系統(tǒng)會(huì)檢測(cè)當(dāng)前操作是否具有前置和后置操作,如果存在就會(huì)按照順序執(zhí)行,前置和后置操作的方法名是在要執(zhí)行的方法前面加 _before_和_after_,例如:
?
class?CityAction?extends?Action{ ????//前置操作方法 ????public?function?_before_index(){ ????????echo?'before<br/>'; ????} ????public?function?index(){ ????????echo?'index<br/>'; ????} ????//后置操作方法 ????public?function?_after_index(){ ????????echo?'after<br/>'; ????} ?} 對(duì)于任何操作方法我們都可以按照這樣的規(guī)則來(lái)定義前置和后置方法。 如果當(dāng)前的操作并沒(méi)有定義操作方法,而是直接渲染模板文件,那么如果定義了前置 和后置方法的話,依然會(huì)生效。真正有模板輸出的可能僅僅是當(dāng)前的操作,前置和后置操作一般情況是沒(méi)有任何輸出的。 需要注意的是,在有些方法里面使用了exit或者錯(cuò)誤輸出之類的話 有可能不會(huì)再執(zhí)行后置方法了。 例如,如果在當(dāng)前操作里面調(diào)用了系統(tǒng)Action的error方法,那么將不會(huì)再執(zhí)行后置操作,但是不影響success方法的后置方法執(zhí)行。 11. 跨模塊調(diào)用 例如,我們?cè)贗ndex模塊調(diào)用User模塊的操作方法 class?IndexAction?extends?Action{ ????public?function?index(){ ????????//實(shí)例化UserAction ????????$User?=?new?UserAction(); ????????//其他用戶操作 ?????????//... ????????$this->display();?//輸出頁(yè)面模板 ????} ?} 因?yàn)橄到y(tǒng)會(huì)自動(dòng)加載Action控制器,因此 我們不需要導(dǎo)入U(xiǎn)serAction類就可以直接實(shí)例化。 并且為了方便跨模塊調(diào)用,系統(tǒng)內(nèi)置了A方法和R方法。 ???$User?=?A('User'); 事實(shí)上,A方法還支持跨分組或者跨項(xiàng)目調(diào)用,默認(rèn)情況下是調(diào)用當(dāng)前項(xiàng)目下面的模塊。 跨項(xiàng)目調(diào)用的格式是:A('[項(xiàng)目名://][分組名/]模塊名') 例如: A('User')?//表示調(diào)用當(dāng)前項(xiàng)目的User模塊 A('Admin://User')?//表示調(diào)用Admin項(xiàng)目的User模塊 A('Admin/User')?//表示調(diào)用Admin分組的User模塊 A('Admin://Tool/User')?//表示調(diào)用Admin項(xiàng)目Tool分組的User模塊 R方法表示調(diào)用一個(gè)模塊的某個(gè)操作方法,調(diào)用格式是:
R('[項(xiàng)目名://][分組名/]模塊名/操作名',array('參數(shù)1','參數(shù)2'…)) 例如:
R('User/info')?//表示調(diào)用當(dāng)前項(xiàng)目的User模塊的info操作方法 R('Admin/User/info')?//表示調(diào)用Admin分組的User模塊的info操作方法 R('Admin://Tool/User/info')?//表示調(diào)用Admin項(xiàng)目Tool分組的User模塊的info操作方法 R方法還支持對(duì)調(diào)用的操作方法需要傳入?yún)?shù),例如User模塊中我們定義了一個(gè)info方法:
class?UserAction?extends?Action{ ????protected?function?info($id){ ????????$User?=?M('User'); ????????$User->find($id); ????????//... ????} ?} 接下來(lái),我們可以在其他模塊中調(diào)用:
R('User/info',array(15)) 表示調(diào)用當(dāng)前項(xiàng)目的User模塊的info操作方法,并且id參數(shù)傳入15
12. 頁(yè)面跳轉(zhuǎn) 系統(tǒng)的Action類內(nèi)置了兩個(gè)跳轉(zhuǎn)方法success和error,用于頁(yè)面跳轉(zhuǎn)提示,而且可以支持ajax提交。使用方法很簡(jiǎn)單,舉例如下: $User?=?M('User');?//實(shí)例化User對(duì)象 $result?=?$User->add($data);? if($result){ ????//設(shè)置成功后跳轉(zhuǎn)頁(yè)面的地址,默認(rèn)的返回頁(yè)面是$_SERVER['HTTP_REFERER'] ????$this->success('新增成功',?'User/list'); }?else?{ ????//錯(cuò)誤頁(yè)面的默認(rèn)跳轉(zhuǎn)頁(yè)面是返回前一頁(yè),通常不需要設(shè)置 ????$this->error('新增失敗'); } Success和error方法都有對(duì)應(yīng)的模板,并且是可以設(shè)置的,默認(rèn)的設(shè)置是兩個(gè)方法對(duì)應(yīng)的模板都是:
//默認(rèn)錯(cuò)誤跳轉(zhuǎn)對(duì)應(yīng)的模板文件 'TMPL_ACTION_ERROR'?=>?THINK_PATH?.?'Tpl/dispatch_jump.tpl'; //默認(rèn)成功跳轉(zhuǎn)對(duì)應(yīng)的模板文件 'TMPL_ACTION_SUCCESS'?=>?THINK_PATH?.?'Tpl/dispatch_jump.tpl'; 也可以使用項(xiàng)目?jī)?nèi)部的模板文件
//默認(rèn)錯(cuò)誤跳轉(zhuǎn)對(duì)應(yīng)的模板文件 'TMPL_ACTION_ERROR'?=>?'Public:error'; //默認(rèn)成功跳轉(zhuǎn)對(duì)應(yīng)的模板文件 'TMPL_ACTION_SUCCESS'?=>?'Public:success'; 模板文件可以使用模板標(biāo)簽,并且可以使用下面的模板變量:
$msgTitle 操作標(biāo)題 $message 頁(yè)面提示信息 $status 操作狀態(tài) 1表示成功 0 表示失敗 具體還可以由項(xiàng)目本身定義規(guī)則 $waitSecond 跳轉(zhuǎn)等待時(shí)間 單位為秒 $jumpUrl 跳轉(zhuǎn)頁(yè)面地址
success和error方法會(huì)自動(dòng)判斷當(dāng)前請(qǐng)求是否屬于Ajax請(qǐng)求,如果屬于Ajax請(qǐng)求則會(huì)調(diào)用ajaxReturn方法返回信息,具體可以參考后面的AJAX返回部分。 3.1版本開(kāi)始,error和success方法支持傳值,無(wú)論是跳轉(zhuǎn)模板方式還是ajax方式 都可以使用assign方式傳參。例如:
$this->assign('var1','value1'); $this->assign('var2','value2'); $this->error('錯(cuò)誤的參數(shù)','要跳轉(zhuǎn)的URL地址'); 當(dāng)正常方式提交的時(shí)候,var1和var2變量會(huì)賦值到錯(cuò)誤模板的模板變量。
當(dāng)采用AJAX方式提交的時(shí)候,會(huì)自動(dòng)調(diào)用ajaxReturn方法傳值過(guò)去(包括跳轉(zhuǎn)的URL地址url和狀態(tài)值status)
13. 重定向 Action類的redirect方法可以實(shí)現(xiàn)頁(yè)面的重定向功能。
redirect方法的參數(shù)用法和U函數(shù)的用法一致(參考上面的URL生成部分),例如:
//重定向到New模塊的Category操作 $this->redirect('New/category',?array('cate_id'?=>?2),?5,?'頁(yè)面跳轉(zhuǎn)中...'); 上面的用法是停留5秒后跳轉(zhuǎn)到News模塊的category操作,并且顯示頁(yè)面跳轉(zhuǎn)中字樣,重定向后會(huì)改變當(dāng)前的URL地址。
如果你僅僅是想重定向要一個(gè)指定的URL地址,而不是到某個(gè)模塊的操作方法,可以直接使用redirect方法重定向,例如:
//重定向到指定的URL地址 redirect('/New/category/cate_id/2',?5,?'頁(yè)面跳轉(zhuǎn)中...') Redirect方法的第一個(gè)參數(shù)是一個(gè)URL地址。
14. 獲取系統(tǒng)變量 $this->方法名("變量名",["過(guò)濾方法"],["默認(rèn)值"]) 方法名可以支持: 方法名含義 _get 獲取GET參數(shù) _post 獲取POST參數(shù) _param 自動(dòng)判斷請(qǐng)求類型獲取GET、POST或者PUT參數(shù)(3.1新增) _request 獲取REQUEST?參數(shù) _put 獲取PUT?參數(shù) _session 獲取?$_SESSION?參數(shù) _cookie 獲取?$_COOKIE?參數(shù) _server 獲取?$_SERVER?參數(shù) _globals 獲取?$GLOBALS參數(shù)
變量名 :(必須)是要獲取的系統(tǒng)變量的名稱過(guò)濾方法 :(可選)可以用任何的內(nèi)置函數(shù)或者自定義函數(shù)名,如果沒(méi)有指定的話,采用默認(rèn)的htmlspecialchars函數(shù)進(jìn)行安全過(guò)濾(由DEFAULT_FILTER 參數(shù)配置),參數(shù)就是前面方法名獲取到的值,也就是說(shuō)如果調(diào)用:$this->_get("name"); 最終調(diào)用的結(jié)果就是 htmlspecialchars($_GET["name"]),如果要改變過(guò)濾方法,可以使用: $this->_get("name","strip_tags"); 默認(rèn)值 :(可選)是要獲取的參數(shù)變量不存在的情況下設(shè)置的默認(rèn)值,例如:$this->_get("id","strip_tags",0); 如果$_GET["id"] 不存在的話,會(huì)返回0。 如果沒(méi)有設(shè)置任何默認(rèn)值的話,系統(tǒng)默認(rèn)返回NULL。
也可以支持多函數(shù)過(guò)濾。 例如,可以設(shè)置:
?'DEFAULT_FILTER'=>'htmlspecialchars,strip_tags' 那么在控制器類如果調(diào)用
$this->_get('id'); 的話,會(huì)依次對(duì)$_GET['id'] 變量進(jìn)行htmlspecialchars和strip_tags方法過(guò)濾后返回結(jié)果。 下面調(diào)用方式也同樣支持:
$this->_get('id','htmlspecialchars,strip_tags',0); 其他變量獲取方法用法相同。 支持獲取全部變量,例如:
$this->_get(); 表示獲取$_GET變量值。
支持不過(guò)濾處理 如果不希望過(guò)濾某個(gè)參數(shù),可以使用
$this->_get('id',false); $this->_post('id',false); ?//或者 $this->_get('id',''); $this->_post('id',''); 第二個(gè)參數(shù)使用false或者空字符串則表示不作任何過(guò)濾處理,即使我們有配置默認(rèn)的過(guò)濾方法。 如果我們忽略第二個(gè)參數(shù)調(diào)用的話
$this->_get('id'); $this->_post('id'); 則表示調(diào)用默認(rèn)的過(guò)濾方法(由DEFAULT_FILTER參數(shù)進(jìn)行配置)。
3.1版本開(kāi)始,Action類增加_param方法,可以自動(dòng)根據(jù)當(dāng)前請(qǐng)求類型(例如GET POST)獲取參數(shù)。 例如:
$this->_param('id'); 當(dāng)前為get方式提交的時(shí)候,就是獲取$_GET['id'](進(jìn)行默認(rèn)過(guò)濾后)的值 當(dāng)前為post方式提交的時(shí)候,就是獲取$_POST['id'](進(jìn)行默認(rèn)過(guò)濾后)的值 還可以用_param方法獲取URL中的參數(shù)
$this->_param(0);?//?獲取PATHINFO地址中的第一個(gè)參數(shù) $this->_param(2);?//?獲取PATHINFO地址中的第3個(gè)參數(shù) 15. 判斷請(qǐng)求類型 系統(tǒng)Action類內(nèi)置了一些判斷方法用于判斷請(qǐng)求類型,包括: 方法說(shuō)明 isGet 判斷是否是GET方式提交 isPost 判斷是否是POST方式提交 isPut 判斷是否是PUT方式提交 isDelete 判斷是否是DELETE方式提交 isHead 判斷是否是HEAD提交
使用舉例如下: class?UserAction?extends?Action{ ????public?function?update(){ ????????if?($this->isPost()){ ????????????$User?=?M('User'); ????????????$User->create(); ????????????$User->save(); ????????????$this->success('保存完成'); ????????}else{ ????????????$this->error('非法請(qǐng)求'); ????????} ????} ?} 另外還提供了一個(gè)判斷當(dāng)前是否屬于AJAX提交的方法 isAjax 是否屬于AJAX提交 需要注意的是,如果使用的是ThinkAjax或者自己寫的Ajax類庫(kù)的話,需要在表單里面添加一個(gè)隱藏域,告訴后臺(tái)屬于ajax方式提交,默認(rèn)的隱藏域名稱是ajax(可以通過(guò)VAR_AJAX_SUBMIT配置),如果是JQUERY類庫(kù)的話,則無(wú)需添加任何隱藏域即可自動(dòng)判斷。 16. 獲取URL參數(shù) 我們可以把URL地址 News/archive/2012/01/15 按照“/”分成多個(gè)參數(shù),$_GET["_URL_"][0] 獲取的就是News,$_GET["_URL_"][1]獲取的就是archive,依次類推,可以通過(guò)數(shù)字索引獲取所有的URL參數(shù)。 3.0版開(kāi)始支持URL地址中的PATH_INFO方式的URL的參數(shù)獲取方式,需要配置
VAR_URL_PARAMS參數(shù),默認(rèn)值是:
????'VAR_URL_PARAMS'??????=>?'_URL_',?//?PATHINFO?URL參數(shù)變量 如果這個(gè)值不為空的話,就可以獲取URL地址里面的PATH_INFO URL參數(shù),例如
我們?cè)L問(wèn)
http://serverName.com/index.php/Blog/read/2012/03 則可以在Blog控制器的read操作方法里面采用?
$GET['_URL_'][2] 獲取參數(shù),表示獲取PATH_INFO的URL參數(shù)
Blog/read/2012/03中的第3個(gè)參數(shù)(數(shù)組索引從0開(kāi)始)
$year?=?$GET['_URL_'][2];?//?2012 $month?=?$GET['_URL_'][3];?//??03 3.1版本開(kāi)始,建議使用_param方法獲取URL參數(shù),_param方法方法是3.1新增的方法,可以自動(dòng)根據(jù)當(dāng)前請(qǐng)求類型獲取參數(shù)。
_param方法的用法同_get和_post等方法,區(qū)別在于,_param方法能夠自動(dòng)根據(jù)當(dāng)前請(qǐng)求類型自動(dòng)獲取相應(yīng)的參數(shù),例如:
如果當(dāng)前是get請(qǐng)求方式,
$this->_param('id');? 將會(huì)返回$_GET['id'] 的處理數(shù)據(jù)
當(dāng)采用POST請(qǐng)求方式的時(shí)候,同樣的代碼將會(huì)返回$_POST['id']的處理數(shù)據(jù)
如果采用的是PUT請(qǐng)求,那么會(huì)自動(dòng)返回PUT的處理數(shù)據(jù),而無(wú)需開(kāi)發(fā)人員進(jìn)行判斷。
并且需要注意的是,無(wú)論是什么方式的請(qǐng)求,系統(tǒng)都可以支持URL參數(shù)的獲取,如果C('VAR_URL_PARAMS')設(shè)置不為空的話,就可以使用:
$this->_param(1); $this->_param(2); 來(lái)獲取URL地址中的某個(gè)參數(shù)。
$year?=?$this->_param(2); $month?=?$this->_param(3); 的方式來(lái)獲取。
這樣的好處是可以不需要使用路由功能就可以獲取某個(gè)不規(guī)則的URL地址中的參數(shù)。
17. AJAX返回 系統(tǒng)支持任何的AJAX類庫(kù),Action類提供了ajaxReturn方法用于AJAX調(diào)用后返回?cái)?shù)據(jù)給客戶端。并且支持JSON、XML和EVAL三種方式給客戶端接受數(shù)據(jù),通過(guò)配置DEFAULT_AJAX_RETURN進(jìn)行設(shè)置,默認(rèn)配置采用JSON格式返回?cái)?shù)據(jù),在選擇不同的AJAX類庫(kù)的時(shí)候可以使用不同的方式返回?cái)?shù)據(jù)。要使用ThinkPHP的ajaxReturn方法返回?cái)?shù)據(jù)的話,需要遵守一定的返回?cái)?shù)據(jù)的格式規(guī)范。 ThinkPHP返回的數(shù)據(jù)格式包括:
status 操作狀態(tài) info 提示信息 data 返回?cái)?shù)據(jù)
調(diào)用示例:
$this->ajaxReturn(返回?cái)?shù)據(jù),提示信息,操作狀態(tài)); 返回?cái)?shù)據(jù)data可以支持字符串、數(shù)字和數(shù)組、對(duì)象,返回客戶端的時(shí)候根據(jù)不同的返回格式進(jìn)行編碼后傳輸。如果是JSON格式,會(huì)自動(dòng)編碼成JSON字符串,如果是XML方式,會(huì)自動(dòng)編碼成XML字符串,如果是EVAL方式的話,只會(huì)輸出字符串data數(shù)據(jù),并且忽略status和info信息。
$User?=?M("User");?//?實(shí)例化User對(duì)象 $result?=?$User->add($data); ?if?($result){ ????//?成功后返回客戶端新增的用戶ID,并返回提示信息和操作狀態(tài) ????$this->ajaxReturn($result,"新增成功!",1); ?}else{ ????//?錯(cuò)誤后返回錯(cuò)誤的操作狀態(tài)和提示信息 ????$this->ajaxReturn(0,"新增錯(cuò)誤!",0); ?} 注意,確保你是使用AJAX提交才使用ajaxReturn方法。
在客戶端接受數(shù)據(jù)的時(shí)候,根據(jù)使用的編碼格式進(jìn)行解析即可。
如果需要改變Ajax返回的數(shù)據(jù)格式,可以在控制器Action中增加ajaxAssign方法定義,定義格式如下: public?function?ajaxAssign(&$result)?{ ????//?返回?cái)?shù)據(jù)中增加url屬性 ????$result['url']?=?$this->url; ?} 3.1版本以后,ajaxReturn方法可以更加靈活的進(jìn)行ajax傳值,并且廢棄了ajaxAssign方法擴(kuò)展。能夠完全定義傳值的數(shù)組和類型,例如: $data['status']?=?1; $data['info']?=?'info'; $data['size']?=?9; $data['url']?=?$url; $this->ajaxReturn($data,'JSON'); data傳值數(shù)組可以隨意定義。 改進(jìn)后的ajaxReturn方法也兼容之前的寫法: $this->ajaxReturn($data,'info',1); 系統(tǒng)會(huì)自動(dòng)把info和1兩個(gè)參數(shù)并入$data數(shù)組中,等同于賦值 $data['info']?=?'info'; $data['status']?=?1; 18. Action參數(shù)綁定 http://doc.thinkphp.cn/manual/action_param_bind.html
19. 多層控制器支持 3.1版本開(kāi)始,控制器支持自定義分層。同時(shí)A方法增加第二個(gè)參數(shù)layer,用于設(shè)置控制器分層。
例如
A('User','Event'); 表示實(shí)例化Lib/Event/UserEvent.class.php。
UserEvent如果繼承Action類的話,可以使用Action類所有的功能。
A('User','Api'); 表示實(shí)例化Lib/Api/UserApi.class.php
分層控制器僅用于內(nèi)部調(diào)用,URL訪問(wèn)的控制器還是Action層,但是可以配置
DEFAULT_C_LAYER修改默認(rèn)控制器層名稱(該參數(shù)默認(rèn)值為Action)。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
模型: 模型類的命名規(guī)則是除去表前綴的數(shù)據(jù)表名稱,采用駝峰法命名,并且首字母大寫,然后加上模型類的后綴定義Model,例如:
模型名(類名)約定對(duì)應(yīng)數(shù)據(jù)表(假設(shè)數(shù)據(jù)庫(kù)的前綴定義是?think_) UserModel think_user UserTypeModel think_user_type
如果你的規(guī)則和上面的系統(tǒng)約定不符合,那么需要設(shè)置Model類的數(shù)據(jù)表名稱屬性。 在ThinkPHP的模型里面,有幾個(gè)關(guān)于數(shù)據(jù)表名稱的屬性定義:
屬性說(shuō)明 tableName 不包含表前綴的數(shù)據(jù)表名稱,一般情況下默認(rèn)和模型名稱相同,只有當(dāng)你的表名和當(dāng)前的模型類的名稱不同的時(shí)候才需要定義。 trueTableName 包含前綴的數(shù)據(jù)表名稱,也就是數(shù)據(jù)庫(kù)中的實(shí)際表名,該名稱無(wú)需設(shè)置,只有當(dāng)上面的規(guī)則都不適用的情況或者特殊情況下才需要設(shè)置。 dbName 定義模型當(dāng)前對(duì)應(yīng)的數(shù)據(jù)庫(kù)名稱,只有當(dāng)你當(dāng)前的模型類對(duì)應(yīng)的數(shù)據(jù)庫(kù)名稱和配置文件不同的時(shí)候才需要定義。
1. 模型實(shí)例化 在ThinkPHP中,可以無(wú)需進(jìn)行任何模型定義。只有在需要封裝單獨(dú)的業(yè)務(wù)邏輯的時(shí)候,模型類才是必須被定義的。
1、實(shí)例化基礎(chǔ)模型(Model) 類 在沒(méi)有定義任何模型的時(shí)候,我們可以使用下面的方法實(shí)例化一個(gè)模型類來(lái)進(jìn)行操作:
//實(shí)例化User模型 $User?=?new?Model('User'); ?//或者使用M()快捷方法實(shí)例化,和上面的方法是等效的 $User?=?M('User'); ?//執(zhí)行其他的數(shù)據(jù)操作 $User->select(); 這種方法最簡(jiǎn)單高效,因?yàn)椴恍枰x任何的模型類,所以支持跨項(xiàng)目調(diào)用。缺點(diǎn)也是因?yàn)闆](méi)有自定義的模型類,因此無(wú)法寫入相關(guān)的業(yè)務(wù)邏輯,只能完成基本的CURD操作。
2、實(shí)例化其他公共模型類 $User?=?new?CommonModel('User'); 模型類的實(shí)例化方法有三個(gè)參數(shù),第一個(gè)參數(shù)是模型名稱,第二個(gè)參數(shù)用于設(shè)置數(shù)據(jù)表的前綴(留空則取當(dāng)前項(xiàng)目配置的表前綴),第三個(gè)參數(shù)用于設(shè)置當(dāng)前使用的數(shù)據(jù)庫(kù)連接信息(留空則取當(dāng)前項(xiàng)目配置的數(shù)據(jù)庫(kù)連接信息),例如: $User?=?new?CommonModel('User','think_','db_config'); 用M方法實(shí)現(xiàn)的話,上面的方法可以寫成:
$User?=?M('CommonModel:User','think_','db_config'); M方法默認(rèn)是實(shí)例化Model類,第二個(gè)參數(shù)用于指定表前綴,第三個(gè)參數(shù)就可以指定其他的數(shù)據(jù)庫(kù)連接信息。 模型類CommonModel必須繼承Model。我們可以在CommonModel類里面定義一些通用的邏輯方法,就可以省去為每個(gè)數(shù)據(jù)表定義具體的模型類。
3、實(shí)例化用戶自定義模型(×××Model)類 這種情況是使用的最多的,一個(gè)項(xiàng)目不可避免的需要定義自身的業(yè)務(wù)邏輯實(shí)現(xiàn),就需要針對(duì)每個(gè)數(shù)據(jù)表定義一個(gè)模型類,例如UserModel 、InfoModel等等。
定義的模型類通常都是放到項(xiàng)目的Lib\Model目錄下面。例如,
<?php ????class?UserModel?extends?Model{ ????????public?function?getTopUser(){ ????????????//添加自己的業(yè)務(wù)邏輯 ?????????????//?... ????????} ????} 其實(shí)模型類還可以繼承一個(gè)用戶自定義的公共模型類,而不是只能繼承Model類。 要實(shí)例化自定義模型類,可以使用下面的方式:
<?php ????//實(shí)例化自定義模型 ????$User?=?new?UserModel(); ????//或者使用D快捷方法 ????$User?=?D('User'); ????//執(zhí)行具體的數(shù)據(jù)操作 ????$User->select(); D方法可以自動(dòng)檢測(cè)模型類,如果存在自定義的模型類,則實(shí)例化自定義模型類,如果不存在,則會(huì)實(shí)例化Model基類,同時(shí)對(duì)于已實(shí)例化過(guò)的模型,不會(huì)重復(fù)去實(shí)例化。
D方法還可以支持跨項(xiàng)目和分組調(diào)用,需要使用: //實(shí)例化Admin項(xiàng)目的User模型 D('Admin://User') ?//實(shí)例化Admin分組的User模型 D('Admin/User') 2. 字段定義 字段緩存保存在Runtime/Data/_fields/ 目錄下面,緩存機(jī)制是每個(gè)模型對(duì)應(yīng)一個(gè)字段緩存文件(而并非每個(gè)數(shù)據(jù)表對(duì)應(yīng)一個(gè)字段緩存文件),命名格式是:數(shù)據(jù)庫(kù)名.模型名.php 字段緩存包括數(shù)據(jù)表的字段信息、主鍵字段和是否自動(dòng)增長(zhǎng),如果開(kāi)啟字段類型驗(yàn)證的話還包括字段類型信息等等,無(wú)論是用M方法還是D方法,或者用原生的實(shí)例化模型類一般情況下只要是不開(kāi)啟調(diào)試模式都會(huì)生成字段緩存(字段緩存可以單獨(dú)設(shè)置關(guān)閉)。從3.1版本開(kāi)始,模型的字段緩存文件名全部轉(zhuǎn)換成小寫,避免重復(fù)生成。 可以通過(guò)設(shè)置DB_FIELDS_CACHE 參數(shù)來(lái)關(guān)閉字段自動(dòng)緩存,如果在開(kāi)發(fā)的時(shí)候經(jīng)常變動(dòng)數(shù)據(jù)庫(kù)的結(jié)構(gòu),而不希望進(jìn)行數(shù)據(jù)表的字段緩存,可以在項(xiàng)目配置文件中增加如下配置:
'DB_FIELDS_CACHE'=>false 注意:調(diào)試模式下面由于考慮到數(shù)據(jù)結(jié)構(gòu)可能會(huì)經(jīng)常變動(dòng),所以默認(rèn)是關(guān)閉字段緩存的。
如果需要顯式獲取當(dāng)前數(shù)據(jù)表的字段信息,可以使用模型類的getDbFields方法來(lái)獲取當(dāng)前數(shù)據(jù)對(duì)象的全部字段信息,例如: $fields?=?$User->getDbFields(); 如果你在部署模式下面修改了數(shù)據(jù)表的字段信息,可能需要清空Data/_fields目錄下面的緩存文件,讓系統(tǒng)重新獲取更新的數(shù)據(jù)表字段信息,否則會(huì)發(fā)生新增的字段無(wú)法寫入數(shù)據(jù)庫(kù)的問(wèn)題。 如果不希望依賴字段緩存或者想提高性能,也可以在模型類里面手動(dòng)定義數(shù)據(jù)表字段的名稱,可以避免IO加載的效率開(kāi)銷,在模型類里面添加fields屬性即可,定義格式如下: <?php ????class?UserModel?extends?Model{ ????????protected?$fields?=?array( ????????????'id',?'username',?'email',?'age',?'_pk'?=>?'id',?'_autoinc'?=>?true ????????); ????} 3. 數(shù)據(jù)主鍵 ThinkPHP的默認(rèn)約定每個(gè)數(shù)據(jù)表的主鍵名采用統(tǒng)一的id作為標(biāo)識(shí),并且是自動(dòng)增長(zhǎng)類型的。系統(tǒng)會(huì)自動(dòng)識(shí)別當(dāng)前操作的數(shù)據(jù)表的字段信息和主鍵名稱,所以即使你的主鍵不是id,也無(wú)需進(jìn)行額外的設(shè)置,系統(tǒng)會(huì)自動(dòng)識(shí)別。要在外部獲取當(dāng)前數(shù)據(jù)對(duì)象的主鍵名稱,請(qǐng)使用下面的方法:
$pk?=?$Model->getPk(); 注意:目前不支持聯(lián)合主鍵的自動(dòng)獲取和操作。
?4. 屬性訪問(wèn) ThinkPHP的模型對(duì)象實(shí)例本身也是一個(gè)數(shù)據(jù)對(duì)象,可以支持對(duì)象和數(shù)組兩種方式來(lái)訪問(wèn)數(shù)據(jù)屬性,例如下面的方式采用數(shù)據(jù)對(duì)象的方式來(lái)訪問(wèn)User模型的屬性: //實(shí)例化User模型 $User?=?D('User'); ?//查詢用戶數(shù)據(jù) $User->find(1); ?//獲取name屬性的值 echo?$User->name; ?//設(shè)置name屬性的值 $User->name?=?'ThinkPHP'; 除了find方法會(huì)產(chǎn)生數(shù)據(jù)對(duì)象屬性外,data方法和create方法也會(huì)產(chǎn)生數(shù)據(jù)對(duì)象,例如: $User?=?D('User'); $User->create(); echo?$User->name; 還有一種屬性的操作方式是通過(guò)返回?cái)?shù)組的方式:
//實(shí)例化User模型 $User?=?D('User'); ?//查詢用戶數(shù)據(jù) $data?=?$User->find(1); ?//獲取name屬性的值 echo?$data['name']; ?//設(shè)置name屬性的值 $data['name']?=?'ThinkPHP'; 兩種方式的屬性獲取區(qū)別是一個(gè)是對(duì)象的屬性,一個(gè)是數(shù)組的索引,開(kāi)發(fā)人員可以根據(jù)自己的需要選擇什么方式。
5. 跨庫(kù)操作 ThinkPHP可以支持模型的同一數(shù)據(jù)庫(kù)服務(wù)器的跨庫(kù)操作,跨庫(kù)操作只需要簡(jiǎn)單配置一個(gè)模型所在的數(shù)據(jù)庫(kù)名稱即可,例如,假設(shè)UserModel對(duì)應(yīng)的數(shù)據(jù)表在數(shù)據(jù)庫(kù)user下面,而InfoModel對(duì)應(yīng)的數(shù)據(jù)表在數(shù)據(jù)庫(kù)info下面,那么我們只需要進(jìn)行下面的設(shè)置即可。
class?UserModel?extends?Model?{ ????protected?$dbName?=?'user'; ?} ?class?InfoModel?extends?Model?{ ????protected?$dbName?=?'info'; ?} 在進(jìn)行查詢的時(shí)候,系統(tǒng)能夠自動(dòng)添加當(dāng)前模型所在的數(shù)據(jù)庫(kù)名。
$User?=?D('User');? $User->select(); echo?$User->getLastSql(); ?//?輸出的SQL語(yǔ)句為?select?*?from?user.think_user? 模型的表前綴取的是項(xiàng)目配置文件定義的數(shù)據(jù)表前綴,如果跨庫(kù)操作的時(shí)候表前綴不是統(tǒng)一的,那么我們可以在模型里面單獨(dú)定義表前綴,例如:
protected?$tablePrefix?=?'other_'; 如果你沒(méi)有定義模型類,而是使用的M方法操作的話,也可以支持跨庫(kù)操作,例如:
$User?=?M('user.User','other_');? 表示實(shí)例化User模型,連接的是user數(shù)據(jù)庫(kù)的other_user表。
6. 連接數(shù)據(jù)庫(kù) ThinkPHP內(nèi)置了抽象數(shù)據(jù)庫(kù)訪問(wèn)層,把不同的數(shù)據(jù)庫(kù)操作封裝起來(lái),我們只需要使用公共的Db類進(jìn)行操作,而無(wú)需針對(duì)不同的數(shù)據(jù)庫(kù)寫不同的代碼和底層實(shí)現(xiàn),Db類會(huì)自動(dòng)調(diào)用相應(yīng)的數(shù)據(jù)庫(kù)驅(qū)動(dòng)來(lái)處理。如果應(yīng)用需要使用數(shù)據(jù)庫(kù),必須配置數(shù)據(jù)庫(kù)連接信息,數(shù)據(jù)庫(kù)的配置文件有多種定義方式。
常用的配置方式是在項(xiàng)目配置文件中添加下面的參數(shù): <?php ????//項(xiàng)目配置文件 ????return?array( ????????//數(shù)據(jù)庫(kù)配置信息 ????????'DB_TYPE'???=>?'mysql',?//?數(shù)據(jù)庫(kù)類型 ????????'DB_HOST'???=>?'localhost',?//?服務(wù)器地址 ????????'DB_NAME'???=>?'thinkphp',?//?數(shù)據(jù)庫(kù)名 ????????'DB_USER'???=>?'root',?//?用戶名 ????????'DB_PWD'????=>?'',?//?密碼 ????????'DB_PORT'???=>?3306,?//?端口 ????????'DB_PREFIX'?=>?'think_',?//?數(shù)據(jù)庫(kù)表前綴? ????????//其他項(xiàng)目配置參數(shù) ????????//?... ????); 或者采用如下配置 'DB_DSN'?=>?'mysql://username:password@localhost:3306/DbName' 如果兩種配置參數(shù)同時(shí)存在的話,DB_DSN配置參數(shù)優(yōu)先。 注意:如果要設(shè)置分布式數(shù)據(jù)庫(kù),暫時(shí)不支持DB_DSN方式配置。 如果采用PDO驅(qū)動(dòng)的話,則必須首先配置DB_TYPE 為pdo,然后還需要單獨(dú)配置其他參數(shù),例如:
//PDO連接方式 ?'DB_TYPE'???=>?'pdo',?//?數(shù)據(jù)庫(kù)類型 ?'DB_USER'???=>?'root',?//?用戶名 ?'DB_PWD'????=>?'',?//?密碼 ?'DB_PREFIX'?=>?'think_',?//?數(shù)據(jù)庫(kù)表前綴? ?'DB_DSN'????=>?'mysql:host=localhost;dbname=thinkphp;charset=UTF-8' 注意:PDO方式的DB_DSN配置格式有所區(qū)別,根據(jù)不同的數(shù)據(jù)庫(kù)類型設(shè)置有所不同。
配置文件定義的數(shù)據(jù)庫(kù)連接信息一般是系統(tǒng)默認(rèn)采用的,因?yàn)橐话阋粋€(gè)項(xiàng)目的數(shù)據(jù)庫(kù)訪問(wèn)配置是相同的。該方法系統(tǒng)在連接數(shù)據(jù)庫(kù)的時(shí)候會(huì)自動(dòng)獲取,無(wú)需手動(dòng)連接。可以對(duì)每個(gè)項(xiàng)目和不同的分組定義不同的數(shù)據(jù)庫(kù)連接信息,如果開(kāi)啟了調(diào)試模式的話,還可以在不同的應(yīng)用狀態(tài)的配置文件里面定義獨(dú)立的數(shù)據(jù)庫(kù)配置信息。
第二種 在模型類里面定義connection屬性 如果在某個(gè)模型類里面定義了connection屬性的話,則實(shí)例化該自定義模型的時(shí)候會(huì)采用定義的數(shù)據(jù)庫(kù)連接信息,而不是配置文件中設(shè)置的默認(rèn)連接信息,通常用于某些數(shù)據(jù)表位于當(dāng)前數(shù)據(jù)庫(kù)連接之外的其它數(shù)據(jù)庫(kù),例如: //在模型里單獨(dú)設(shè)置數(shù)據(jù)庫(kù)連接信息 ?protected?$connection?=?array( ????'db_type'??=>?'mysql', ????'db_user'??=>?'root', ????'db_pwd'???=>?'1234', ????'db_host'??=>?'localhost', ????'db_port'??=>?'3306', ????'db_name'??=>?'thinkphp' ?); 也可以采用DSN方式定義,例如: //或者使用DSN定義 ?protected?$connection?=?'mysql://root:1234@localhost:3306/thinkphp'; 如果我們已經(jīng)在配置文件中配置了額外的數(shù)據(jù)庫(kù)連接信息,例如: //數(shù)據(jù)庫(kù)配置1 ?'DB_CONFIG1'?=>?array( ????'db_type'??=>?'mysql', ????'db_user'??=>?'root', ????'db_pwd'???=>?'1234', ????'db_host'??=>?'localhost', ????'db_port'??=>?'3306', ????'db_name'??=>?'thinkphp' ?), ?//數(shù)據(jù)庫(kù)配置2 ?'DB_CONFIG2'?=>?'mysql://root:1234@localhost:3306/thinkphp'; 那么,我們可以把模型類的屬性定義改為: //調(diào)用配置文件中的數(shù)據(jù)庫(kù)配置1 ?protected?$connection?=?'DB_CONFIG1'; ?//調(diào)用配置文件中的數(shù)據(jù)庫(kù)配置2 ?protected?$connection?=?'DB_CONFIG2'; 如果采用的是M方法實(shí)例化模型的話,也可以支持傳入不同的數(shù)據(jù)庫(kù)連接信息,例如:
$User?=?M('User','other_','mysql://root:1234@localhost/demo');? 表示實(shí)例化User模型,連接的是demo數(shù)據(jù)庫(kù)的other_user表,采用的連接信息是第三個(gè)參數(shù)配置的。如果我們?cè)陧?xiàng)目配置文件中已經(jīng)配置了DB_CONFIG2的話,也可以采用:
$User?=?M('User','other_','DB_CONFIG2');? 如果你的個(gè)別數(shù)據(jù)表沒(méi)有定義任何前綴的話,可以在前綴參數(shù)中傳入NULL,例如:
$User?=?M('User',Null,'DB_CONFIG2');? 表示實(shí)例化User模型,連接的是demo數(shù)據(jù)庫(kù)的user表。需要注意的是,ThinkPHP的數(shù)據(jù)庫(kù)連接的惰性的,所以并不是在實(shí)例化的時(shí)候就連接數(shù)據(jù)庫(kù),而是在有實(shí)際的數(shù)據(jù)操作的時(shí)候才會(huì)去連接數(shù)據(jù)庫(kù)(額外的情況是,在系統(tǒng)第一次實(shí)例化模型的時(shí)候,會(huì)自動(dòng)連接數(shù)據(jù)庫(kù)獲取相關(guān)模型類對(duì)應(yīng)的數(shù)據(jù)表的字段信息)。
7. 切換數(shù)據(jù)庫(kù) 只需要調(diào)用Model類的db方法,用法: Model->db("數(shù)據(jù)庫(kù)編號(hào)","數(shù)據(jù)庫(kù)配置"); 數(shù)據(jù)庫(kù)編號(hào)用數(shù)字格式,對(duì)于已經(jīng)調(diào)用過(guò)的數(shù)據(jù)庫(kù)連接,是不需要再傳入數(shù)據(jù)庫(kù)連接信息的,系統(tǒng)會(huì)自動(dòng)記錄。對(duì)于默認(rèn)的數(shù)據(jù)庫(kù)連接,內(nèi)部的數(shù)據(jù)庫(kù)編號(hào)是0,因此為了避免沖突,請(qǐng)不要再次定義數(shù)據(jù)庫(kù)編號(hào)為0的數(shù)據(jù)庫(kù)配置。 數(shù)據(jù)庫(kù)配置的定義方式和模型定義connection屬性一樣,支持?jǐn)?shù)組、字符串以及調(diào)用配置參數(shù)三種格式。 Db方法調(diào)用后返回當(dāng)前的模型實(shí)例,直接可以繼續(xù)進(jìn)行模型的其他操作,所以該方法可以在查詢的過(guò)程中動(dòng)態(tài)切換,例如: $this->db(1,"mysql://root:123456@localhost:3306/test")->query("查詢SQL"); 該方法添加了一個(gè)編號(hào)為1的數(shù)據(jù)庫(kù)連接,并自動(dòng)切換到當(dāng)前的數(shù)據(jù)庫(kù)連接。 當(dāng)?shù)诙吻袚Q到相同的數(shù)據(jù)庫(kù)的時(shí)候,就不需要傳入數(shù)據(jù)庫(kù)連接信息了,可以直接使用: $this->db(1)->query("查詢SQL"); 如果需要切換到默認(rèn)的數(shù)據(jù)庫(kù)連接,只需要調(diào)用: $this->db(0); 如果我們已經(jīng)在項(xiàng)目配置中定義了其他的數(shù)據(jù)庫(kù)連接信息,例如: //數(shù)據(jù)庫(kù)配置1 ?'DB_CONFIG1'?=?array( ????'db_type'??=>?'mysql', ????'db_user'??=>?'root', ????'db_pwd'???=>?'1234', ????'db_host'??=>?'localhost', ????'db_port'??=>?'3306', ????'db_name'??=>?'thinkphp' ?), ?//數(shù)據(jù)庫(kù)配置2 ?'DB_CONFIG2'?=>?'mysql://root:1234@localhost:3306/thinkphp'; 我們就可以直接在db方法中調(diào)用配置進(jìn)行連接了: $this->db(1,"DB_CONFIG1")->query("查詢SQL"); $this->db(2,"DB_CONFIG2")->query("查詢SQL"); 如果切換數(shù)據(jù)庫(kù)之后,數(shù)據(jù)表和當(dāng)前不一致的話,可以使用table方法指定要操作的數(shù)據(jù)表: $this->db(1)->table("top_user")->find(); 我們也可以直接用M方法切換數(shù)據(jù)庫(kù),例如: M("User","think_","mysql://root:123456@localhost:3306/test")->query("查詢SQL"); 或者 M("User","think_","DB_CONFIG1")->query("查詢SQL"); 8. 分布式數(shù)據(jù)庫(kù) ThinkPHP內(nèi)置了分布式數(shù)據(jù)庫(kù)的支持,包括主從式數(shù)據(jù)庫(kù)的讀寫分離,但是分布式數(shù)據(jù)庫(kù)必須是相同的數(shù)據(jù)庫(kù)類型。配置DB_DEPLOY_TYPE 為1 可以采用分布式數(shù)據(jù)庫(kù)支持。如果采用分布式數(shù)據(jù)庫(kù),定義數(shù)據(jù)庫(kù)配置信息的方式如下: //在項(xiàng)目配置文件里面定義 ?return?array( ????//分布式數(shù)據(jù)庫(kù)配置定義 ????'DB_TYPE'???=>?'mysql',?//分布式數(shù)據(jù)庫(kù)類型必須相同 ????'DB_HOST'???=>?'192.168.0.1,192.168.0.2', ????'DB_NAME'???=>?'thinkphp',?//如果相同可以不用定義多個(gè) ????'DB_USER'???=>?'user1,user2', ????'DB_PWD'????=>?'pwd1,pwd2', ????'DB_PORT'???=>?'3306', ????'DB_PREFIX'?=>?'think_', ????//其他配置參數(shù) ????//?... ?); 連接的數(shù)據(jù)庫(kù)個(gè)數(shù)取決于DB_HOST定義的數(shù)量,所以即使是兩個(gè)相同的IP也需要重復(fù)定義,但是其他的參數(shù)如果存在相同的可以不用重復(fù)定義。 還可以設(shè)置分布式數(shù)據(jù)庫(kù)的讀寫是否分離,默認(rèn)的情況下讀寫不分離,也就是每臺(tái)服務(wù)器都可以進(jìn)行讀寫操作,對(duì)于主從式數(shù)據(jù)庫(kù)而言,需要設(shè)置讀寫分離,通過(guò)下面的設(shè)置就可以:
'DB_RW_SEPARATE'=>true, 在讀寫分離的情況下,默認(rèn)
第一個(gè)數(shù)據(jù)庫(kù)配置是主服務(wù)器 的配置信息,負(fù)責(zé)寫入數(shù)據(jù),如果設(shè)置了
DB_MASTER_NUM 參數(shù),則可以支持多個(gè)主服務(wù)器寫入。其它的都是從數(shù)據(jù)庫(kù)的配置信息,負(fù)責(zé)讀取數(shù)據(jù),數(shù)量不限制。每次連接從服務(wù)器并且進(jìn)行讀取操作的時(shí)候,系統(tǒng)會(huì)隨機(jī)進(jìn)行在從服務(wù)器中選擇。
CURD操作系統(tǒng)會(huì)自動(dòng)判斷當(dāng)前執(zhí)行的方法的讀操作還是寫操作,如果你用的是原生SQL,那么需要注意系統(tǒng)的默認(rèn)規(guī)則:
寫操作必須用模型的execute方法,讀操作必須用模型的query方法,否則會(huì)發(fā)生主從讀寫錯(cuò)亂的情況。
注意:主從數(shù)據(jù)庫(kù)的數(shù)據(jù)同步工作不在框架實(shí)現(xiàn),需要數(shù)據(jù)庫(kù)考慮自身的同步或者復(fù)制機(jī)制。
?
9. 創(chuàng)建數(shù)據(jù) 在進(jìn)行數(shù)據(jù)操作之前,我們往往需要手動(dòng)創(chuàng)建需要的數(shù)據(jù),例如對(duì)于提交的表單數(shù)據(jù):
?
//?獲取表單的POST數(shù)據(jù) $data['name']?=?$_POST['name']; $data['email']?=?$_POST['email']; ?//?更多的表單數(shù)據(jù)值獲取 ?//…… 很簡(jiǎn)單的例子:
//?實(shí)例化User模型 $User?=?M('User'); ?//?根據(jù)表單提交的POST數(shù)據(jù)創(chuàng)建數(shù)據(jù)對(duì)象 $User->create(); ?//?把創(chuàng)建的數(shù)據(jù)對(duì)象寫入數(shù)據(jù)庫(kù) $User->add(); Create方法支持從其它方式創(chuàng)建數(shù)據(jù)對(duì)象,例如,從其它的數(shù)據(jù)對(duì)象,或者數(shù)組等
$data['name']?=?'ThinkPHP'; $data['email']?=?'ThinkPHP@gmail.com'; $User->create($data); 甚至還可以支持從對(duì)象創(chuàng)建新的數(shù)據(jù)對(duì)象
//?從User數(shù)據(jù)對(duì)象創(chuàng)建新的Member數(shù)據(jù)對(duì)象 $User?=?M("User"); $User->find(1); $Member?=?M("Member"); $Member->create($User); Create方法創(chuàng)建的數(shù)據(jù)對(duì)象是保存在內(nèi)存中,并沒(méi)有實(shí)際寫入到數(shù)據(jù)庫(kù)中,直到使用add或者save方法才會(huì)真正寫入數(shù)據(jù)庫(kù)。 因此在沒(méi)有調(diào)用add或者save方法之前,我們都可以改變create方法創(chuàng)建的數(shù)據(jù)對(duì)象,例如:
$User?=?M('User'); $User->create();?//創(chuàng)建User數(shù)據(jù)對(duì)象 $User->status?=?1;?//?設(shè)置默認(rèn)的用戶狀態(tài) $User->create_time?=?time();?//?設(shè)置用戶的創(chuàng)建時(shí)間 $User->add();?//?把用戶對(duì)象寫入數(shù)據(jù)庫(kù) 如果只是想簡(jiǎn)單創(chuàng)建一個(gè)數(shù)據(jù)對(duì)象,并不需要完成一些額外的功能的話,可以使用data方法簡(jiǎn)單的創(chuàng)建數(shù)據(jù)對(duì)象。
使用如下:
//?實(shí)例化User模型 $User?=?M('User'); ?//?創(chuàng)建數(shù)據(jù)后寫入到數(shù)據(jù)庫(kù) $data['name']?=?'ThinkPHP'; $data['email']?=?'ThinkPHP@gmail.com'; $User->data($data)->add(); Data方法也支持傳入數(shù)組和對(duì)象,使用data方法創(chuàng)建的數(shù)據(jù)對(duì)象不會(huì)進(jìn)行自動(dòng)驗(yàn)證和過(guò)濾操作,請(qǐng)自行處理。但在進(jìn)行add或者save操作的時(shí)候,數(shù)據(jù)表中不存在的字段以及非法的數(shù)據(jù)類型(例如對(duì)象、數(shù)組等非標(biāo)量數(shù)據(jù))是會(huì)自動(dòng)過(guò)濾的,不用擔(dān)心非數(shù)據(jù)表字段的寫入導(dǎo)致SQL錯(cuò)誤的問(wèn)題。
安全提示: create方法如果沒(méi)有傳值,默認(rèn)取$_POST數(shù)據(jù),如果用戶提交的變量?jī)?nèi)容,含有可執(zhí)行的html代碼,請(qǐng)進(jìn)行手工過(guò)濾。$_POST['title']?=?"<script>alert(1);</script>"; 非法html代碼可以使用htmlspecialchars進(jìn)行編碼,以防止用戶提交的html代碼在展示時(shí)被執(zhí)行,以下是兩種安全處理方法。 $_POST['title']?=?htmlspecialchars($_POST['title']); M('User')->create(); $data['title']?=?$this->_post('title',?'htmlspecialchars'); M('User')->create($data); 10. 字段映射 ThinkPHP的字段映射功能可以讓你在表單中隱藏真正的數(shù)據(jù)表字段,而不用擔(dān)心放棄自動(dòng)創(chuàng)建表單對(duì)象的功能,假設(shè)我們的User表里面有username和email字段,我們需要映射成另外的字段,定義方式如下:
Class?UserModel?extends?Model{ ????protected?$_map?=?array( ????????'name'?=>'username',?//?把表單中name映射到數(shù)據(jù)表的username字段 ????????'mail'??=>'email',?//?把表單中的mail映射到數(shù)據(jù)表的email字段 ????); ?} 這樣,在表單里面就可以直接使用name和mail名稱作為表單數(shù)據(jù)提交了。在保存的時(shí)候會(huì)字段轉(zhuǎn)換成定義的實(shí)際數(shù)據(jù)表字段。字段映射還可以支持對(duì)主鍵的映射。 如果我們需要把數(shù)據(jù)庫(kù)中的數(shù)據(jù)顯示在表單中,并且也支持字段映射的話,需要對(duì)查詢的數(shù)據(jù)進(jìn)行一下處理,處理方式是調(diào)用Model類的parseFieldsMap方法,例如:
//?實(shí)例化User模型 $User?=?M('User'); $data?=?$User->find(3); 這個(gè)時(shí)候取出的data數(shù)據(jù)包含的是實(shí)際的username和email字段,為了方便便表單輸出,我們需要處理成字段映射顯示在表單中,就需要使用下面的代碼處理:
$data?=?$User->parseFieldsMap($data); 這樣一來(lái),data數(shù)據(jù)中就包含了name和mail字段數(shù)據(jù)了,而不再有username和email字段數(shù)據(jù)了。
?11. 連貫操作 ThinkPHP模型基礎(chǔ)類提供的連貫操作方法,可以有效的提高數(shù)據(jù)存取的代碼清晰度和開(kāi)發(fā)效率,并且支持所有的CURD操作。使用也比較簡(jiǎn)單, 假如我們現(xiàn)在要查詢一個(gè)User表的滿足狀態(tài)為1的前10條記錄,并希望按照用戶的創(chuàng)建時(shí)間排序 ,代碼如下:
$User->where('status=1')->order('create_time')->limit(10)->select(); 這里的where、order和limit方法就被稱之為連貫操作方法,T除了select方法必須放到最后一個(gè)外(因?yàn)閟elect方法并不是連貫操作方法),連貫操作T的方法調(diào)用順序沒(méi)有先后,例如,下面的代碼和上面的等效:
$User->order('create_time')->limit(10)->where('status=1')->select(); 如果不習(xí)慣使用連貫操作的話,還支持直接使用參數(shù)進(jìn)行查詢的方式。例如上面的代碼可以改寫為:
$User->select(array('order'=>'create_time','where'=>'status=1','limit'=>'10')); 使用數(shù)組參數(shù)方式的話,索引的名稱就是連貫操作的方法名稱。其實(shí)T不僅僅是查詢方法可以使用連貫操作,包括所有的CURD方法都可以使用,例如:
$User->where('id=1')->field('id,name,email')->find();? $User->where('status=1?and?id=1')->delete(); 連貫操作通常只有一個(gè)參數(shù),并且僅在當(dāng)此查詢或者操作有效,完成后會(huì)自動(dòng)清空連貫操作的所有傳值(有個(gè)別特殊的連貫操作有多個(gè)參數(shù),并且會(huì)記錄當(dāng)前的傳值)。簡(jiǎn)而言之,連貫操作的結(jié)果不會(huì)帶入以后的查詢。
系統(tǒng)支持的連貫操作方法有:
連貫操作作用支持的參數(shù)類型 where 用于查詢或者更新條件的定義 字符串、數(shù)組和對(duì)象 table 用于定義要操作的數(shù)據(jù)表名稱 字符串和數(shù)組 alias 用于給當(dāng)前數(shù)據(jù)表定義別名 字符串 data 用于新增或者更新數(shù)據(jù)之前的數(shù)據(jù)對(duì)象賦值 數(shù)組和對(duì)象 field 用于定義要查詢的字段(支持字段排除) 字符串和數(shù)組 order 用于對(duì)結(jié)果排序 字符串和數(shù)組 limit 用于限制查詢結(jié)果數(shù)量 字符串和數(shù)字 page 用于查詢分頁(yè)(內(nèi)部會(huì)轉(zhuǎn)換成limit) 字符串和數(shù)字 group 用于對(duì)查詢的group支持 字符串 having 用于對(duì)查詢的having支持 字符串 join* 用于對(duì)查詢的join支持 字符串和數(shù)組 union* 用于對(duì)查詢的union支持 字符串、數(shù)組和對(duì)象 distinct 用于查詢的distinct支持 布爾值 lock 用于數(shù)據(jù)庫(kù)的鎖機(jī)制 布爾值 cache 用于查詢緩存 支持多個(gè)參數(shù) relation 用于關(guān)聯(lián)查詢(需要關(guān)聯(lián)模型支持) 字符串
所有的連貫操作都返回當(dāng)前的模型實(shí)例對(duì)象(this),其中帶*標(biāo)識(shí)的表示支持多次調(diào)用。
可參考: http://doc.thinkphp.cn/manual/continuous_operation.html
12. CURD操作 創(chuàng)建(Create) 在ThinkPHP中使用add方法新增數(shù)據(jù)到數(shù)據(jù)庫(kù)(而并不是create方法)。 使用示例如下:
$User?=?M("User");?//?實(shí)例化User對(duì)象 $data['name']?=?'ThinkPHP'; $data['email']?=?'ThinkPHP@gmail.com'; $User->add($data); 或者使用data方法連貫操作
$User->data($data)->add(); 如果在add之前已經(jīng)創(chuàng)建數(shù)據(jù)對(duì)象的話(例如使用了create或者data方法),add方法就不需要再傳入數(shù)據(jù)了。 使用create方法的例子:
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?根據(jù)表單提交的POST數(shù)據(jù)創(chuàng)建數(shù)據(jù)對(duì)象 $User->create(); $User->add();?//?根據(jù)條件保存修改的數(shù)據(jù) 如果你的主鍵是自動(dòng)增長(zhǎng)類型,并且如果插入數(shù)據(jù)成功的話,Add方法的返回值就是最新插入的主鍵值,可以直接獲取。
讀取(Read) 在ThinkPHP中讀取數(shù)據(jù)的方式很多,通常分為讀取數(shù)據(jù)和讀取數(shù)據(jù)集。 讀取數(shù)據(jù)集使用select方法(新版已經(jīng)廢除原來(lái)的findall方法): 使用示例:
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?查找status值為1的用戶數(shù)據(jù)?以創(chuàng)建時(shí)間排序?返回10條數(shù)據(jù) $list?=?$User->where('status=1')->order('create_time')->limit(10)->select(); Select方法配合連貫操作方法可以完成復(fù)雜的數(shù)據(jù)查詢。而最復(fù)雜的連貫方法應(yīng)該是where方法的使用。 讀取數(shù)據(jù)使用find方法: 讀取數(shù)據(jù)的操作其實(shí)和數(shù)據(jù)集的類似,select可用的所有連貫操作方法也都可以用于find方法,區(qū)別在于find方法最多只會(huì)返回一條記錄,因此limit方法對(duì)于find查詢操作是無(wú)效的。
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?查找status值為1name值為think的用戶數(shù)據(jù)? $User->where('status=1?AND?name="think"')->find(); 即使?jié)M足條件的數(shù)據(jù)不止一條,find方法也只會(huì)返回第一條記錄。 如果要讀取某個(gè)字段的值,可以使用getField方法 示例如下:
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?獲取ID為3的用戶的昵稱? $nickname?=?$User->where('id=3')->getField('nickname'); 當(dāng)只有一個(gè)字段的時(shí)候,默認(rèn)返回一個(gè)值。
如果需要返回?cái)?shù)組,可以用:
$this->getField('id',true);?//?獲取id數(shù)組 如果傳入多個(gè)字段的話,默認(rèn)返回一個(gè)關(guān)聯(lián)數(shù)組:
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?獲取所有用戶的ID和昵稱列表? $list?=?$User->getField('id,nickname'); 返回的list是一個(gè)數(shù)組,鍵名是用戶的id, 鍵值是用戶的昵稱nickname。
如果傳入多個(gè)字段的名稱,例如:
$list?=?$User->getField('id,nickname,email'); 返回的是一個(gè)二維數(shù)組,類似select方法的返回結(jié)果,區(qū)別的是這個(gè)二維數(shù)組的鍵名是用戶的id(準(zhǔn)確的說(shuō)是getField方法的第一個(gè)字段名)。
如果我們傳入一個(gè)字符串分隔符:
$list?=?$User->getField('id,nickname,email',':'); 那么返回的結(jié)果就是一個(gè)數(shù)組,鍵名是用戶id,鍵值是 nickname:email的輸出字符串。
getField方法的sepa參數(shù)還可以支持限制數(shù)量,例如:
$this->getField('id,name',5);?//?限制返回5條記錄 $this->getField('id',3);?//?獲取id數(shù)組?限制3條記錄 可以配合使用order方法使用。
更新(Update) 在ThinkPHP中使用save方法更新數(shù)據(jù)庫(kù),并且也支持連貫操作的使用。
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?要修改的數(shù)據(jù)對(duì)象屬性賦值 $data['name']?=?'ThinkPHP'; $data['email']?=?'ThinkPHP@gmail.com'; $User->where('id=5')->save($data);?//?根據(jù)條件保存修改的數(shù)據(jù) 為了保證數(shù)據(jù)庫(kù)的安全,避免出錯(cuò)更新整個(gè)數(shù)據(jù)表,如果沒(méi)有任何更新條件,數(shù)據(jù)對(duì)象本身也不包含主鍵字段的話,save方法不會(huì)更新任何數(shù)據(jù)庫(kù)的記錄。 因此下面的代碼不會(huì)更改數(shù)據(jù)庫(kù)的任何記錄 $User->save($data);? 除非使用下面的方式: $User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?要修改的數(shù)據(jù)對(duì)象屬性賦值 $data['id']?=?5; $data['name']?=?'ThinkPHP'; $data['email']?=?'ThinkPHP@gmail.com'; $User->save($data);?//?根據(jù)條件保存修改的數(shù)據(jù) 如果id是數(shù)據(jù)表的主鍵的話,系統(tǒng)自動(dòng)會(huì)把主鍵的值作為更新條件來(lái)更新其他字段的值。 還有一種方法是通過(guò)create或者data方法創(chuàng)建要更新的數(shù)據(jù)對(duì)象,然后進(jìn)行保存操作,這樣save方法的參數(shù)可以不需要傳入。 $User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?要修改的數(shù)據(jù)對(duì)象屬性賦值 $data['name']?=?'ThinkPHP'; $data['email']?=?'ThinkPHP@gmail.com'; $User->where('id=5')->data($data)->save();?//?根據(jù)條件保存修改的數(shù)據(jù) 使用create方法的例子: $User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?根據(jù)表單提交的POST數(shù)據(jù)創(chuàng)建數(shù)據(jù)對(duì)象 $User->create(); $User->save();?//?根據(jù)條件保存修改的數(shù)據(jù) 如果只是更新個(gè)別字段的值,可以使用setField方法。 使用示例: $User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?更改用戶的name值 $User->?where('id=5')->setField('name','ThinkPHP'); setField方法支持同時(shí)更新多個(gè)字段,只需要傳入數(shù)組即可,例如: $User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?更改用戶的name和email的值 $data?=?array('name'=>'ThinkPHP','email'=>'ThinkPHP@gmail.com'); $User->?where('id=5')->setField($data); 而對(duì)于統(tǒng)計(jì)字段(通常指的是數(shù)字類型)的更新,系統(tǒng)還提供了setInc和setDec方法。 $User?=?M("User");?//?實(shí)例化User對(duì)象 $User->where('id=5')->setInc('score',3);?//?用戶的積分加3 $User->where('id=5')->setInc('score');?//?用戶的積分加1 $User->where('id=5')->setDec('score',5);?//?用戶的積分減5 $User->where('id=5')->setDec('score');?//?用戶的積分減1 刪除(Delete) 在ThinkPHP中使用delete方法刪除數(shù)據(jù)庫(kù)中的記錄。 示例如下: $User?=?M("User");?//?實(shí)例化User對(duì)象 $User->where('id=5')->delete();?//?刪除id為5的用戶數(shù)據(jù) $User->where('status=0')->delete();?//?刪除所有狀態(tài)為0的用戶數(shù)據(jù) delete方法可以用于刪除單個(gè)或者多個(gè)數(shù)據(jù),主要取決于刪除條件,也就是where方法的參數(shù),也可以用order和limit方法來(lái)限制要?jiǎng)h除的個(gè)數(shù),例如: //?刪除所有狀態(tài)為0的5?個(gè)用戶數(shù)據(jù)?按照創(chuàng)建時(shí)間排序 $User->where('status=0')->order('create_time')->limit('5')->delete();? 可參見(jiàn):http://doc.thinkphp.cn/manual/curd.html
13. ActiveRecord ThinkPHP實(shí)現(xiàn)了ActiveRecords模式的ORM模型,采用了非標(biāo)準(zhǔn)的ORM模型:表映射到類,記錄映射到對(duì)象。 下面我們用AR模式來(lái)?yè)Q一種方式重新完成CURD操作。
一、創(chuàng)建數(shù)據(jù) $User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?然后直接給數(shù)據(jù)對(duì)象賦值 $User->name?=?'ThinkPHP'; $User->email?=?'ThinkPHP@gmail.com'; ?//?把數(shù)據(jù)對(duì)象添加到數(shù)據(jù)庫(kù) $User->add(); 如果使用了create方法創(chuàng)建數(shù)據(jù)對(duì)象的話,仍然可以在創(chuàng)建完成后進(jìn)行賦值 $User?=?D("User"); $User->create();?//?創(chuàng)建User數(shù)據(jù)對(duì)象,默認(rèn)通過(guò)表單提交的數(shù)據(jù)進(jìn)行創(chuàng)建 ?//?增加或者更改其中的屬性 $User->status?=?1; $User->create_time?=?time(); ?//?把數(shù)據(jù)對(duì)象添加到數(shù)據(jù)庫(kù) $User->add();? 二、查詢記錄 假如我們要查詢主鍵為8的某個(gè)用戶記錄,如果按照之前的方式:
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?查找id為8的用戶數(shù)據(jù) $User->where('id=8')->find(); 用AR模式的話可以直接寫成: $User->find(8); 如果要根據(jù)某個(gè)字段查詢,例如查詢姓名為ThinkPHP的可以用: $User?=?M("User");?//?實(shí)例化User對(duì)象 $User->getByName("ThinkPHP"); 如果要查詢數(shù)據(jù)集,可以直接使用: ?//?查找主鍵為1、3、8的多個(gè)數(shù)據(jù) $userList?=?$User->select('1,3,8');? 三、更新記錄 在完成查詢后,可以直接修改數(shù)據(jù)對(duì)象然后保存到數(shù)據(jù)庫(kù)。 $User->find(1);?//?查找主鍵為1的數(shù)據(jù) $User->name?=?'TOPThink';?//?修改數(shù)據(jù)對(duì)象 $User->save();?//?保存當(dāng)前數(shù)據(jù)對(duì)象 上面這種方式僅僅是示例,不代表保存操作之前一定要先查詢。因?yàn)橄旅娴姆绞狡鋵?shí)是等效的: $User->id?=?1; $User->name?=?'TOPThink';?//?修改數(shù)據(jù)對(duì)象 $User->save();?//?保存當(dāng)前數(shù)據(jù)對(duì)象 四、刪除記錄 可以刪除當(dāng)前查詢的數(shù)據(jù)對(duì)象 $User->find(2); $User->delete();?//?刪除當(dāng)前的數(shù)據(jù)對(duì)象 或者直接根據(jù)主鍵進(jìn)行刪除 $User->delete(8);?//?刪除主鍵為8的數(shù)據(jù) $User->delete('5,6');?//?刪除主鍵為5、6的多個(gè)數(shù)據(jù) 14. 自動(dòng)驗(yàn)證 大多數(shù)情況下面,數(shù)據(jù)對(duì)象是由表單提交的$_POST數(shù)據(jù)創(chuàng)建。需要使用系統(tǒng)的自動(dòng)驗(yàn)證功能,只需要在Model類里面定義$_validate屬性,是由多個(gè)驗(yàn)證因子組成的二維數(shù)組。 驗(yàn)證因子格式: array(驗(yàn)證字段,驗(yàn)證規(guī)則,錯(cuò)誤提示,[驗(yàn)證條件,附加規(guī)則,驗(yàn)證時(shí)間]) 示例 :protected?$_validate?=?array( ????array('verify','require','驗(yàn)證碼必須!'),?//默認(rèn)情況下用正則進(jìn)行驗(yàn)證 ????array('name','','帳號(hào)名稱已經(jīng)存在!',0,'unique',1),?//?在新增的時(shí)候驗(yàn)證name字段是否唯一 ????array('value',array(1,2,3),'值的范圍不正確!',2,'in'),?//?當(dāng)值不為空的時(shí)候判斷是否在一個(gè)范圍內(nèi) ????array('repassword','password','確認(rèn)密碼不正確',0,'confirm'),?//?驗(yàn)證確認(rèn)密碼是否和密碼一致 ????array('password','checkPwd','密碼格式不正確',0,'function'),?//?自定義函數(shù)驗(yàn)證密碼格式 ?); 當(dāng)使用系統(tǒng)的create方法創(chuàng)建數(shù)據(jù)對(duì)象的時(shí)候會(huì)自動(dòng)進(jìn)行數(shù)據(jù)驗(yàn)證操作,代碼示例: $User?=?D("User");?//?實(shí)例化User對(duì)象 ?if?(!$User->create()){ ????//?如果創(chuàng)建失敗?表示驗(yàn)證沒(méi)有通過(guò)?輸出錯(cuò)誤提示信息 ?exit($User->getError()); ?}else{ ????//?驗(yàn)證通過(guò)?可以進(jìn)行其他數(shù)據(jù)操作 ?} 通常來(lái)說(shuō),每個(gè)數(shù)據(jù)表對(duì)應(yīng)的驗(yàn)證規(guī)則是相對(duì)固定的,但是有些特殊的情況下面可能會(huì)改變驗(yàn)證規(guī)則,我們可以動(dòng)態(tài)的改變驗(yàn)證規(guī)則來(lái)滿足不同條件下面的驗(yàn)證: $User?=?D("User");?//?實(shí)例化User對(duì)象 $validate?=?array( ????array('verify','require','驗(yàn)證碼必須!'),?//?僅僅需要進(jìn)行驗(yàn)證碼的驗(yàn)證 ?); $User->?setProperty("_validate",$validate); $result?=?$User->create(); ?if?(!$result){ ????//?如果創(chuàng)建失敗?表示驗(yàn)證沒(méi)有通過(guò)?輸出錯(cuò)誤提示信息 ????exit($User->getError()); ?}else{ ????//?驗(yàn)證通過(guò)?可以進(jìn)行其他數(shù)據(jù)操作 ?} 多字段驗(yàn)證 自動(dòng)驗(yàn)證功能中的function和callback規(guī)則可以支持多字段。
例子:
protected?$_validate?=?array( ????array('user_id,good_id',?'checkIfOrderToday',?'今天已經(jīng)購(gòu)買過(guò),請(qǐng)明天再來(lái)',?1,'callback',?1), ?); ?protected?function?checkIfOrderToday($data){ ????$map?=?$data; ????$map['ctime']?=?array(array('gt',[開(kāi)始時(shí)間]),?array('lt',?[結(jié)束時(shí)間])); ????if($this->where($map)->find()) ????????return?false; ????else ????????return?true; ?} 批量驗(yàn)證 新版支持?jǐn)?shù)據(jù)的批量驗(yàn)證功能,只需要在模型類里面設(shè)置patchValidate屬性為true( 默認(rèn)為false),設(shè)置批處理驗(yàn)證后,getError() 方法返回的錯(cuò)誤信息是一個(gè)數(shù)組,返回格式是:
array("字段名1"=>"錯(cuò)誤提示1","字段名2"=>"錯(cuò)誤提示2"...?) 前端可以根據(jù)需要需要自行處理。
手動(dòng)驗(yàn)證 3.1版本開(kāi)始,可以使用validate方法實(shí)現(xiàn)動(dòng)態(tài)和批量手動(dòng)驗(yàn)證,例如:$this->validate($validate)->create(); 其中$validate變量的規(guī)范和_validate屬性的定義規(guī)則一致,而且還可以支持函數(shù)調(diào)用(由于PHP本身的限制,在類的屬性定義中不能調(diào)用函數(shù))。 通過(guò)這一改進(jìn),以前需要支持?jǐn)?shù)據(jù)自動(dòng)驗(yàn)證,必須定義模型類的情況已經(jīng)不再出現(xiàn),你完全可以通過(guò)M方法實(shí)例化模型類后使用動(dòng)態(tài)設(shè)置完成自動(dòng)驗(yàn)證操作。 另外還有一個(gè)check方法,用于對(duì)單個(gè)數(shù)據(jù)的手動(dòng)驗(yàn)證,支持部分自動(dòng)驗(yàn)證的規(guī)則,用法如下: ?check('驗(yàn)證數(shù)據(jù)','驗(yàn)證規(guī)則','驗(yàn)證類型')? 驗(yàn)證類型支持 in between equal length regex expire ip_allow ip_deny,默認(rèn)為regex? 結(jié)果返回布爾值 $model->check($value,'email');? $model->check($value,'1,2,3','in'); 可參見(jiàn): http://doc.thinkphp.cn/manual/auto_validate.html
15. 命名范圍 首先定義_scope屬性:
class?NewsModel?extends?Model?{ ????protected?$_scope?=?array( ????????//?命名范圍normal ????????'normal'=>array( ????????????'where'=>array('status'=>1), ????????), ????????//?命名范圍latest ????????'latest'=>array( ????????????'order'=>'create_time?DESC', ????????????'limit'=>10, ????????), ????); ?} _scope屬性是一個(gè)數(shù)組,每個(gè)數(shù)組項(xiàng)表示定義一個(gè)命名范圍。 屬性定義完成后,接下來(lái)就是使用
scope方法 進(jìn)行命名范圍的調(diào)用了,每調(diào)用一個(gè)命名范圍,就相當(dāng)于執(zhí)行了命名范圍中定義的相關(guān)操作選項(xiàng)。
調(diào)用某個(gè)命名范圍 最簡(jiǎn)單的調(diào)用方式就直接調(diào)用某個(gè)命名范圍,例如: $Model->scope('normal')->select(); $Model->scope('latest')->select(); 生成的SQL語(yǔ)句分別是: SELECT?*?FROM?think_news?WHERE?status=1 SELECT?*?FROM?think_news?ORDER?BY?create_time?DESC?LIMIT?10 調(diào)用多個(gè)命名范圍 也可以支持同時(shí)調(diào)用多個(gè)命名范圍定義,例如:
$Model->scope('normal')->scope('latest')->select(); 或者簡(jiǎn)化為:
$Model->scope('normal,latest')->select(); 生成的SQL都是:
SELECT?*?FROM?think_news?WHERE?status=1?ORDER?BY?create_time?DESC?LIMIT?10 如果兩個(gè)命名范圍的定義存在沖突,則后面調(diào)用的命名范圍定義會(huì)覆蓋前面的相同屬性的定義。
默認(rèn)命名范圍 系統(tǒng)支持默認(rèn)命名范圍功能,如果你定義了一個(gè)default命名范圍,例如: ????protected?$_scope?=?array( ????????//?默認(rèn)的命名范圍 ????????'default'=>array( ????????????'where'=>array('status'=>1), ????????????'limit'=>10, ????????), ????); 那么調(diào)用default命名范圍可以直接使用: $Model->scope()->select(); 命名范圍調(diào)整 如果你需要在normal命名范圍的基礎(chǔ)上增加額外的調(diào)整,可以使用: $Model->scope('normal',array('limit'=>5))->select(); 生成的SQL語(yǔ)句是: SELECT?*?FROM?think_news?WHERE?status=1?LIMIT?5 當(dāng)然,也可以在兩個(gè)命名范圍的基礎(chǔ)上進(jìn)行調(diào)整,例如: $Model->scope('normal,latest',array('limit'=>5))->select(); 生成的SQL是: SELECT?*?FROM?think_news?WHERE?status=1?ORDER?BY?create_time?DESC?LIMIT?5 自定義命名范圍 又或者,干脆不用任何現(xiàn)有的命名范圍,我直接傳入一個(gè)命名范圍:
$Model->scope(array('field'=>'id,title','limit'=>5,'where'=>'status=1','order'=>'create_time?DESC'))->select(); 這樣,生成的SQL變成:
SELECT?id,title?FROM?think_news?WHERE?status=1?ORDER?BY?create_time?DESC?LIMIT?5 與連貫操作混合使用 命名范圍一樣可以和之前的連貫操作混合使用,例如定義了命名范圍_scope屬性:
protected?$_scope?=?array( ????'normal'=>array( ????????'where'=>array('status'=>1), ????????'field'=>'id,title', ????????'limit'=>10, ????), ?); 然后在使用的時(shí)候,可以這樣調(diào)用:
$Model->scope('normal')->limit(8)->order('id?desc')->select(); 這樣,生成的SQL變成:
SELECT?id,title?FROM?think_news?WHERE?status=1?ORDER?BY?id?desc?LIMIT?8 如果定義的命名范圍和連貫操作的屬性有沖突,則后面調(diào)用的會(huì)覆蓋前面的。
如果是這樣調(diào)用:
$Model->limit(8)->scope('normal')->order('id?desc')->select(); 生成的SQL則是:
SELECT?id,title?FROM?think_news?WHERE?status=1?ORDER?BY?id?desc?LIMIT?10 命名范圍功能的優(yōu)勢(shì)在于可以一次定義多次調(diào)用,并且在項(xiàng)目中也能起到分工配合的規(guī)范,避免開(kāi)發(fā)人員在寫CURD操作的時(shí)候出現(xiàn)問(wèn)題,項(xiàng)目經(jīng)理只需要合理的規(guī)劃命名范圍即可。
16. 自動(dòng)完成 在Model類定義 $_auto 屬性,可以完成數(shù)據(jù)自動(dòng)處理功能,用來(lái)處理默認(rèn)值、數(shù)據(jù)過(guò)濾以及其他系統(tǒng)寫入字段。$_auto屬性是由多個(gè)填充因子組成的數(shù)組。 填充因子格式: array(填充字段,填充內(nèi)容,[填充條件,附加規(guī)則]) 示例 :
protected?$_auto?=?array?(? ????array('status','1'),??//?新增的時(shí)候把status字段設(shè)置為1 ????array('password','md5',1,'function')?,?//?對(duì)password字段在新增的時(shí)候使md5函數(shù)處理 ????array('name','getName',1,'callback'),?//?對(duì)name字段在新增的時(shí)候回調(diào)getName方法 ????array('create_time','time',2,'function'),?//?對(duì)create_time字段在更新的時(shí)候?qū)懭氘?dāng)前時(shí)間戳 ?); 使用自動(dòng)填充可能會(huì)覆蓋表單提交項(xiàng)目。其目的是為了防止表單非法提交字段。使用Model類的create方法創(chuàng)建數(shù)據(jù)對(duì)象的時(shí)候會(huì)自動(dòng)進(jìn)行表單數(shù)據(jù)處理。
和自動(dòng)驗(yàn)證一樣,自動(dòng)完成機(jī)制需要使用create方法才能生效。并且,也可以在操作方法中動(dòng)態(tài)的更改自動(dòng)完成的規(guī)則。 $auto?=?array?(? ????array('password','md5',1,'function')?//?對(duì)password字段在新增的時(shí)候使md5函數(shù)處理 ?); $User->?setProperty("_auto",$auto); $User->create(); 動(dòng)態(tài)設(shè)置自動(dòng)完成規(guī)則 還可以使用auto方法動(dòng)態(tài)設(shè)置自動(dòng)完成規(guī)則,例如:
$this->auto($auto)->create(); 其中$auto變量的規(guī)范和_auto屬性的定義規(guī)則一致,而且還可以支持函數(shù)調(diào)用(由于PHP本身的限制,在類的屬性定義中不能調(diào)用函數(shù))。
通過(guò)這一改進(jìn),以前需要支持?jǐn)?shù)據(jù)自動(dòng)完成,必須定義模型類的情況已經(jīng)不再出現(xiàn),你完全可以通過(guò)M方法實(shí)例化模型類后使用動(dòng)態(tài)設(shè)置完成自動(dòng)完成操作。
17. 查詢語(yǔ)言 查詢方式 ThinkPHP可以支持直接使用字符串作為查詢條件,但是大多數(shù)情況推薦使用索引數(shù)組或者對(duì)象來(lái)作為查詢條件,因?yàn)闀?huì)更加安全。一、使用字符串作為查詢條件 這是最傳統(tǒng)的方式,但是安全性不高,例如: $User?=?M("User");?//?實(shí)例化User對(duì)象 $User->where('type=1?AND?status=1')->select();? 最后生成的SQL語(yǔ)句是 SELECT * FROM think_user WHERE type=1 AND status=1 二、使用數(shù)組作為查詢條件 $User?=?M("User");?//?實(shí)例化User對(duì)象 $condition['name']?=?'thinkphp'; $condition['status']?=?1; ?//?把查詢條件傳入查詢方法 $User->where($condition)->select();? 最后生成的SQL語(yǔ)句是
SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
如果進(jìn)行多字段查詢,那么字段之間的默認(rèn)邏輯關(guān)系是 邏輯與 AND,但是用下面的規(guī)則可以更改默認(rèn)的邏輯判斷,通過(guò)使用 _logic 定義查詢邏輯:
$User?=?M("User");?//?實(shí)例化User對(duì)象 $condition['name']?=?'thinkphp'; $condition['account']?=?'thinkphp'; $condition['_logic']?=?'OR'; ?//?把查詢條件傳入查詢方法 $User->where($condition)->select();? 最后生成的SQL語(yǔ)句是
SELECT * FROM think_user WHERE `name`='thinkphp' OR `account`='thinkphp'
三、使用對(duì)象方式來(lái)查詢 ?(這里以stdClass內(nèi)置對(duì)象為例)
$User?=?M("User");?//?實(shí)例化User對(duì)象 ?//?定義查詢條件 $condition?=?new?stdClass();? $condition->name?=?'thinkphp';? $condition->status=?1;? $User->where($condition)->select();? 最后生成的SQL語(yǔ)句和上面一樣
SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
使用對(duì)象方式查詢和使用數(shù)組查詢的效果是相同的,并且是可以互換的,大多數(shù)情況下,我們建議采用數(shù)組方式更加高效,后面我們會(huì)以數(shù)組方式為例來(lái)講解具體的查詢語(yǔ)言用法。
表達(dá)式查詢 上面的查詢條件僅僅是一個(gè)簡(jiǎn)單的相等判斷,可以使用查詢表達(dá)式支持更多的SQL查詢語(yǔ)法,并且可以用于數(shù)組或者對(duì)象方式的查詢(下面僅以數(shù)組方式為例說(shuō)明),查詢表達(dá)式的使用格式:
$map['字段名'] = array('表達(dá)式','查詢條件');
表達(dá)式不分大小寫,支持的查詢表達(dá)式有下面幾種,分別表示的含義是:
表達(dá)式含義 EQ 等于(=) NEQ 不等于(<>) GT 大于(>) EGT 大于等于(>=) LT 小于(<) ELT 小于等于(<=) LIKE 模糊查詢 [NOT]?BETWEEN (不在)區(qū)間查詢 [NOT]?IN (不在)IN?查詢 EXP 表達(dá)式查詢,支持SQL語(yǔ)法
快捷查詢 新版增加了快捷查詢方式,可以進(jìn)一步簡(jiǎn)化查詢條件的寫法,例如:
一、實(shí)現(xiàn)不同字段相同的查詢條件 $User?=?M("User");?//?實(shí)例化User對(duì)象 $map['name|title']?=?'thinkphp'; ?//?把查詢條件傳入查詢方法 $User->where($map)->select();? 查詢條件就變成?name=?'thinkphp' OR title = 'thinkphp'
二、實(shí)現(xiàn)不同字段不同的查詢條件 $User?=?M("User");?//?實(shí)例化User對(duì)象 $map['status&title']?=array('1','thinkphp','_multi'=>true); ?//?把查詢條件傳入查詢方法 $User->where($map)->select();? '_multi'=>true必須加在數(shù)組的最后,表示當(dāng)前是多條件匹配,這樣查詢條件就變成?status=?1 AND title = 'thinkphp' ,查詢字段支持更多的,例如:
$map['status&score&title']?=array('1',array('gt','0'),'thinkphp','_multi'=>true);
查詢條件就變成?status=?1 AND score >0 AND title = 'thinkphp'
注意:快捷查詢方式中“|”和“&”不能同時(shí)使用。
區(qū)間查詢 ThinkPHP支持對(duì)某個(gè)字段的區(qū)間查詢,例如:
$map['id']?=?array(array('gt',1),array('lt',10))?; 得到的查詢條件是:?(`id` > 1) AND (`id` < 10)
$map['id']?=?array(array('gt',3),array('lt',10),?'or')?; 得到的查詢條件是: (`id` > 3) OR (`id` < 10)
$map['id']??=?array(array('neq',6),array('gt',3),'and');? 得到的查詢條件是:(`id` != 6) AND (`id` > 3)
最后一個(gè)可以是AND、 OR或者 XOR運(yùn)算符,如果不寫,默認(rèn)是AND運(yùn)算。
組合查詢 組合查詢的主體還是采用數(shù)組方式查詢,只是加入了一些特殊的查詢支持,包括字符串模式查詢(_string)、復(fù)合查詢(_complex)、請(qǐng)求字符串查詢(_query),混合查詢中的特殊查詢每次查詢只能定義一個(gè),由于采用數(shù)組的索引方式,索引相同的特殊查詢會(huì)被覆蓋。
一、字符串模式查詢 (采用_string 作為查詢條件)
數(shù)組條件還可以和字符串條件混合使用,例如:
$User?=?M("User");?//?實(shí)例化User對(duì)象 $map['id']?=?array('neq',1); $map['name']?=?'ok'; $map['_string']?=?'status=1?AND?score>10'; $User->where($map)->select();? 最后得到的查詢條件就成了:
( `id` != 1 ) AND ( `name` = 'ok' ) AND ( status=1 AND score>10 )
二、請(qǐng)求字符串查詢方式 請(qǐng)求字符串查詢是一種類似于URL傳參的方式,可以支持簡(jiǎn)單的條件相等判斷。
$map['id']?=?array('gt','100'); $map['_query']?=?'status=1&score=100&_logic=or'; 得到的查詢條件是:`id`>100 AND (`status` = '1' OR `score` = '100')
三、復(fù)合查詢 $where['name']??=?array('like',?'%thinkphp%'); $where['title']??=?array('like','%thinkphp%'); $where['_logic']?=?'or'; $map['_complex']?=?$where; $map['id']??=?array('gt',1); 查詢條件是?
(?id?>?1)?AND?( (?name?like?'%thinkphp%')?OR?(?title?like?'%thinkphp%') )
統(tǒng)計(jì)查詢 方法說(shuō)明 Count 統(tǒng)計(jì)數(shù)量,參數(shù)是要統(tǒng)計(jì)的字段名(可選) Max 獲取最大值,參數(shù)是要統(tǒng)計(jì)的字段名(必須) Min 獲取最小值,參數(shù)是要統(tǒng)計(jì)的字段名(必須) Avg 獲取平均值,參數(shù)是要統(tǒng)計(jì)的字段名(必須) Sum 獲取總分,參數(shù)是要統(tǒng)計(jì)的字段名(必須)
用法示例:
$User?=?M("User");?//?實(shí)例化User對(duì)象 獲取用戶數(shù):
$userCount?=?$User->count(); 或者根據(jù)字段統(tǒng)計(jì):
$userCount?=?$User->count("id"); 獲取用戶的最大積分:
$maxScore?=?$User->max('score'); 獲取積分大于0的用戶的最小積分:
$minScore?=?$User->where('score>0')->min('score'); 獲取用戶的平均積分:
$avgScore?=?$User->avg('score'); 統(tǒng)計(jì)用戶的總成績(jī):
$sumScore?=?$User->sum('score'); 并且所有的統(tǒng)計(jì)查詢均支持連貫操作的使用。
定位查詢 ThinkPHP支持定位查詢,但是要求當(dāng)前模型必須繼承高級(jí)模型類才能使用,可以使用getN方法直接返回查詢結(jié)果中的某個(gè)位置的記錄。例如:? ?獲取符合條件的第3條記錄: $User->where('score>0')->order('score?desc')->getN(2); ?獲取符合條件的最后第二條記錄: $User->?where('score>80')->order('score?desc')->getN(-2); ?獲取第一條記錄: $User->where('score>80')->order('score?desc')->first(); ?獲取最后一條記錄: $User->where('score>80')->order('score?desc')->last(); SQL查詢 1、query方法 query??執(zhí)行SQL查詢操作 用法 query($sql,$parse=false) 參數(shù) query(必須):要查詢的SQL語(yǔ)句 parse(可選):是否需要解析SQL 返回值 如果數(shù)據(jù)非法或者查詢錯(cuò)誤則返回false
否則返回查詢結(jié)果數(shù)據(jù)集(同select方法)
使用示例:
$Model?=?new?Model()?//?實(shí)例化一個(gè)model對(duì)象?沒(méi)有對(duì)應(yīng)任何數(shù)據(jù)表 $Model->query("select?*?from?think_user?where?status=1"); 如果你當(dāng)前采用了分布式數(shù)據(jù)庫(kù),并且設(shè)置了讀寫分離的話,query方法始終是在讀服務(wù)器執(zhí)行,因此query方法對(duì)應(yīng)的都是讀操作,而不管你的SQL語(yǔ)句是什么。
2、execute方法 execute用于更新和寫入數(shù)據(jù)的sql操作 用法 execute($sql,$parse=false) 參數(shù) query(必須):要執(zhí)行的SQL語(yǔ)句 parse(可選):是否需要解析SQL 返回值 如果數(shù)據(jù)非法或者查詢錯(cuò)誤則返回false? 否則返回影響的記錄數(shù)
使用示例:
$Model?=?new?Model()?//?實(shí)例化一個(gè)model對(duì)象?沒(méi)有對(duì)應(yīng)任何數(shù)據(jù)表 $Model->execute("update?think_user?set?name='thinkPHP'?where?status=1"); 如果你當(dāng)前采用了分布式數(shù)據(jù)庫(kù),并且設(shè)置了讀寫分離的話,execute方法始終是在寫服務(wù)器執(zhí)行,因此execute方法對(duì)應(yīng)的都是寫操作,而不管你的SQL語(yǔ)句是什么。
3、其他技巧 自動(dòng)獲取當(dāng)前表名
通常使用原生SQL需要手動(dòng)加上當(dāng)前要查詢的表名,如果你的表名以后會(huì)變化的話,那么就需要修改每個(gè)原生SQL查詢的sql語(yǔ)句了,針對(duì)這個(gè)情況,系統(tǒng)還提供了一個(gè)小的技巧來(lái)幫助解決這個(gè)問(wèn)題。
例如:
$model?=?M("User"); $model->query('select?*?from?__TABLE__?where?status>1'); 我們這里使用了__TABLE__ 這樣一個(gè)字符串,系統(tǒng)在解析的時(shí)候會(huì)自動(dòng)替換成當(dāng)前模型對(duì)應(yīng)的表名,這樣就可以做到即使模型對(duì)應(yīng)的表名有所變化,仍然不用修改原生的sql語(yǔ)句。
支持連貫操作和SQL解析 新版對(duì)query和execute兩個(gè)原生SQL操作方法增加第二個(gè)參數(shù)支持, 表示是否需要解析SQL (默認(rèn)為false 表示直接執(zhí)行sql ),如果設(shè)為true 則會(huì)解析SQL中的特殊字符串 (需要配合連貫操作)。 例如,支持 如下寫法: $model->table("think_user") ??????->where(array("name"=>"thinkphp")) ??????->field("id,name,email") ??????->query('select?%FIELD%?from?%TABLE%?%WHERE%',true); 其中query方法中的%FIELD%、%TABLE%和%WHERE%字符串會(huì)自動(dòng)替換為同名的連貫操作方法的解析結(jié)果SQL,支持的替換字符串包括: 替換字符串對(duì)應(yīng)連貫操作方法 %FIELD% field %TABLE% table %DISTINCT% distinct %WHERE% where %JOIN% join %GROUP% group %HAVING% having %ORDER% order %LIMIT% limit %UNION% union
動(dòng)態(tài)查詢 借助PHP5語(yǔ)言的特性,ThinkPHP實(shí)現(xiàn)了動(dòng)態(tài)查詢,包括下面幾種: 方法名說(shuō)明舉例 getBy 根據(jù)某個(gè)字段的值查詢數(shù)據(jù) 例如,getByName,getByEmail getFieldBy 根據(jù)某個(gè)字段查詢并返回某個(gè)字段的值 例如,getFieldByName top 獲取前多少條記錄(需要高級(jí)模型支持) 例如,top8,top12
一、getBy動(dòng)態(tài)查詢 該查詢方式針對(duì)數(shù)據(jù)表的字段進(jìn)行查詢。例如,User對(duì)象擁有id,name,email,address 等屬性,那么我們就可以使用下面的查詢方法來(lái)直接根據(jù)某個(gè)屬性來(lái)查詢符合條件的記錄。
$user?=?$User->getByName('liu21st'); $user?=?$User->getByEmail('liu21st@gmail.com'); $user?=?$User->getByAddress('中國(guó)深圳'); 暫時(shí)不支持多數(shù)據(jù)字段的動(dòng)態(tài)查詢方法,請(qǐng)使用find方法和select方法進(jìn)行查詢。
二、getFieldBy動(dòng)態(tài)查詢 針對(duì)某個(gè)字段查詢并返回某個(gè)字段的值,例如
$user?=?$User->getFieldByName('liu21st','id'); 表示根據(jù)用戶的name獲取用戶的id值。
三、top動(dòng)態(tài)查詢 ThinkPHP還提供了另外一種動(dòng)態(tài)查詢方式,就是獲取符合條件的前N條記錄(和定位查詢一樣,也要求當(dāng)前模型類必須繼承高級(jí)模型類后才能使用)。例如,我們需要獲取當(dāng)前用戶中積分大于0,積分最高的前5位用戶 :$User->?where('score>80')->order('score?desc')->top5(); 要獲取積分的前8位可以改成: $User->?where('score>80')->order('score?desc')->top8(); 子查詢 新版新增了子查詢支持,有兩種使用方式:
1、使用select方法 當(dāng)select方法的參數(shù)為false的時(shí)候,表示不進(jìn)行查詢只是返回構(gòu)建SQL,例如:
//?首先構(gòu)造子查詢SQL? $subQuery?=?$model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->select(false);? 2、使用buildSql方法 $subQuery?=?$model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->buildSql();? 調(diào)用buildSql方法后不會(huì)進(jìn)行實(shí)際的查詢操作,而只是生成該次查詢的SQL語(yǔ)句(為了避免混淆,會(huì)在SQL兩邊加上括號(hào)),然后我們直接在后續(xù)的查詢中直接調(diào)用。
//?利用子查詢進(jìn)行查詢? $model->table($subQuery.'?a')->where()->order()->select()? 構(gòu)造的子查詢SQL可用于TP的連貫操作方法,例如table where等。
18. 查詢鎖定 ThinkPHP支持查詢或者更新的鎖定,只需要在查詢或者更新之前使用lock方法即可。 查詢鎖定使用: $list?=?$User->lock(true)->where('status=1')->order('create_time')->limit(10)->select(); 更新鎖定使用: $list?=?$User->lock(true)->where('status=1')->data($data)->save(); 19. 字段排除 當(dāng)使用下面的字段排除方式查詢的時(shí)候
$Model->field('create_time,read_count,comment_count',true);? 第二個(gè)參數(shù)表示field方法采用的是排除機(jī)制,因此實(shí)際查詢的字段是除create_time,read_count,comment_count之外的其他數(shù)據(jù)表所有字段,最終要查詢的字段根據(jù)實(shí)際的數(shù)據(jù)表字段有所不同。
生成的SQL語(yǔ)句就變成了SELECT id,name,title,status FROM article
20. 事務(wù)支持 ThinkPHP提供了單數(shù)據(jù)庫(kù)的事務(wù)支持,如果要在應(yīng)用邏輯中使用事務(wù)。事務(wù)是針對(duì)數(shù)據(jù)庫(kù)本身的,所以可以跨模型操作的 。 例如:
//??在User模型中啟動(dòng)事務(wù) $User->startTrans(); ?//?進(jìn)行相關(guān)的業(yè)務(wù)邏輯操作 $Info?=?M("Info");?//?實(shí)例化Info對(duì)象 $Info->save($User);?//?保存用戶信息 ?if?(操作成功){ ????//?提交事務(wù) ????$User->commit();? ?}else{ ???//?事務(wù)回滾 ???$User->rollback();? ?} 注意:系統(tǒng)提供的事務(wù)操作方法必須有數(shù)據(jù)庫(kù)本身的支持,如果你的數(shù)據(jù)庫(kù)或者數(shù)據(jù)表類型不支持事務(wù),那么系統(tǒng)的事務(wù)操作是無(wú)效的。
21. 高級(jí)模型 http://doc.thinkphp.cn/manual/adv_model.html
22. 視圖模型 http://doc.thinkphp.cn/manual/view_model.html
23. 關(guān)聯(lián)模型 http://doc.thinkphp.cn/manual/relation_model.html
24. Mongo模型 http://doc.thinkphp.cn/manual/mongo_model.html
25. 動(dòng)態(tài)模型 你可以從基本模型切換到高級(jí)模型或者視圖模型,而當(dāng)前的數(shù)據(jù)不會(huì)丟失,并可以控制要傳遞的參數(shù)和動(dòng)態(tài)賦值。
要切換模型,可以使用: $User?=?M("User");?//?實(shí)例化User對(duì)象?是基礎(chǔ)模型類的實(shí)例 ?//?動(dòng)態(tài)切換到高級(jí)模型類?執(zhí)行top10查詢操作 $User->switchModel("Adv")->top10(); 上面的寫法也可以改成 $User?=?M("AdvModel:User");?//?實(shí)例化User對(duì)象?是基礎(chǔ)模型類的實(shí)例 $User->top10(); 如果要傳遞參數(shù),可以使用: $User?=?D("User");?//?實(shí)例化User對(duì)象?是基礎(chǔ)模型類的實(shí)例 ?//?動(dòng)態(tài)切換到視圖模型類?并傳入viewFields屬性 $UserView?=?$User->switchModel("View",array("viewFields")); 如果要?jiǎng)討B(tài)賦值,可以使用: $User?=?M("User");?//?實(shí)例化User對(duì)象?是基礎(chǔ)模型類的實(shí)例 ?//?動(dòng)態(tài)切換到關(guān)聯(lián)模型類?并傳入data屬性 $advUser?=?$User->switchModel("Relation"); ?//?或者在切換模型后再動(dòng)態(tài)賦值給新的模型 $advUser->setProperty("_link",$link); ?//?查找關(guān)聯(lián)數(shù)據(jù) $user?=?$advUser->relation(true)->find(1); 26. 虛擬模型 有些時(shí)候,我們建立模型類但又不需要進(jìn)行數(shù)據(jù)庫(kù)操作,僅僅是借助模型類來(lái)封裝一些業(yè)務(wù)邏輯,那么可以借助虛擬模型來(lái)完成。虛擬模型不會(huì)自動(dòng)連接數(shù)據(jù)庫(kù),因此也不會(huì)自動(dòng)檢測(cè)數(shù)據(jù)表和字段信息,有兩種方式可以定義虛擬模型:
第一種:繼承Model類 Class?UserModel?extends?Model?{ ????Protected?$autoCheckFields?=?false; ?} 設(shè)置autoCheckFields屬性為false后,就會(huì)關(guān)閉字段信息的自動(dòng)檢測(cè),因?yàn)門hinkPHP采用的是惰性數(shù)據(jù)庫(kù)連接,只要你不進(jìn)行數(shù)據(jù)庫(kù)查詢操作,是不會(huì)連接數(shù)據(jù)庫(kù)的。 1
第二種:不繼承Model類 Class?UserModel?{?} 這種方式下面自定義模型類就是一個(gè)單純的業(yè)務(wù)邏輯類,不能再使用模型的CURD操作方法,但是可以實(shí)例化其他的模型類進(jìn)行相關(guān)操作,也可以在需要的時(shí)候直接實(shí)例化Db類進(jìn)行數(shù)據(jù)庫(kù)操作。 3.1版本開(kāi)始,模型層(M)支持自定義分層。并且D方法,增加layer參數(shù),具體分層的M類仍然繼承Model類,用法示例:
實(shí)例化UserModel類(默認(rèn)的情況)
文件位于項(xiàng)目的Lib/Model/UserModel.class.php
D('User'); 實(shí)例化UserLogic類 實(shí)現(xiàn)Logic分層
文件位于項(xiàng)目的Lib/Logic/UserLogic.class.php
D('User','Logic'); 實(shí)例化UserService類,實(shí)現(xiàn)Service分層
文件位于項(xiàng)目的Lib/Service/UserService.class.php
D('User','Service'); 可以配置DEFAULT_M_LAYER修改默認(rèn)的模型層名稱(該參數(shù)默認(rèn)值為Model) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
視圖: ThinkPHP的視圖有兩個(gè)部分組成:View類和模板文件。Action控制器直接和View視圖類打交道,把要輸出的數(shù)據(jù)通過(guò)模板變量賦值的方式傳遞到視圖類,而具體的輸出工作則交由View視圖類來(lái)進(jìn)行,同時(shí)視圖類還和模板引擎進(jìn)行接口,包括完成布局渲染、輸出替換、頁(yè)面Trace等功能。
1. 模板定義 為了對(duì)模板文件更加有效的管理,ThinkPHP對(duì)模板文件進(jìn)行目錄劃分,默認(rèn)的模板文件定義規(guī)則是:
模板目錄/[分組名/][模板主題/]模塊名/操作名+模板后綴 模板目錄默認(rèn)是項(xiàng)目下面的Tpl, 當(dāng)定義分組的情況下,會(huì)按照分組名分開(kāi)子目錄,新版模板主題默認(rèn)是空(表示不啟用模板主題功能),模板主題功能是為了多模板切換而設(shè)計(jì)的,如果有多個(gè)模板主題的話,可以用
DEFAULT_THEME 參數(shù)設(shè)置默認(rèn)的模板主題名。
在每個(gè)模板主題下面,是以項(xiàng)目的模塊名為目錄,然后是每個(gè)模塊的具體操作模板文件,例如:
User模塊的add操作 對(duì)應(yīng)的模板文件就應(yīng)該是:
Tpl/User/add.html? 模板文件的默認(rèn)后綴的情況是.html,也可以通過(guò)
TMPL_TEMPLATE_SUFFIX 來(lái)配置成其他的。
如果項(xiàng)目啟用了模塊分組功能(假設(shè)User模塊屬于Home分組),那么默認(rèn)對(duì)應(yīng)的模板文件可能變成 :
Tpl/Home/User/add.html? 當(dāng)然,分組功能也提供了
TMPL_FILE_DEPR 參數(shù)來(lái)配置簡(jiǎn)化模板的目錄層次。
例如 TMPL_FILE_DEPR如果配置成“_”的話,默認(rèn)的模板文件就變成了:
Tpl/Home/User_add.html 正是因?yàn)橄到y(tǒng)有這樣一種模板文件自動(dòng)識(shí)別的規(guī)則,所以通常的display方法無(wú)需帶任何參數(shù)即可輸出對(duì)應(yīng)的模板。
2. 模板賦值 要在模板中輸出變量,必須在在Action類中把變量傳遞給模板,視圖類提供了assign方法對(duì)模板變量賦值,無(wú)論何種變量類型都統(tǒng)一使用assign賦值。
$this->assign('name',$value); ?//?下面的寫法是等效的 $this->name?=?$value; 系統(tǒng)只會(huì)輸出設(shè)定的變量,其它變量不會(huì)輸出,一定程度上保證了變量的安全性。
如果要同時(shí)輸出多個(gè)模板變量,可以使用下面的方式: $array['name']????=????'thinkphp'; $array['email']????=????'liu21st@gmail.com'; $array['phone']????=????'12335678'; $this->assign($array); 模板變量賦值后,怎么在模板文件中輸出,需要根據(jù)選擇的模板引擎來(lái)用不同的方法,如果使用的是內(nèi)置的模板引擎,請(qǐng)參考后面的模板指南部分。如果你使用的是PHP本身作為模板引擎的話 ,就可以直接在模板文件里面輸出了,如下: <?php? ????echo?$name.'['.$email.''.$phone.']'; 如果要獲得全部的模板變量,可以調(diào)用View類的get方法支持獲取全部模板變量的值,例如: $this->get('name');?//?獲取name模板變量的值 $this->get();?//?獲取所有模板賦值變量的值 3. 模板輸出 模板變量賦值后就需要調(diào)用模板文件來(lái)輸出相關(guān)的變量,模板調(diào)用通過(guò)display方法來(lái)實(shí)現(xiàn)。我們?cè)诓僮鞣椒ǖ淖詈笫褂?#xff1a;
$this->display(); 就可以輸出模板。
一、調(diào)用當(dāng)前模塊的其他操作模板 格式:display('操作名')
例如,假設(shè)當(dāng)前操作是User模塊下面的read操作,我們需要調(diào)用User模塊的edit操作模版,使用:
$this->display('edit');? 不需要寫模板文件的路徑和后綴。
二、調(diào)用其他模塊的操作模板 格式:display('模塊名:操作名') 例如,當(dāng)前是User模塊,我們需要調(diào)用Member模塊的read操作模版?,使用: $this->display('Member:read');? 三、調(diào)用其他主題的操作模板 格式:display('主題名:模塊名:操作名')
例如我們需要?調(diào)用Xp主題的User模塊的edit操作模版,使用:
$this->display('Xp:User:edit');? 這種方式需要指定模塊和操作名
四、直接全路徑輸出模板 格式:display('模板文件名')
例如,我們直接輸出當(dāng)前的Public目錄下面的menu.html模板文件,使用:?
$this->display('./Public/menu.html'); 這種方式需要指定模板路徑和后綴,這里的Public目錄是位于當(dāng)前項(xiàng)目入口文件位置下面。如果是其他的后綴文件,也支持直接輸出,例如:
$this->display('./Public/menu.tpl'); 只要./Public/menu.tpl是一個(gè)實(shí)際存在的模板文件。如果使用的是相對(duì)路徑的話,要注意當(dāng)前位置是相對(duì)于項(xiàng)目的入口文件,而不是模板目錄。
五、直接解析內(nèi)容 Action類的display方法如果傳入第四個(gè)參數(shù),表示不讀取模板文件而是直接解析內(nèi)容。例如: $this->assign('foo','ThinkPHP');? $this->show('Hello,?{$foo}!'); 會(huì)在頁(yè)面輸出: Hello,ThinkPHP!? 直接輸出的內(nèi)容仍然支持模板布局功能。 show方法也可以支持指定編碼和輸出格式,例如: $this->show($content,?'utf-8',?'text/xml');? 事實(shí)上,display方法還有其他的參數(shù)和用法。 有時(shí)候某個(gè)模板頁(yè)面我們需要輸出指定的編碼,而不是默認(rèn)的編碼,可以使用: $this->display('Member:read',?'gbk');? 或者輸出的模板文件不是text/html格式的,而是XML格式的,可以用: $this->display('Member:read',?'utf-8',?'text/xml');? 如果你的網(wǎng)站輸出編碼不是默認(rèn)的編碼,可以使用: 'DEFAULT_CHARSET'=>?'gbk'? 如果要輸出XML格式的,可以用: 'TMPL_CONTENT_TYPE'=>?'text/xml' 4. 模板替換 在進(jìn)行模板輸出之前,系統(tǒng)還會(huì)對(duì)渲染的模板結(jié)果進(jìn)行一些模板的特殊字符串替換操作,也就是實(shí)現(xiàn)了模板輸出的替換和過(guò)濾。模板替換適用于所有的模板引擎,包括原生的PHP模板。這個(gè)機(jī)制可以使得模板文件的定義更加方便,默認(rèn)的替換規(guī)則有:
../Public : 會(huì)被替換成當(dāng)前項(xiàng)目的公共模板目錄 通常是 /項(xiàng)目目錄/Tpl/當(dāng)前主題/Public/?
__TMPL__ : 會(huì)替換成項(xiàng)目的模板目錄 通常是 /項(xiàng)目目錄/Tpl/當(dāng)前主題/
(注:為了部署安全考慮,../Public和__TMPL__不再建議使用)
__PUBLIC__ :會(huì)被替換成當(dāng)前網(wǎng)站的公共目錄 通常是 /Public/
__ROOT__ : 會(huì)替換成當(dāng)前網(wǎng)站的地址(不含域名)?
__APP__ : 會(huì)替換成當(dāng)前項(xiàng)目的URL地址 (不含域名)
__GROUP__ :會(huì)替換成當(dāng)前分組的URL地址 (不含域名)
__URL__ : 會(huì)替換成當(dāng)前模塊的URL地址(不含域名)
__ACTION__ :會(huì)替換成當(dāng)前操作的URL地址 (不含域名)
__SELF__ : 會(huì)替換成當(dāng)前的頁(yè)面URL
注意這些特殊的字符串是嚴(yán)格區(qū)別大小寫的,并且這些特殊字符串的替換規(guī)則是可以更改或者增加的,我們只需要在項(xiàng)目配置文件中配置TMPL_PARSE_STRING就可以完成。如果有相同的數(shù)組索引,就會(huì)更改系統(tǒng)的默認(rèn)規(guī)則。例如:
'TMPL_PARSE_STRING'??=>array( ?????'__PUBLIC__'?=>?'/Common',?//?更改默認(rèn)的/Public?替換規(guī)則 ?????'__JS__'?=>?'/Public/JS/',?//?增加新的JS類庫(kù)路徑替換規(guī)則 ?????'__UPLOAD__'?=>?'/Uploads',?//?增加新的上傳路徑替換規(guī)則 ?) 有了模板替換規(guī)則后,頁(yè)面上所有的__PUBLIC__ 字符串都會(huì)被替換,那如果確實(shí)需要輸出__PUBLIC__ 字符串到模板呢,我們可以通過(guò)增加替換規(guī)則的方式,例如:
'TMPL_PARSE_STRING'??=>array( ?????'--PUBLIC--'?=>?'__PUBLIC__',?//?采用新規(guī)則輸出/Public字符串 ?) 這樣增加替換規(guī)則后,如果我們要輸出__PUBLIC__ 字符串,只需要在模板中添加--PUBLIC--,其他替換字符串的輸出方式類似。
5. 獲取內(nèi)容 有些時(shí)候我們不想直接輸出模板內(nèi)容,而是希望對(duì)內(nèi)容再進(jìn)行一些處理后輸出,就可以使用fetch方法來(lái)獲取解析后的模板內(nèi)容,在Action類里面使用:
$content?=?$this->fetch(); fetch的參數(shù)用法和Display方法基本一致,也可以使用:
$content?=?$this->fetch('Member:read');? 區(qū)別就在于display方法直接輸出模板文件渲染后的內(nèi)容,而fetch方法是返回模板文件渲染后的內(nèi)容。如何對(duì)返回的結(jié)果content進(jìn)行處理,完全由開(kāi)發(fā)人員自行決定了。這是模板替換的另外一種高級(jí)方式,比較靈活,而且不需要通過(guò)配置的方式。
注意,fetch方法仍然會(huì)執(zhí)行上面的模板替換操作。
6. 模板引擎 系統(tǒng)支持原生的PHP模板,而且本身內(nèi)置了一個(gè)基于XML的高效的編譯型模板引擎,系統(tǒng)默認(rèn)使用的模板引擎是內(nèi)置模板引擎,關(guān)于這個(gè)模板引擎的標(biāo)簽詳細(xì)使用可以參考模板指南部分。
內(nèi)置的模板引擎也可以直接支持在模板文件中采用PHP原生代碼和模板標(biāo)簽的混合使用,如果需要完全使用PHP本身作為模板引擎,可以配置:
'TMPL_ENGINE_TYPE'?=>'PHP' 可以達(dá)到最佳的效率。
如果你使用了其他的模板引擎,只需要設(shè)置TMPL_ENGINE_TYPE參數(shù)為相關(guān)的模板引擎名稱即可。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 模板引擎: ThinkPHP內(nèi)置了一個(gè)基于XML的性能卓越的模板引擎 ThinkTemplate,這是一個(gè)專門為ThinkPHP服務(wù)的內(nèi)置模板引擎。ThinkTemplate是一個(gè)使用了XML標(biāo)簽庫(kù)技術(shù)的編譯型模板引擎,支持兩種類型的模板標(biāo)簽,使用了動(dòng)態(tài)編譯和緩存技術(shù),而且支持自定義標(biāo)簽庫(kù)。 每個(gè)模板文件在執(zhí)行過(guò)程中都會(huì)生成一個(gè)編譯后的緩存文件,其實(shí)就是一個(gè)可以運(yùn)行的PHP文件。模板緩存默認(rèn)位于項(xiàng)目的Runtime/Cache目錄下面,以模板文件的md5編碼作為緩存文件名保存的。如果在模板標(biāo)簽的使用過(guò)程中發(fā)現(xiàn)問(wèn)題,可以嘗試通過(guò)查看模板緩存文件找到問(wèn)題所在。
內(nèi)置的模板引擎支持普通標(biāo)簽和XML標(biāo)簽方式兩種標(biāo)簽定義,分別用于不同的目的:
普通標(biāo)簽 主要用于輸出變量和做一些基本的操作 XML標(biāo)簽 主要完成一些邏輯判斷、控制和循環(huán)輸出,并且可擴(kuò)展
1. 變量輸出 如果我們?cè)贏ction中賦值了一個(gè)name模板變量:
$name?=?'ThinkPHP'; $this->assign('name',$name); 使用內(nèi)置的模板引擎輸出變量,只需要在模版文件使用:
{$name} 模板編譯后的結(jié)果就是
<?php?echo($name);?> 注意模板標(biāo)簽的{和$之間不能有任何的空格,否則標(biāo)簽無(wú)效。
普通標(biāo)簽?zāi)J(rèn)開(kāi)始標(biāo)記是 {,結(jié)束標(biāo)記是 }。也可以通過(guò)設(shè)置TMPL_L_DELIM和TMPL_R_DELIM進(jìn)行更改。例如,我們?cè)陧?xiàng)目配置文件中定義: 'TMPL_L_DELIM'=>'<{', ?'TMPL_R_DELIM'=>'}>', 那么,上面的變量輸出標(biāo)簽就應(yīng)該改成: <{$name}> 如果TMPL_VAR_IDENTIFY設(shè)置為array,那么
{$user.name}和{$user['name']}等效,也就是輸出數(shù)組變量。
如果TMPL_VAR_IDENTIFY設(shè)置為obj,那么
{$user.name}和{$user:name}等效,也就是輸出對(duì)象的屬性。
如果TMPL_VAR_IDENTIFY留空的話,系統(tǒng)會(huì)自動(dòng)判斷要輸出的變量是數(shù)組還是對(duì)象,這種方式會(huì)一定程度上影響效率,而且只支持二維數(shù)組和兩級(jí)對(duì)象屬性。
如果TMPL_VAR_IDENTIFY留空的話,系統(tǒng)會(huì)自動(dòng)判斷要輸出的變量是數(shù)組還是對(duì)象,這種方式會(huì)一定程度上影響效率,而且只支持二維數(shù)組和兩級(jí)對(duì)象屬性。 如果是多維數(shù)組或者多層對(duì)象屬性的輸出,可以使用下面的定義方式: {$user.sub.name}//?使用點(diǎn)語(yǔ)法輸出 或者使用 {$user['sub']['name']}//?輸出三維數(shù)組的值 ?{$user:sub:name}//?輸出對(duì)象的多級(jí)屬性 2. 系統(tǒng)變量 除了常規(guī)變量的輸出外,模板引擎還支持系統(tǒng)變量和系統(tǒng)常量、以及系統(tǒng)特殊變量的輸出。它們的輸出不需要事先賦值給某個(gè)模板變量。系統(tǒng)變量的輸出必須以$Think.打頭,并且仍然可以支持使用函數(shù)。常用的系統(tǒng)變量輸出包括下面: 用法含義例子 $Think.server 獲取$_SERVER {$Think.server.php_self} $Think.get 獲取$_GET {$Think.get.id} $Think.post 獲取$_POST {$Think.post.name} $Think.request 獲取$_REQUEST {$Think.request.user_id} $Think.cookie 獲取$_COOKIE {$Think.cookie.username} $Think.session 獲取$_SESSION {$Think.session.user_id} $Think.config 獲取系統(tǒng)配置參數(shù) {$Think.config.app_status} $Think.lang 獲取系統(tǒng)語(yǔ)言變量 {$Think.lang.user_type} $Think.const 獲取系統(tǒng)常量 {$Think.const.app_name}或{$Think.APP_NAME} $Think.env 獲取環(huán)境變量 {$Think.env.HOSTNAME} $Think.version 獲取框架版本號(hào) {$Think.version} $Think.now 獲取當(dāng)前時(shí)間 {$Think.now} $Think.template 獲取當(dāng)前模板 {$Think.template} $Think.ldelim 獲取模板左界定符 {$Think.ldelim} $Think.rdelim 獲取模板右界定符 {$Think.rdelim}
1、系統(tǒng)變量:包括server、session、post、get、request、cookie 2、系統(tǒng)常量:使用$Think.const 輸出 3、特殊變量:由ThinkPHP系統(tǒng)內(nèi)部定義的常量
4、配置參數(shù):輸出項(xiàng)目的配置參數(shù)值 {$Think.config.db_charset} 輸出的值和C('db_charset') 的返回結(jié)果是一樣的。 也可以輸出二維的配置參數(shù),例如: {$Think.config.user.user_name} 5、語(yǔ)言變量:輸出項(xiàng)目的當(dāng)前語(yǔ)言定義值
{$Think.lang.page_error} 輸出的值和L('page_error')的返回結(jié)果是一樣的。
3. 使用函數(shù) 用于模板標(biāo)簽的函數(shù)可以是PHP內(nèi)置函數(shù)或者是用戶自定義函數(shù),和smarty不同,用于模板的函數(shù)不需要特別的定義。 模板變量的函數(shù)調(diào)用格式為:
{$varname|function1|function2=arg1,arg2,###?} 說(shuō)明:?{ 和 $ 符號(hào)之間不能有空格 ,后面參數(shù)的空格就沒(méi)有問(wèn)題,###表示模板變量本身的參數(shù)位置?,支持多個(gè)函數(shù),函數(shù)之間支持空格?,支持函數(shù)屏蔽功能,在配置文件中可以配置禁止使用的函數(shù)列表?,支持變量解析緩存功能,重復(fù)變量字串不多次解析。
{$webTitle|md5|strtoupper|substr=0,3} 編譯后的PHP代碼就是: <?php?echo?(substr(strtoupper(md5($webTitle)),0,3));??> 注意函數(shù)的定義和使用順序的對(duì)應(yīng)關(guān)系,通常來(lái)說(shuō)函數(shù)的第一個(gè)參數(shù)就是前面的變量或者前一個(gè)函數(shù)調(diào)用的返回結(jié)果,如果你的變量并不是函數(shù)的第一個(gè)參數(shù),需要使用定位符號(hào),例如: {$create_time|date="y-m-d",###} 編譯后的PHP是: <?php?echo?(date("y-m-d",$create_time));??> 函數(shù)的使用沒(méi)有個(gè)數(shù)限制,但是可以允許配置TMPL_DENY_FUNC_LIST定義禁用函數(shù)列表,系統(tǒng)默認(rèn)禁用了exit和echo函數(shù),以防止破壞模板輸出,我們也可以增加額外的定義,例如:
TMPL_DENY_FUNC_LIST=>"echo,exit,halt" 多個(gè)函數(shù)之間使用半角逗號(hào)分隔即可。
并且還提供了在模板文件中直接調(diào)用函數(shù)的快捷方法,這種方式更加直接明了,而且無(wú)需通過(guò)模板變量,包括兩種方式:1、執(zhí)行函數(shù)并輸出返回值 : 格式:{:function(…)}? 例如,輸出U函數(shù)的返回值: {:U('User/insert')} 編譯后的PHP代碼是 <?php?echo?U('User/insert');?> 2、執(zhí)行函數(shù)但不輸出 : 格式:{~function(…)}? 例如,調(diào)用say_hello函數(shù):{~say_hello('ThinkPHP')} 編譯后的PHP代碼是: <?php?say_hello('ThinkPHP');?> 4. 默認(rèn)值輸出 如果輸出的模板變量沒(méi)有值,但是我們需要在顯示的時(shí)候賦予一個(gè)默認(rèn)值的話,可以使用default語(yǔ)法,格式:
{$變量|default="默認(rèn)值"}
這里的default不是函數(shù),而是系統(tǒng)的一個(gè)語(yǔ)法規(guī)則,例如:
{$user.nickname|default="這家伙很懶,什么也沒(méi)留下"} 對(duì)系統(tǒng)變量的輸出也可以支持默認(rèn)值,例如:
{$Think.post.name|default="名稱為空"} 默認(rèn)值支持Html語(yǔ)法。
5. 使用運(yùn)算符 內(nèi)置模板引擎包含了運(yùn)算符的支持,包括對(duì)“+”“ –” “*” “/”和“%”的支持。 在使用運(yùn)算符的時(shí)候,不再支持點(diǎn)語(yǔ)法和常規(guī)的函數(shù)用法,例如:
{$user.score+10}?是錯(cuò)誤的 ?{$user['score']+10}?是正確的 ?{$user['score']*$user['level']}?正確的 ?{$user['score']|myFun*10}?錯(cuò)誤的 ?{$user['score']+myFun($user['level'])}?正確的 6. 內(nèi)置標(biāo)簽 系統(tǒng)內(nèi)置標(biāo)簽庫(kù)的所有標(biāo)簽無(wú)需引入標(biāo)簽庫(kù)即可直接使用。XML標(biāo)簽有兩種,包括閉合標(biāo)簽和開(kāi)放標(biāo)簽,一個(gè)標(biāo)簽在定義的時(shí)候就已經(jīng)決定了是否是閉合標(biāo)簽還是開(kāi)放標(biāo)簽,不可混合使用,例如: 閉合標(biāo)簽: <include?file="read"?/> 開(kāi)放標(biāo)簽: <gt?name="name"?value="5">value</gt> 內(nèi)置支持的標(biāo)簽和屬性列表如下: 標(biāo)簽名作用包含屬性 include 包含外部模板文件(閉合) file import 導(dǎo)入資源文件(閉合?包括js?css?load別名) file,href,type,value,basepath volist 循環(huán)數(shù)組數(shù)據(jù)輸出 name,id,offset,length,key,mod foreach 數(shù)組或?qū)ο蟊闅v輸出 name,item,key for For循環(huán)數(shù)據(jù)輸出 name,from,to,before,step switch 分支判斷輸出 name case 分支判斷輸出(必須和switch配套使用) value,break default 默認(rèn)情況輸出(閉合?必須和switch配套使用) 無(wú) compare 比較輸出(包括eq?neq?lt?gt?egt?elt?heq?nheq等別名) name,value,type range 范圍判斷輸出(包括in?notin?between?notbetween別名) name,value,type present 判斷是否賦值 name notpresent 判斷是否尚未賦值 name empty 判斷數(shù)據(jù)是否為空 name notempty 判斷數(shù)據(jù)是否不為空 name defined 判斷常量是否定義 name notdefined 判斷常量是否未定義 name define 常量定義(閉合) name,value assign 變量賦值(閉合) name,value if 條件判斷輸出 condition elseif 條件判斷輸出(閉合??必須和if標(biāo)簽配套使用) condition else 條件不成立輸出(閉合?可用于其他標(biāo)簽) 無(wú) php 使用php代碼 無(wú)
7. 包含文件 可以使用Include標(biāo)簽來(lái)包含外部的模板文件,使用方法如下: include標(biāo)簽(包含外部模板文件) 閉合 閉合標(biāo)簽 屬性 file(必須):要包含的模板文件,支持變量
1、 使用完整文件名包含 格式:<include file="完整模板文件名" /> <include?file="./Tpl/default/Public/header.html"?/> 2、包含當(dāng)前模塊的其他操作模板文件 格式:<include file="操作名" /> <include?file="read"?/> 操作模板無(wú)需帶后綴。 4、包含其他模板主題的模塊操作模板 格式:<include file="主題名:模塊名:操作名" /> <include?file="blue:User:read"?/> 5、 用變量控制要導(dǎo)入的模版
格式:<include file="$變量名" />
<include?file="$tplName"?/> 給$tplName賦不同的值就可以包含不同的模板文件,變量的值的用法和上面的用法相同。 無(wú)論你使用什么方式包含外部模板,Include標(biāo)簽支持在包含文件的同時(shí)傳入?yún)?shù),注意:由于模板解析的特點(diǎn),從入口模板開(kāi)始解析,如果外部模板有所更改,模板引擎并不會(huì)重新編譯模板,除非在調(diào)試模式下或者緩存已經(jīng)過(guò)期。如果部署模式下修改了包含的外部模板文件后,需要把模塊的緩存目錄清空,否則無(wú)法生效。
3.1版本開(kāi)始,include標(biāo)簽支持導(dǎo)入多個(gè)模板,用逗號(hào)分割即可,例如: <include?file='file1,file2'?/> 8. 導(dǎo)入文件 import標(biāo)簽(包含外部模板文件) 閉合 閉合標(biāo)簽 屬性 file(必須):要包含的模板文件,支持變量
<import?type='js'?file="Js.Util.Array"?/> Type屬性默認(rèn)是js。還可以支持多個(gè)文件批量導(dǎo)入,例如:
<import?file="Js.Util.Array,Js.Util.Date"?/> 導(dǎo)入外部CSS文件必須指定type屬性的值,例如: <import?type='css'?file="Css.common"?/> 上面的方式默認(rèn)的import的起始路徑是網(wǎng)站的Public目錄,如果需要指定其他的目錄,可以使用basepath屬性,例如: <import?file="Js.Util.Array"??basepath="./Common"?/> load標(biāo)簽(采用url方式引入資源文件) 閉合 閉合標(biāo)簽 屬性 href(必須):要引入的資源文件url地址,支持變量
<load?href="/Book/Tpl/Home/Public/Js/Common.js"?/> ?<load?href="/Book/Tpl/Home/Public/Css/common.css"?/> 系統(tǒng)還提供了兩個(gè)標(biāo)簽別名js和css 用法和load一致,例如: <js?href="/Public/Js/Common.js"?/> ?<css?href="/Book/Tpl/Home/Public/Css/common.css"?/> 9. Volist標(biāo)簽 Volist標(biāo)簽主要用于在模板中循環(huán)輸出數(shù)據(jù)集或者多維數(shù)組。 volist標(biāo)簽(循環(huán)輸出數(shù)據(jù)) 閉合 非閉合標(biāo)簽 屬性 name(必須):要輸出的數(shù)據(jù)模板變量
id(必須):循環(huán)變量
offset(可選):要輸出數(shù)據(jù)的offset
length(可選):輸出數(shù)據(jù)的長(zhǎng)度
key(可選):循環(huán)的key變量,默認(rèn)值為i
mod(可選):對(duì)key值取模,默認(rèn)為2
empty(可選):如果數(shù)據(jù)為空顯示的字符串
通常模型的select方法返回的結(jié)果是一個(gè)二維數(shù)組,可以直接使用volist標(biāo)簽進(jìn)行輸出。 在Action中首先對(duì)模版賦值: $User?=?M('User'); $list?=?$User->select(); $this->assign('list',$list); 在模版定義如下,循環(huán)輸出用戶的編號(hào)和姓名: <volist?name="list"?id="vo"> {$vo.id} {$vo.name} ?</volist> 輸出循環(huán)變量 <volist?name="list"?id="vo"?key="k"?> {$k}.{$vo.name} ?</volist> 如果沒(méi)有指定key屬性的話,默認(rèn)使用循環(huán)變量i,例如: <volist?name="list"?id="vo"??> {$i}.{$vo.name} ?</volist> 如果要輸出數(shù)組的索引,可以直接使用key變量,和循環(huán)變量不同的是,這個(gè)key是由數(shù)據(jù)本身決定,而不是循環(huán)控制的,例如: <volist?name="list"?id="vo"??> {$key}.{$vo.name} ?</volist> 從2.1版開(kāi)始允許在模板中直接使用函數(shù)設(shè)定數(shù)據(jù)集,而不需要在控制器中給模板變量賦值傳入數(shù)據(jù)集變量,如: <volist?name=":fun('arg')"?id="vo">{$vo.name}</volist> 10. Foreach標(biāo)簽 foreach標(biāo)簽也是用于循環(huán)輸出
foreach標(biāo)簽(循環(huán)輸出數(shù)據(jù)) 閉合 非閉合標(biāo)簽 屬性 name(必須):要輸出的數(shù)據(jù)模板變量 item(必須):循環(huán)單元變量 key(可選):循環(huán)的key變量,默認(rèn)值為key
<foreach?name="list"?item="vo"> ????{$vo.id} ????{$vo.name} ?</foreach> Foreach標(biāo)簽相對(duì)比volist標(biāo)簽簡(jiǎn)潔,沒(méi)有volist標(biāo)簽?zāi)敲炊嗟墓δ堋?yōu)勢(shì)是可以對(duì)對(duì)象進(jìn)行遍歷輸出,而volist標(biāo)簽通常是用于輸出數(shù)組。
11. For標(biāo)簽 For標(biāo)簽用于實(shí)現(xiàn)for循環(huán),格式為: for標(biāo)簽(循環(huán)輸出數(shù)據(jù)) 閉合 非閉合標(biāo)簽 屬性 start(必須):循環(huán)變量開(kāi)始值 end(必須):循環(huán)變量結(jié)束值 name(可選):循環(huán)變量名,默認(rèn)值為i step(可選):步進(jìn)值,默認(rèn)值為1 comparison(可選):判斷條件,默認(rèn)為lt
<for?start="開(kāi)始值"?end="結(jié)束值"?comparison=""?step="步進(jìn)值"?name="循環(huán)變量名"?> ?</for> <for?start="1"?end="100"> {$i} ?</for> 解析后的代碼是 for?($i=1;$i<100;$i+=1){ ????echo?$i; ?} 12. Switch標(biāo)簽 <switch?name="變量"?> ?<case?value="值1"?break="0或1">輸出內(nèi)容1</case> ?<case?value="值2">輸出內(nèi)容2</case> ?<default?/>默認(rèn)情況 ?</switch> 其中name屬性可以使用函數(shù)以及系統(tǒng)變量,例如: <switch?name="Think.get.userId|abs"> ????<case?value="1">admin</case> ????<default?/>default ?</switch> 對(duì)于case的value屬性可以支持多個(gè)條件的判斷,使用”|”進(jìn)行分割,例如: <switch?name="Think.get.type"> ????<case?value="gif|png|jpg">圖像格式</case> ????<default?/>其他格式 ?</switch> Case標(biāo)簽還有一個(gè)break屬性,表示是否需要break,默認(rèn)是會(huì)自動(dòng)添加break,如果不要break,可以使用: <switch?name="Think.get.userId|abs"> ????<case?value="1"?break="0">admin</case> ????<case?value="2">admin</case> ????<default?/>default ?</switch> 也可以對(duì)case的value屬性使用變量,例如:
<switch?name="User.userId"> ????<case?value="$adminId">admin</case> ????<case?value="$memberId">member</case> ????<default?/>default ?</switch> 使用變量方式的情況下,不再支持多個(gè)條件的同時(shí)判斷。
13. 比較標(biāo)簽 <比較標(biāo)簽?name="變量"?value="值">內(nèi)容</比較標(biāo)簽> 系統(tǒng)支持的比較標(biāo)簽以及所表示的含義分別是: eq或者 equal 等于 neq 或者notequal 不等于 gt 大于 egt 大于等于 lt 小于 elt 小于等于 heq 恒等于 nheq 不恒等于
例如,要求name變量的值等于value就輸出,可以使用: <eq?name="name"?value="value">value</eq> 當(dāng)name變量的值不小于5就輸出 <egt?name="name"?value="5">value</egt> 比較標(biāo)簽中的變量可以支持對(duì)象的屬性或者數(shù)組,甚至可以是系統(tǒng)變量: 當(dāng)vo對(duì)象的屬性(或者數(shù)組,或者自動(dòng)判斷)等于5就輸出 <eq?name="vo.name"?value="5">{$vo.name}</eq> 而且還可以支持對(duì)變量使用函數(shù)? 當(dāng)vo對(duì)象的屬性值的字符串長(zhǎng)度等于5就輸出 <eq?name="vo:name|strlen"?value="5">{$vo.name}</eq> 變量名可以支持系統(tǒng)變量的方式,例如: <eq?name="Think.get.name"?value="value">相等<else/>不相等</eq> 14. 三元運(yùn)算 模板可以支持三元運(yùn)算符,例如:
{$status?'正常':'錯(cuò)誤'} ?{$info['status']?$info['msg']:$info['error']} 注意:三元運(yùn)算符中暫時(shí)不支持點(diǎn)語(yǔ)法。
15. 范圍判斷標(biāo)簽 Range標(biāo)簽用于判斷某個(gè)變量是否在某個(gè)范圍之內(nèi): 范圍判斷標(biāo)簽(包括innotinbetween notbetween) 閉合 非閉合標(biāo)簽 屬性 name(必須):變量名 value(必須):要比較的范圍值,支持變量
可以使用in標(biāo)簽來(lái)判斷模板變量是否在某個(gè)范圍內(nèi),例如: <in?name="id"value="1,2,3">輸出內(nèi)容1</in> 如果判斷不再某個(gè)范圍內(nèi),可以使用: <notin?name="id"value="1,2,3">輸出內(nèi)容2</notin> 可以把上面兩個(gè)標(biāo)簽合并成為: <in?name="id"value="1,2,3">輸出內(nèi)容1<else/>輸出內(nèi)容2</in> 可以使用between標(biāo)簽來(lái)判斷變量是否在某個(gè)區(qū)間范圍內(nèi),可以使用:
<between?name="id"value="1,10">輸出內(nèi)容1</between> 可以使用notbetween標(biāo)簽來(lái)判斷變量不在某個(gè)范圍內(nèi):
<notbetween?name="id"value="1,10">輸出內(nèi)容1</notbetween> 當(dāng)使用between標(biāo)簽的時(shí)候,value只需要一個(gè)區(qū)間范圍,也就是只支持兩個(gè)值,后面的值無(wú)效。 所有的范圍判斷標(biāo)簽的value屬性都可以使用變量,例如:
<in?name="id"value="$var">輸出內(nèi)容1</in> 變量的值可以是字符串或者數(shù)組,都可以完成范圍判斷。
也可以直接使用range標(biāo)簽,替換in和notin的用法:
<range?name="id"value="1,2,3"type="in">輸出內(nèi)容1</range> 其中type屬性的值可以用in或者notin。
16. Present標(biāo)簽和Empty標(biāo)簽 可以使用present標(biāo)簽來(lái)判斷模板變量是否已經(jīng)賦值, present標(biāo)簽和notpresent標(biāo)簽 閉合 非閉合標(biāo)簽 屬性 name(必須):變量名 配合 可以結(jié)合else標(biāo)簽一起使用
<present?name="name">name已經(jīng)賦值</present> 如果判斷沒(méi)有賦值,可以使用: <notpresent?name="name">name還沒(méi)有賦值</notpresent> 可以把上面兩個(gè)標(biāo)簽合并成為: <present?name="name">name已經(jīng)賦值<else?/>?name還沒(méi)有賦值</present> 可以使用empty標(biāo)簽判斷模板變量是否為空, empty標(biāo)簽和notempty標(biāo)簽 閉合 非閉合標(biāo)簽 屬性 name(必須):變量名 配合 可以結(jié)合else標(biāo)簽一起使用
<empty?name="name">name為空值</empty> 如果判斷沒(méi)有賦值,可以使用: <notempty?name="name">name不為空</notempty> 可以把上面兩個(gè)標(biāo)簽合并成為: <empty?name="name">name為空<else?/>?name不為空</empty> 17. Defined標(biāo)簽和Define標(biāo)簽 可以使用defined標(biāo)簽判斷常量是否已經(jīng)有定義: defined標(biāo)簽和notdefined標(biāo)簽 閉合 非閉合標(biāo)簽 屬性 name(必須):變量名
<defined?name="NAME">NAME常量已經(jīng)定義</defined> 如果判斷沒(méi)有被定義,可以使用: <notdefined?name="NAME">NAME常量未定義</notdefined> 可以把上面兩個(gè)標(biāo)簽合并成為: <defined?name="NAME">NAME常量已經(jīng)定義<else?/>?NAME常量未定義</defined> 可以使用define標(biāo)簽進(jìn)行常量定義:
defined標(biāo)簽和notdefined標(biāo)簽 閉合 閉合標(biāo)簽 屬性 name(必須):常量名 value(必須):常量值,支持變量 配合 可以結(jié)合else標(biāo)簽一起使用
<define?name="MY_DEFINE_NAME"value="3"/> 在運(yùn)行模板的時(shí)候 定義了一個(gè)MY_DEFINE_NAME的常量。
18. Assign標(biāo)簽 可以使用assign標(biāo)簽進(jìn)行賦值:
assign標(biāo)簽(在模板中給變量賦值) 閉合 閉合標(biāo)簽 屬性 name(必須):模板變量名 value(必須):變量值,支持變量
<assign?name="var"?value="123"?/> 在運(yùn)行模板的時(shí)候 賦值了一個(gè)var的變量,值是123。 19. IF標(biāo)簽 用法示例: <if?condition="($name?eq?1)?OR?($name?gt?100)?">?value1 ?<elseif?condition="$name?eq?2"/>value2 ?<else?/>?value3 ?</if> 除此之外,我們可以在condition屬性里面使用php代碼,例如: <if?condition="strtoupper($user['name'])?neq?'THINKPHP'">ThinkPHP ?<else?/>?other?Framework ?</if> condition屬性可以支持點(diǎn)語(yǔ)法和對(duì)象語(yǔ)法,例如:
自動(dòng)判斷user變量是數(shù)組還是對(duì)象
<if?condition="$user.name?neq?'ThinkPHP'">ThinkPHP ?<else?/>?other?Framework ?</if> 或者知道user變量是對(duì)象
<if?condition="$user:name?neq?'ThinkPHP'">ThinkPHP ?<else?/>?other?Framework ?</if> 由于if標(biāo)簽的condition屬性里面基本上使用的是php語(yǔ)法,盡可能使用判斷標(biāo)簽和Switch標(biāo)簽會(huì)更加簡(jiǎn)潔,原則上來(lái)說(shuō),能夠用switch和比較標(biāo)簽解決的盡量不用if標(biāo)簽完成。因?yàn)閟witch和比較標(biāo)簽可以使用變量調(diào)節(jié)器和系統(tǒng)變量。如果某些特殊的要求下面,IF標(biāo)簽仍然無(wú)法滿足要求的話,可以使用原生php代碼或者PHP標(biāo)簽來(lái)直接書(shū)寫代碼。
20. 標(biāo)簽嵌套 模板引擎支持標(biāo)簽的多層嵌套功能,可以對(duì)標(biāo)簽庫(kù)的標(biāo)簽指定可以嵌套。
系統(tǒng)內(nèi)置的標(biāo)簽中,volist、switch、if、elseif、else、foreach、compare(包括所有的比較標(biāo)簽)、(not)present、(not)empty、(not)defined等標(biāo)簽都可以嵌套使用。例如:
<volist?name="list"?id="vo"> ????<volist?name="vo['sub']"?id="sub"> ????????{$sub.name} ????</volist> ?</volist> 上面的標(biāo)簽可以用于輸出雙重循環(huán)。默認(rèn)的嵌套層次是3級(jí),所以嵌套層次不能超過(guò)3層,如果需要更多的層次可以指定TAG_NESTED_LEVEL配置參數(shù),例如:
'TAG_NESTED_LEVEL'?=>5 可以改變循環(huán)嵌套級(jí)別為5級(jí)。
21. 使用PHP代碼 <php>echo?'Hello,world!';</php> 注意:php標(biāo)簽或者php代碼里面就不能再使用標(biāo)簽(包括普通標(biāo)簽和XML標(biāo)簽)了,因此下面的幾種方式都是無(wú)效的: <php><eq?name='name'value='value'>value</eq></php> 簡(jiǎn)而言之,在PHP標(biāo)簽里面不能再使用PHP本身不支持的代碼。 如果設(shè)置了TMPL_DENY_PHP參數(shù)為true,就不能在模板中使用原生的PHP代碼,但是仍然支持PHP標(biāo)簽輸出。 22. 模板布局 第一種方式是 以布局模板為入口的方式
該方式需要配置開(kāi)啟LAYOUT_ON 參數(shù)(默認(rèn)不開(kāi)啟),并且設(shè)置布局入口文件名LAYOUT_NAME(默認(rèn)為layout)。
開(kāi)啟LAYOUT_ON后,我們的模板渲染流程就有所變化,例如:
Class?UserAction?extends?Action?{ ????Public?function?add()?{ ????$this->display('add'); ????} ?} 在不開(kāi)啟LAYOUT_ON布局模板之前,會(huì)直接渲染Tpl/User/add.html 模板文件,開(kāi)啟之后,首先會(huì)渲染Tpl/layout.html 模板,布局模板的寫法和其他模板的寫法類似,本身也可以支持所有的模板標(biāo)簽以及包含文件,區(qū)別在于有一個(gè)特定的輸出替換變量{__CONTENT__},例如,下面是一個(gè)典型的layout.html模板的寫法:
{__CONTENT__} 讀取layout模板之后,會(huì)再解析User/add.html 模板文件,并把解析后的內(nèi)容替換到layout布局模板文件的{__CONTENT__} 特定字符串。
采用這種布局方式的情況下,一旦User/add.html 模板文件或者layout.html布局模板文件發(fā)生修改,都會(huì)導(dǎo)致模板重新編譯。
如果項(xiàng)目需要使用不同的布局模板,可以動(dòng)態(tài)的配置LAYOUT_NAME參數(shù)實(shí)現(xiàn)。
如果某些頁(yè)面不需要使用布局模板功能,可以在模板文件開(kāi)頭加上 {__NOLAYOUT__} 字符串。
如果上面的User/add.html 模板文件里面包含有{__NOLAYOUT__},則即使當(dāng)前開(kāi)啟布局模板,也不會(huì)進(jìn)行布局模板解析。 第二種方式是以當(dāng)前輸出模板為入口的方式
以前面的輸出模板為例,這種方式的入口還是在User/add.html 模板,但是我們可以修改下add模板文件的內(nèi)容,在頭部增加下面的布局標(biāo)簽:
<layout?name="layout"?/> 表示當(dāng)前模板文件需要使用layout.html 布局模板文件,而布局模板文件的寫法和上面第一種方式是一樣的。當(dāng)渲染User/add.html 模板文件的時(shí)候,如果讀取到layout標(biāo)簽,則會(huì)把當(dāng)前模板的解析內(nèi)容替換到layout布局模板的{__CONTENT__} 特定字符串。
如果需要使用其他的布局模板,可以改變layout的name屬性,例如:
<layout?name="new_layout"?/> 由于所有include標(biāo)簽引入的文件都支持layout標(biāo)簽,所以,我們可以借助layout標(biāo)簽和include標(biāo)簽相結(jié)合的方式實(shí)現(xiàn)布局模板的嵌套。例如,上面的例子
<include?file="Public:header"?/> ?<div?id="main"?class="main"?> {__CONTENT__} ?</div> ?<include?file="Public:bottom"?/>? 在引入的header和footer模板文件中也可以添加layout標(biāo)簽,例如header模板文件的開(kāi)頭添加如下標(biāo)簽:
<layout?name="menu"?/> 這樣就實(shí)現(xiàn)了在頭部模板中引用了menu布局模板。
也可以采用兩種布局方式的結(jié)合,可以實(shí)現(xiàn)更加復(fù)雜的模板布局以及嵌套功能。
23. 模板繼承 模板繼承的優(yōu)勢(shì)其實(shí)是設(shè)計(jì)基礎(chǔ)模板中的區(qū)塊(block)和子模板中替換這些區(qū)塊。每個(gè)區(qū)塊由<block></block>標(biāo)簽組成,并且不支持block標(biāo)簽的嵌套。
下面就是基礎(chǔ)模板中的一個(gè)典型的區(qū)塊設(shè)計(jì)(用于設(shè)計(jì)網(wǎng)站標(biāo)題): <block?name="title"><title>網(wǎng)站標(biāo)題</title></block> block標(biāo)簽必須指定name屬性來(lái)標(biāo)識(shí)當(dāng)前區(qū)塊的名稱,這個(gè)標(biāo)識(shí)在當(dāng)前模板中應(yīng)該是唯一的,block標(biāo)簽中可以包含任何模板內(nèi)容,包括其他標(biāo)簽和變量,例如: <block?name="title"><title>{$web_title}</title></block> 你甚至還可以在區(qū)塊中加載外部文件: <block?name="include"><include?file="Public:header"?/></block> 在子模板中,可以對(duì)基礎(chǔ)模板中的區(qū)塊進(jìn)行重載定義,如果沒(méi)有重新定義的話,則表示沿用基礎(chǔ)模板中的區(qū)塊定義,如果定義了一個(gè)空的區(qū)塊,則表示刪除基礎(chǔ)模板中的該區(qū)塊內(nèi)容。 24. 原樣輸出 literal標(biāo)簽(保持原樣輸出) 閉合 非閉合標(biāo)簽 屬性 無(wú)
可以使用literal標(biāo)簽來(lái)防止模板標(biāo)簽被解析,例如:
<literal> ????<if?condition="$name?eq?1?">?value1 ????<elseif?condition="$name?eq?2"/>value2 ????????<else?/>?value3 ????</if> ?</literal> 上面的if標(biāo)簽被literal標(biāo)簽包含,因此if標(biāo)簽里面的內(nèi)容并不會(huì)被模板引擎解析,而是保持原樣輸出。 Literal標(biāo)簽還可以用于頁(yè)面的JS代碼外層,確保JS代碼中的某些用法和模板引擎不產(chǎn)生混淆。
總之,所有可能和內(nèi)置模板引擎的解析規(guī)則沖突的地方都可以使用literal標(biāo)簽處理。
25. 模板注釋 模板支持注釋功能,該注釋文字在最終頁(yè)面不會(huì)顯示,僅供模板制作人員參考和識(shí)別。
{//?這是模板注釋內(nèi)容?} ?{/*?這是模板 注釋內(nèi)容*/?} 模板注釋支持多行,模板注釋在生成編譯緩存文件后會(huì)自動(dòng)刪除,這一點(diǎn)和Html的注釋不同。
26. 引入標(biāo)簽庫(kù) 格式:
<tagLib name="標(biāo)簽庫(kù)1[,標(biāo)簽庫(kù)2,…]"/> 可以同時(shí)導(dǎo)入多個(gè)標(biāo)簽庫(kù),用逗號(hào)分隔,例如:
<tagLib?name="html"/> 表示在當(dāng)前模板文件需要引入html標(biāo)簽庫(kù)。要引入標(biāo)簽庫(kù)必須確保有Html標(biāo)簽庫(kù)的定義文件和解析類庫(kù)(如何擴(kuò)展這種方式請(qǐng)參考前面的標(biāo)簽庫(kù)擴(kuò)展部分)。 引入后,html標(biāo)簽庫(kù)的所有標(biāo)簽在當(dāng)前模板頁(yè)面中都可以使用了。外部導(dǎo)入的標(biāo)簽庫(kù)必須使用標(biāo)簽庫(kù)前綴的xml標(biāo)簽,避免兩個(gè)不同的標(biāo)簽庫(kù)中存在同名的標(biāo)簽定義,例如(假設(shè)Html標(biāo)簽庫(kù)中已經(jīng)有定義select和link標(biāo)簽):
<html:select?options='name'?selected='value'?/> ?<html:link?href='/path/to/common.js'?/> 標(biāo)簽庫(kù)使用的時(shí)候忽略大小寫,因此下面的方式一樣有效:
<HTML:LINK?HREF='/path/to/common.js'?/> 如果你的每個(gè)模板頁(yè)面都需要加載Html標(biāo)簽庫(kù)的話,也可以通過(guò)配置直接預(yù)先加載Html標(biāo)簽庫(kù)。
?'TAGLIB_PRE_LOAD'?=>?'html'?, 如果有多個(gè)標(biāo)簽庫(kù)需要預(yù)先加載的話,用逗號(hào)分隔。定義之后,每個(gè)模板頁(yè)面都可以直接使用:
<html:select?options='name'?selected='value'?/> 而不需手動(dòng)引入Html標(biāo)簽庫(kù)。
假設(shè)你確信Html標(biāo)簽庫(kù)無(wú)論在現(xiàn)在還是將來(lái)都不會(huì)和系統(tǒng)內(nèi)置的標(biāo)簽庫(kù)存在相同的標(biāo)簽,那么可以配置TAGLIB_BUILD_IN的值把Html標(biāo)簽庫(kù)作為內(nèi)置標(biāo)簽庫(kù)引入,例如:
'TAGLIB_BUILD_IN'?=>?'cx,html'?, 這樣,也無(wú)需在模板文件頁(yè)面引入Html標(biāo)簽庫(kù)了,并且可以不帶前綴直接使用Html標(biāo)簽庫(kù)的標(biāo)簽:
<select?options='name'?selected='value'?/> 注意,cx標(biāo)簽庫(kù)是系統(tǒng)內(nèi)置標(biāo)簽庫(kù),不能刪除定義。
27. 修改定界符 要更改普遍模板的起始標(biāo)簽和結(jié)束標(biāo)簽,請(qǐng)使用下面的配置參數(shù): TMPL_L_DELIM??//模板引擎普通標(biāo)簽開(kāi)始標(biāo)記? TMPL_R_DELIM????//模板引擎普通標(biāo)簽結(jié)束標(biāo)記 例如在項(xiàng)目配置文件中增加下面的配置: 'TMPL_L_DELIM'=>'', 普通模板標(biāo)簽主要用于模板變量輸出和模板注釋。如果要使用其它功能,請(qǐng)使用XML模板標(biāo)簽。XML模板標(biāo)簽可以用于模板變量輸出、文件包含、條件控制、循環(huán)輸出等功能,而且完全可以自己擴(kuò)展功能。如果你覺(jué)得XML標(biāo)簽無(wú)法在正在使用的編輯器里面無(wú)法編輯,還可以更改XML標(biāo)簽庫(kù)的起始和結(jié)束標(biāo)簽,請(qǐng)修改下面的配置參數(shù): TAGLIB_BEGIN????//標(biāo)簽庫(kù)標(biāo)簽開(kāi)始標(biāo)簽? TAGLIB_END????//標(biāo)簽庫(kù)標(biāo)簽結(jié)束標(biāo)記 例如在項(xiàng)目配置文件中增加下面的配置: 'TAGLIB_BEGIN'=>'[', ?'TAGLIB_END'=>']', 注意:XML標(biāo)簽和普通標(biāo)簽的定界符不能沖突,否則會(huì)導(dǎo)致解析錯(cuò)誤。如果你定制了普通表情的定界符,而且默認(rèn)跳轉(zhuǎn)頁(yè)面用的是系統(tǒng)默認(rèn)的話,記得修改下默認(rèn)跳轉(zhuǎn)模板中的變量定界符。 28. 避免JS混淆 如果使用內(nèi)置的模板引擎,而且采用默認(rèn)的標(biāo)簽設(shè)置的話,在某些情況下,如果不注意,{$('name').value} 這樣的JS代碼很容易被內(nèi)置模板引擎誤解析。 有三個(gè)方法可以解決類似的混淆問(wèn)題: 1、{$('name').value}改成{ $('name').value} 因?yàn)閮?nèi)置模板引擎的解析規(guī)則是"{"后面緊跟"$"符號(hào)才會(huì)解析變量 因此只要在"{" 和"$"之間添加空格就不會(huì)被誤解析了 2、使用內(nèi)置的literal標(biāo)簽包含JS代碼 <literal>JS代碼</literal> 包含在literal標(biāo)簽中的代碼將會(huì)直接輸出,不進(jìn)行任何解析 3、定制模板引擎標(biāo)簽的定界符 例如:'TMPL_L_DELIM'=>'<{','TMPL_R_DELIM'=>'}>'這樣就和JS代碼區(qū)別開(kāi)來(lái)了。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 日志: 日志的處理工作是由系統(tǒng)自動(dòng)進(jìn)行的,在開(kāi)啟日志記錄的情況下,會(huì)記錄下允許的日志級(jí)別的所有日志信息。其中,為了性能考慮,SQL日志級(jí)別必須在調(diào)試模式開(kāi)啟下有效,否則就不會(huì)記錄。 系統(tǒng)的日志記錄由核心的Log類完成,提供了多種方式記錄了不同的級(jí)別的日志信息。 1. 日志級(jí)別 EMERG 嚴(yán)重錯(cuò)誤,導(dǎo)致系統(tǒng)崩潰無(wú)法使用 ALERT 警戒性錯(cuò)誤, 必須被立即修改的錯(cuò)誤 CRIT 臨界值錯(cuò)誤, 超過(guò)臨界值的錯(cuò)誤 ERR 一般性錯(cuò)誤 WARN 警告性錯(cuò)誤, 需要發(fā)出警告的錯(cuò)誤 NOTICE 通知,程序可以運(yùn)行但是還不夠完美的錯(cuò)誤 INFO 信息,程序輸出信息 DEBUG 調(diào)試,用于調(diào)試信息 SQL SQL語(yǔ)句,該級(jí)別只在調(diào)試模式開(kāi)啟時(shí)有效
要開(kāi)啟日志記錄,必須在配置中開(kāi)啟LOG_RECORD參數(shù),以及可以在項(xiàng)目配置文件中配置需要記錄的日志級(jí)別,例如: 'LOG_RECORD'?=>?true,?//?開(kāi)啟日志記錄 ?'LOG_LEVEL'??=>'EMERG,ALERT,CRIT,ERR',?//?只記錄EMERG?ALERT?CRIT?ERR?錯(cuò)誤 2. 記錄方式 記錄方式 說(shuō)明 常量標(biāo)識(shí) SYSTEM 日志發(fā)送到PHP的系統(tǒng)日志記錄 0 MAIL 日志通過(guò)郵件方式發(fā)送 1 FILE 日志通過(guò)文件方式記錄(默認(rèn)方式) 3 SAPI 日志通過(guò)SAPI方式記錄 4
日志的記錄格式:記錄時(shí)間 訪問(wèn)URL | 日志級(jí)別:日志信息 其中的時(shí)間顯示可以動(dòng)態(tài)配置,默認(rèn)是采用 [ c ],例如我們可以改成: Log::$format?=?'[?Y-m-d?H:i:s?]'; 其格式定義和date函數(shù)的用法一致,默認(rèn)情況下具體的日志信息類似于下面的內(nèi)容: [2012-01-15T18:09:22+08:00]?/Index/index|NOTIC:?[8]?Undefined?variable:?verify?PublicAction.class.php?第?162?行. ?[2012-01-15T18:09:22+08:00]?/Index/index?|?SQL:??RunTime:0.214238s?SQL?=?SHOW?COLUMNS?FROM?think_user ?[2012-01-15T18:09:22+08:00]?/Index/index?|?SQL:??RunTime:0.039159s?SQL?=?SELECT?*?FROM?`think_user`?WHERE?(?`account`?=?'admin'?)?AND?(?`status`?>?0?)?LIMIT?1 默認(rèn)采用文件方式記錄日志信息,日志文件的命名格式是:年(簡(jiǎn)寫)_月_日.log,例如: 09_10_01.log 表示2009年10月1日的日志文件 可以設(shè)置LOG_FILE_SIZE參數(shù)來(lái)限制日志文件的大小,超過(guò)大小的日志會(huì)形成備份文件。備份文件的格式是在當(dāng)前文件名前面加上備份的時(shí)間戳,例如: 1189571417-07_09_12.log 備份的日志文件 如果需要使用其他方式記錄日志,可以設(shè)置LOG_TYPE參數(shù),例如下面設(shè)置了采用郵件方式發(fā)送日志記錄: 'LOG_TYPE'?=>1,?//??采用郵件方式記錄日志 ?'LOG_DEST'?=>'admin@domain.com',?//?要發(fā)送日志的郵箱 ?'LOG_EXTRA'?=>'From:?webmaster@example.com',?//?郵件的發(fā)件人設(shè)置 3. 手動(dòng)記錄 http://doc.thinkphp.cn/manual/log_record.html ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 錯(cuò)誤: 1. 異常處理 和PHP默認(rèn)的異常處理不同,ThinkPHP拋出的不是單純的錯(cuò)誤信息,而是一個(gè)人性化的錯(cuò)誤頁(yè)面。 只有在調(diào)試模式下面才能顯示具體的錯(cuò)誤信息,如果在部署模式下面,你可能看到的是一個(gè)統(tǒng)一錯(cuò)誤的提示文字,如果你試圖在部署模式下訪問(wèn)一個(gè)不存在的模塊或者操作,會(huì)發(fā)送404錯(cuò)誤。 調(diào)試模式下面一旦系統(tǒng)發(fā)生嚴(yán)重錯(cuò)誤會(huì)自動(dòng)拋出異常,也可以用ThinkPHP定義的throw_exception方法手動(dòng)拋出異常。 throw_exception('新增失敗'); throw_exception('信息錄入錯(cuò)誤','InfoException'); 同樣也可以使用throw 關(guān)鍵字來(lái)拋出異常,下面的寫法是等效的: throw?new?ThinkException('新增失敗'); ?throw?new?InfoException('信息錄入錯(cuò)誤'); 如果需要,我們建議在項(xiàng)目的類庫(kù)目錄下面增加Exception目錄用于專門存放異常類庫(kù),以更加精確地定位異常。 2. 異常模板 系統(tǒng)內(nèi)置的異常模板在系統(tǒng)目錄的Tpl/think_exception.tpl,可以通過(guò)修改系統(tǒng)模板來(lái)修改異常頁(yè)面的顯示。也通過(guò)設(shè)置TMPL_EXCEPTION_FILE 配置參數(shù)來(lái)修改系統(tǒng)默認(rèn)的異常模板文件, 例如: 'TMPL_EXCEPTION_FILE'?=>?APP_PATH.'/Public/exception.tpl' 異常模板中可以使用的異常變量有: $e['file']異常文件名 $e['line'] 異常發(fā)生的文件行數(shù) $e['message'] 異常信息 $e['trace'] 異常的詳細(xì)Trace信息 因?yàn)楫惓D0迨褂玫氖窃鶳HP代碼,所以還可以支持任何的PHP方法和系統(tǒng)變量使用。 3. 異常顯示 拋出異常后通常會(huì)顯示具體的錯(cuò)誤信息,如果不想讓用戶看到具體的錯(cuò)誤信息,可以設(shè)置關(guān)閉錯(cuò)誤信息的顯示并設(shè)置統(tǒng)一的錯(cuò)誤提示信息,例如: 'SHOW_ERROR_MSG'?=>false, ?'ERROR_MESSAGE'?=>'發(fā)生錯(cuò)誤!' 設(shè)置之后,所有的異常頁(yè)面只會(huì)顯示“發(fā)生錯(cuò)誤!”這樣的提示信息,但是日志文件中仍然可以查看具體的錯(cuò)誤信息。新版如果關(guān)閉調(diào)試模式的話,為了安全起見(jiàn),默認(rèn)就是關(guān)閉異常信息提示。 另外一種方式是配置ERROR_PAGE參數(shù),把所有異常和錯(cuò)誤都指向一個(gè)統(tǒng)一頁(yè)面,從而避免讓用戶看到異常信息,通常在部署模式下面使用。ERROR_PAGE參數(shù)必須是一個(gè)完整的URL地址,例如: 'ERROR_PAGE'?=>'/Public/error.html' 如果不在當(dāng)前域名,還可以指定域名: 'ERROR_PAGE'?=>'http://www.myDomain.com/Public/error.html' 注意ERROR_PAGE所指向的頁(yè)面不能再使用異常的模板變量了。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ?
轉(zhuǎn)載于:https://www.cnblogs.com/echohao/p/4715421.html
創(chuàng)作挑戰(zhàn)賽 新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔 為你收集整理的ThinkPHP- 3.1 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。