日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

ThinkPHP- 3.1

發(fā)布時(shí)間:2023/12/10 php 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ThinkPHP- 3.1 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

基礎(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/CoreThink.Core核心類庫(kù)包
    Lib/BehaviorThink.Behavior內(nèi)置行為類庫(kù)包
    Lib/DriverThink.Driver內(nèi)置驅(qū)動(dòng)類庫(kù)包
    Lib/TemplateThink.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ù)類
    DispatcherURL調(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_)
    UserModelthink_user
    UserTypeModelthink_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
    forFor循環(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)試信息
    SQLSQL語(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ò),歡迎將生活随笔推薦給好友。

    欧美性一级观看 | 亚洲精品视频在线播放 | 色噜噜日韩精品一区二区三区视频 | 成人欧美一区二区三区黑人麻豆 | 成人午夜久久 | 欧美精品久久99 | 四虎影视www | 亚洲毛片视频 | 韩国一区二区av | 91麻豆免费版 | 91视频com| 久操伊人 | 国产98色在线 | 日韩 | 激情五月婷婷网 | 九九激情视频 | 99人久久精品视频最新地址 | 国产精品免费久久久久影院仙踪林 | 国产二区免费视频 | 成人免费观看av | 久久都是精品 | 日本爱爱免费视频 | 久久三级毛片 | av在线中文 | 欧洲亚洲精品 | 天天操天天综合网 | 欧美一级专区免费大片 | 日韩视频免费观看高清 | 激情综合五月婷婷 | 成人午夜性影院 | 欧美日韩99| 五月婷综合网 | 色噜噜日韩精品一区二区三区视频 | 久久激情小说 | 成年人在线播放视频 | 亚洲日本一区二区在线 | 97超碰.com| 欧美孕交vivoestv另类 | 国产男女爽爽爽免费视频 | 91桃色国产在线播放 | 国产精品久久久久久久久久久久午夜片 | 日本精品久久久久影院 | 中文字幕频道 | 西西4444www大胆艺术 | 午夜精品久久久久久久99 | 国产男女免费完整视频 | 性色av香蕉一区二区 | 日韩在线精品视频 | 999精品网 | 国模一二三区 | 一区二区三区观看 | 看片的网址 | 国产一区二区在线播放视频 | 麻豆视频在线 | 91亚洲精品久久久久图片蜜桃 | 欧美做受xxx| 91在线视频精品 | 午夜久久美女 | 日韩免费电影一区二区三区 | 国产a国产| 日韩av片无码一区二区不卡电影 | 亚洲精品视频免费在线 | 在线免费黄色毛片 | 99这里精品 | 亚洲精品视频久久 | 99热最新在线 | 欧美另类视频 | 97超碰在线久草超碰在线观看 | 日韩精品免费在线 | 99久久精品国产欧美主题曲 | 精品亚洲网| 国产亚洲精品久久久久久大师 | 国产精品欧美久久久久天天影视 | 亚洲另类久久 | 五月在线视频 | 日韩黄色大片在线观看 | 日韩激情视频在线 | 色综合天天狠狠 | 亚洲电影图片小说 | 色综合天天做天天爱 | 伊人天堂久久 | 人人舔人人干 | 在线 高清 中文字幕 | 丁香九月婷婷综合 | 中文字幕在线日本 | 国产亚洲高清视频 | 99色精品视频 | 中文字幕频道 | 99热高清 | 国产精品一区二区三区99 | 日韩高清三区 | 久久精品中文视频 | 国产一区黄色 | 日本三级人妇 | 日韩av片无码一区二区不卡电影 | 久久歪歪 | 麻豆av一区二区三区在线观看 | 天天色天天搞 | 西西4444www大胆视频 | 国产精品免费一区二区三区在线观看 | 久久国产精品色av免费看 | 性色av一区二区三区在线观看 | 久久精品久久精品久久 | 天天综合日| 国产精品成人aaaaa网站 | 麻豆免费观看视频 | 在线天堂中文www视软件 | 一级黄毛片 | 欧美91成人网 | 久久久久亚洲精品男人的天堂 | 国产精品久久久久久久久久新婚 | 免费欧美| 精品视频在线免费观看 | 在线观看韩日电影免费 | 不卡电影免费在线播放一区 | 91天天操| 国产麻豆剧传媒免费观看 | 精产嫩模国品一二三区 | 91视频传媒| 亚洲国产精品人久久电影 | 狠狠狠的干 | 日韩一区二区三区在线看 | 综合天天 | 中文十次啦| 六月激情网 | 一区二区三区免费 | 久久免费国产电影 | 97精品超碰一区二区三区 | 蜜桃视频在线视频 | 97成人在线| 午夜黄色大片 | 久久久久国产视频 | 亚洲资源视频 | 91成人短视频在线观看 | 日日干夜夜干 | 99欧美视频 | 亚洲综合成人婷婷小说 | 国产精品视频你懂的 | www欧美xxxx| 91看片在线播放 | 五月激情综合婷婷 | 激情婷婷久久 | 欧美日韩精品在线观看视频 | www.狠狠操.com | 亚洲精品在线资源 | 超碰在线9 | 亚洲涩涩网 | 日韩电影中文字幕在线 | 亚洲国产黄色 | 国产精品久久久久影院日本 | 亚洲精品大全 | 国产福利免费在线观看 | 激情片av| 91豆麻精品91久久久久久 | 91亚洲精品久久久蜜桃网站 | 成人动漫视频在线 | 丁香婷婷激情网 | 天天射天天舔天天干 | 亚洲国产精品成人精品 | 日韩一级成人av | 美女久久久久久 | 亚洲精选久久 | 黄色特级一级片 | 天天综合网入口 | 在线色网站| 女人18毛片a级毛片一区二区 | 国产视频午夜 | 精品国产一区二区三区在线观看 | 久久99久久99精品 | 亚洲欧美日韩一区二区三区在线观看 | 狠狠操狠狠干天天操 | 国产精品久久久久久久久婷婷 | 国产中文视频 | 337p西西人体大胆瓣开下部 | 日b视频在线观看网址 | 天天干天天干天天干天天干天天干天天干 | 日日天天狠狠 | 99久久精品国产一区二区三区 | 欧洲一区二区在线观看 | 超碰免费av | 国产精品久久久999 国产91九色视频 | 欧美成人亚洲成人 | 成人高清在线 | 免费黄色一区 | 久久婷婷综合激情 | 久久国产影院 | 成年人毛片在线观看 | 一本一道久久a久久精品蜜桃 | www.久久com| 视频在线日韩 | 精品成人在线 | 可以免费观看的av片 | 黄色软件在线观看视频 | 日本黄色免费观看 | 激情五月视频 | 亚洲国产免费看 | av蜜桃在线| 精品视频在线视频 | 黄色1级毛片 | 色姑娘综合网 | 激情 婷婷 | 亚洲香蕉视频 | 最新极品jizzhd欧美 | 亚洲三级在线免费观看 | 色婷婷a | 美女视频免费一区二区 | 久久系列 | www.色综合.com | 人人要人人澡人人爽人人dvd | 欧美精品一区二区三区一线天视频 | 一区二区三区免费在线 | 狠狠色丁香婷婷综合最新地址 | 久草网首页 | 亚州精品天堂中文字幕 | 玖玖视频在线 | 99999精品| 操操操干干干 | 六月丁香六月婷婷 | 日日夜夜天天综合 | 国产精品ssss在线亚洲 | 999久久久免费视频 午夜国产在线观看 | 亚洲综合网站在线观看 | 日本资源中文字幕在线 | 婷婷精品进入 | 久久观看免费视频 | 免费成人av网站 | 伊甸园av在线 | 最近中文字幕在线播放 | 久久久久久久久久久电影 | 97在线观看| 日韩av在线一区二区 | 五月天狠狠操 | 在线免费视 | 97国产在线播放 | 91九色在线| 2019国产精品 | 日韩午夜网站 | 欧美日韩国产免费视频 | 成人午夜免费福利 | 久久激情精品 | 五月婷婷欧美 | 97成人在线免费视频 | 三级av在线播放 | 五月天久久久久久 | 人人要人人澡人人爽人人dvd | 在线精品在线 | 99热最新 | 91毛片在线 | 成人xxxx| 欧美成人黄色 | 色婷婷www | 国产黄色精品在线 | a黄色 | 又爽又黄又刺激的视频 | 久久天堂影院 | 97国产一区| 美女视频一区二区 | 午夜久久久久久久久久久 | 成人久久免费视频 | 国产99久久久国产 | 欧美精品亚州精品 | 久久婷婷国产色一区二区三区 | 日韩三级成人 | 91麻豆精品国产91久久久使用方法 | 国产美腿白丝袜足在线av | 一本之道乱码区 | 亚洲最新av在线网站 | 国产玖玖精品视频 | 日韩欧美在线观看 | 国产精品涩涩屋www在线观看 | 久久久免费观看完整版 | 韩国精品一区二区三区六区色诱 | 久久免费精品国产 | 欧美91av| 人操人| 99这里精品 | 日韩在线在线 | 欧美国产精品一区二区 | 在线观看aaa| bbb搡bbb爽爽爽 | 欧美综合在线观看 | 日韩精品免费专区 | 国产精品成人自产拍在线观看 | 久久成人黄色 | 国产精品久久嫩一区二区免费 | 成人av电影在线观看 | 五月婷婷开心 | 韩日三级av | 精品不卡视频 | 高清不卡一区二区三区 | 国产精品福利无圣光在线一区 | 久久精品区 | 天天久久综合 | 激情欧美一区二区三区免费看 | 久久精品一区二区 | 韩国av一区二区三区在线观看 | 国产精品18久久久久久久网站 | 高清av免费一区中文字幕 | 黄色免费大全 | 久久精品99久久久久久 | 在线观看视频黄 | 91人人在线| 亚洲精品国偷拍自产在线观看蜜桃 | 国产成人三级在线观看 | 免费看国产一级片 | 亚洲精品电影在线 | 欧美日韩二区在线 | 免费观看不卡av | 成人97人人超碰人人99 | 日韩成人免费在线 | 国产精品久久久久久久久久久久午夜片 | 欧美怡红院 | 很黄很黄的网站免费的 | 亚洲伊人天堂 | 国产精品系列在线播放 | 91在线视频网址 | 973理论片235影院9 | 国产一区在线免费 | 欧美久久久久久久久久久久久 | 日韩动漫免费观看高清完整版在线观看 | 国产美女精品 | 国产精品精品久久久久久 | 亚洲区视频在线观看 | 91久久影院 | 色婷丁香 | 99在线视频免费观看 | 国产91小视频 | 天堂av色婷婷一区二区三区 | 久久av网| 天天干,狠狠干 | 欧美天天综合 | 99久久精品午夜一区二区小说 | 国产成人精品一区二区三区在线 | 国产精品毛片一区视频播不卡 | 五月情婷婷 | 91传媒在线看 | 国产黄色大全 | 激情图片qvod | 91av免费看 | 色丁香婷婷 | 91av视频播放 | 日韩视频一区二区在线 | 97在线视频免费观看 | 97成人资源站 | 欧美99精品 | 久久国产电影院 | 激情黄色av | 国产超碰在线 | 日本黄色免费在线观看 | 久久桃花网 | 精品亚洲免费视频 | 中文字幕在线资源 | www在线免费观看 | 国产精品一区二区久久国产 | 日韩高清一区 | 亚洲 欧美 综合 在线 精品 | 在线播放视频一区 | 成人小视频在线播放 | 精品亚洲午夜久久久久91 | 久久精品4| 免费久久99精品国产婷婷六月 | 中文字幕在线观看视频免费 | 亚洲激情综合 | 日韩国产精品久久久久久亚洲 | 亚洲精品在线一区二区三区 | 亚洲专区免费观看 | 在线视频 91 | 国产白浆在线观看 | 91精品国产九九九久久久亚洲 | 高清免费在线视频 | 黄色免费网站大全 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | 天天干天天操天天搞 | 人人干在线 | 国内丰满少妇猛烈精品播放 | 天天摸夜夜操 | 波多野结依在线观看 | 亚洲播放一区 | aaa亚洲精品一二三区 | 国产成人免费网站 | 亚洲日韩欧美视频 | av免费试看 | 色多多污污 | 免费色视频网站 | 九九在线播放 | 亚洲狠狠婷婷 | 99久久精品免费看国产免费软件 | 天堂素人在线 | 久久久 激情 | 色中文字幕在线观看 | 久章草在线 | 欧美国产日韩中文 | 久久精品国产免费看久久精品 | 午夜精品福利一区二区三区蜜桃 | 欧美国产视频在线 | 成人免费在线网 | 免费精品久久久 | 国产精品视频永久免费播放 | 久久久久激情 | 成人中文字幕在线 | 国产久视频 | 欧美一区二区三区在线看 | 国产亚洲视频在线免费观看 | 2022久久国产露脸精品国产 | 片网站 | 日日日操操 | 在线观看色网 | 国产精品永久免费观看 | 国产一区二区不卡视频 | 亚洲精品乱码久久久久久久久久 | 精品v亚洲v欧美v高清v | 久热免费在线 | 国产精品久久久久一区二区国产 | 欧美日韩xxxxx | 亚洲精品国产日韩 | 日韩网站免费观看 | 天天干天天操天天操 | 亚洲日韩欧美一区二区在线 | 91久久精品一区 | 夜色资源站国产www在线视频 | 久久久久久久久久久久电影 | 狠狠躁日日躁狂躁夜夜躁 | www.香蕉视频在线观看 | 在线观看黄色小视频 | 国产日韩欧美在线一区 | 视频一区二区三区视频 | www.夜色.com | 91九色最新| 成人宗合网| 中文字幕中文字幕在线一区 | 六月色 | 国产一区二区在线免费播放 | 久操视频在线 | 99热最新精品 | 91成年人网站 | 中文免费观看 | 天天操天天射天天操 | 久久久久久中文字幕 | 亚洲va天堂va欧美ⅴa在线 | 久久草草影视免费网 | av网站播放 | 久久伦理电影网 | 欧美精品一区二区三区一线天视频 | 亚洲在线网址 | 国产在线视频导航 | 在线天堂中文在线资源网 | 国产精品美女久久久久久久 | 深爱婷婷激情 | 国产精品高潮呻吟久久久久 | 色婷在线| 国产日韩精品一区二区在线观看播放 | 国产精品麻豆视频 | 亚洲精品无 | 在线观看日韩av | 亚洲精品日韩在线观看 | 99热在 | 久久成人一区 | 亚洲 成人 一区 | 99久久精品免费看国产麻豆 | 久久精品91久久久久久再现 | 中文字幕一区二区三区在线播放 | 精品在线一区二区三区 | 国产亚洲精品久久久久久久久久久久 | av电影中文字幕 | 亚洲一区二区精品3399 | 人人插人人搞 | av在线专区 | 日韩欧美aaa | 人人干人人搞 | 在线电影 你懂得 | 91热爆在线观看 | 不卡视频国产 | 婷婷久久亚洲 | 黄色影院在线观看 | 久久伊人婷婷 | 午夜精品一二区 | 国产一级二级在线 | 国产一级久久 | 天天插狠狠干 | av在线免费观看网站 | 日韩精品播放 | 美女网站黄免费 | 国产精品成人aaaaa网站 | 黄色大片日本免费大片 | 夜夜操网站 | 久久成人在线视频 | 九九视频精品在线 | www九九热| 视频在线观看入口黄最新永久免费国产 | 高清日韩一区二区 | 在线 成人 | 五月婷久久 | 久久久伊人网 | 国产午夜激情视频 | 国产精品视频观看 | 一区二区成人国产精品 | 9999毛片 | 亚洲第五色综合网 | 黄色在线观看污 | 日本精品一区二区三区在线播放视频 | 五月天激情开心 | 色婷婷综合成人av | 免费精品视频在线观看 | 中文字幕乱在线伦视频中文字幕乱码在线 | 草久久av | 国产不卡在线 | 久久久亚洲麻豆日韩精品一区三区 | 日韩免费观看一区二区 | 婷婷在线色| 精品久久久国产 | 中文字幕在线看视频国产中文版 | 精品国自产在线观看 | 亚洲在线免费视频 | 99精品小视频 | 国偷自产中文字幕亚洲手机在线 | 国产精品18毛片一区二区 | 亚洲丁香久久久 | 亚洲精品乱码久久久久久蜜桃动漫 | 91在线看视频 | 成年人免费在线观看网站 | 国产伦理久久精品久久久久_ | 91视频免费国产 | 四虎国产精品免费 | 亚州人成在线播放 | 色综合www| 久久精品精品电影网 | 在线观看免费av网站 | 久久1电影院 | 久久精品一区二区三区中文字幕 | 国产成人一区二区在线观看 | 九九亚洲视频 | 97精品电影院 | 去干成人网 | 天天插天天操天天干 | 97超级碰碰碰碰久久久久 | 久久久久99精品国产片 | 国产手机视频在线播放 | 日韩成人精品一区二区 | 日日夜夜婷婷 | 亚洲91精品在线观看 | 日本性视频 | 国产视频资源在线观看 | 亚洲激情在线视频 | 中文一区二区三区在线观看 | 国产精品国产三级在线专区 | 亚洲精品久久久久中文字幕二区 | 欧美国产精品一区二区 | 国产91学生粉嫩喷水 | 国产成人一区二区三区 | 日韩电影在线观看一区二区三区 | www.久久免费视频 | 亚洲精品视频中文字幕 | 成年人免费电影 | 午夜精品一区二区三区在线播放 | 久久综合九色 | 激情综合啪 | 91av官网 | 亚洲精品动漫在线 | 亚洲高清久久久 | 欧美一区二区三区在线视频观看 | 久久精品国产成人 | 日韩中文字幕免费视频 | 久久久精品国产一区二区三区 | www.天天干 | 99久久婷婷国产综合精品 | 亚洲国产97在线精品一区 | 免费在线观看av的网站 | 中文字幕传媒 | 欧美精品久久久久久 | 久久久精品免费看 | 国产视频在线看 | 亚洲午夜久久久久久久久久久 | 日韩在线国产精品 | 亚洲成人在线免费 | 国产精品久久久精品 | 中文字幕免费高清 | 亚洲五月| 日韩精品久久久免费观看夜色 | 日日天天狠狠 | 久久免费a| 国产亚洲欧美在线视频 | 最新国产中文字幕 | 欧美日韩不卡在线观看 | 成人毛片久久 | 探花视频在线观看 | 欧美精品久 | 久久国产一区 | 夜夜爽夜夜操 | 天天射射天天 | 精品国产一区在线观看 | 国产精品高潮呻吟久久av无 | 五月激情片| 亚洲午夜av久久乱码 | 国产精华国产精品 | 亚洲欧洲精品一区二区精品久久久 | 99热精品在线 | 国产91aaa | 欧美国产日韩一区二区三区 | 五月婷婷综合在线观看 | www.久热| 日韩欧美在线高清 | 亚洲在线高清 | 亚洲精品字幕在线 | 成人h动漫精品一区二 | 亚洲国内精品在线 | 免费观看性生活大片3 | 色综合久久久久综合体桃花网 | 91人人视频在线观看 | 色婷婷丁香 | 日韩在线观看免费 | 国内精品久久久 | 日韩在线视频精品 | 国产视 | 91精品一区二区在线观看 | 免费的黄色av | 亚欧日韩av| 伊人狠狠色丁香婷婷综合 | 丁香综合网| 亚洲精品免费观看视频 | 婷婷爱五月天 | 香蕉视频91 | 人人讲| 91av中文字幕 | 激情中文字幕 | 国产91九色蝌蚪 | 日韩欧美aaa | 国产精品乱码一区二区视频 | 久久久久成人免费 | 国产福利免费在线观看 | 亚洲一区二区黄色 | 国产在线不卡精品 | 91九色视频在线 | 久久久久一区二区三区 | 91色亚洲| 日韩精品免费在线 | 久久精品视频2 | 97国产大学生情侣白嫩酒店 | 国产日韩欧美在线免费观看 | av网站在线免费观看 | 成人免费影院 | 狠狠色丁婷婷日日 | 中文字幕在线人 | 久久久久久久久久伊人 | 人人干天天干 | 五月婷婷色 | 男女激情网址 | 久草在线资源观看 | 免费一级黄色 | 国产精品免费看 | 成人一区在线观看 | 国产午夜精品一区 | 国产亚洲精品久久网站 | 久久久首页 | 久久99久久99精品免观看粉嫩 | h视频在线看 | 免费黄a大片 | 成年人在线免费看视频 | 免费日韩一级片 | 日韩在线国产精品 | 国产原创av在线 | 亚洲国产精久久久久久久 | 亚洲视频aaa | 91九色视频观看 | 国产91精品在线观看 | 欧美日韩一区二区三区视频 | 国产精品黄色影片导航在线观看 | 国产91在线观| 天天操天天色天天 | 国产无区一区二区三麻豆 | 99视频国产在线 | 天堂av免费 | 亚洲国产成人av网 | 亚洲精品国产精品国自产观看浪潮 | 国产在线观看地址 | 在线观看不卡视频 | 国产精品第54页 | 精品国产亚洲一区二区麻豆 | 色午夜| 中文字幕第一页在线 | 天无日天天操天天干 | 成人免费在线视频观看 | 国产黄色精品在线观看 | 国产成人精品国内自产拍免费看 | 91色欧美| 成片免费观看视频999 | 91麻豆精品国产 | 日韩免费在线观看视频 | 六月天综合网 | 欧美日韩高清 | 亚洲激情免费 | 91最新中文字幕 | 欧美日韩在线免费视频 | 天天干夜夜爱 | 97免费在线视频 | 成年人免费在线观看 | 久久免费99精品久久久久久 | av大片免费在线观看 | 色综合久久88色综合天天人守婷 | 成人av一级片 | 91视频久久久久 | 国产高清视频免费观看 | 91视频麻豆 | 91热这里只有精品 | 2019国产精品 | 亚洲一区二区三区四区在线视频 | 日本精品久久久久中文字幕5 | 美女网站视频久久 | 2021av在线 | 精品一区二区久久久久久久网站 | 国产婷婷vvvv激情久 | 在线日韩中文 | 黄色日视频 | 丁香婷婷激情网 | 在线看国产日韩 | 激情开心站 | 欧美人zozo| 日韩91av| 欧美日韩调教 | 国产精品99久久久久久久久久久久 | 久草视频在线新免费 | 四季av综合网站 | 日韩毛片在线免费观看 | 伊人婷婷久久 | 久久人人做 | 99久久99久久精品国产片 | 国产精品密入口果冻 | 日本成人中文字幕在线观看 | 不卡视频在线看 | 日韩在线视频播放 | av中文字幕av | 亚洲资源网 | 91九色在线 | 国产精品午夜久久 | 黄色性av | 精品字幕在线 | 黄网站色视频免费观看 | 色综合久久久久网 | 国产99中文字幕 | 久久久久久久久久国产精品 | 香蕉成人在线视频 | 伊人婷婷综合 | 99视频网址 | 国产一区二区久久久 | 视频99爱| 美女黄久久 | 成人在线视频免费观看 | 成年人在线免费看视频 | av噜噜噜在线播放 | 国产精品h在线观看 | 另类五月激情 | 国产精品乱码高清在线看 | 国产视频精品免费 | 成人av电影在线观看 | 日韩精品视频网站 | 久久国产精品免费看 | 日韩a免费| 日韩欧美在线观看一区 | 91尤物在线播放 | 天天射天天干天天插 | 超碰97国产| 久久精品视频在线 | 日韩午夜精品福利 | 五月婷婷黄色网 | 精品久久久久久久久久 | 国产精品国产三级国产 | 四虎影视精品永久在线观看 | 婷婷丁香色综合狠狠色 | 国产视频首页 | 狠狠狠狠狠狠狠狠 | 亚洲欧美视频在线 | 亚洲精品影视 | 日韩天天干 | 日韩精品一二三 | 丝袜美腿一区 | 色美女在线 | 免费在线激情电影 | 在线日本v二区不卡 | 二区三区视频 | 欧美国产日韩一区 | 婷婷丁香久久五月婷婷 | 久久久久久久久精 | 久久久久女教师免费一区 | 色网站黄 | 97偷拍在线视频 | 国产高清专区 | 日韩av中文在线观看 | 精品视频 | 国产一二三在线视频 | 国产精品一区二区三区在线免费观看 | 男女精品久久 | 日韩中文字幕第一页 | 精品国产区 | 美女网站免费福利视频 | 久久精品视频在线看 | 91精品久久久久久久99蜜桃 | 国产91精品久久久久久 | 日韩免费看视频 | www.av在线.com | 中文字幕在线视频国产 | 中文字幕 成人 | 黄色小说视频在线 | 日韩视频图片 | 天天曰夜夜爽 | 美女网站在线播放 | 五月的婷婷 | 亚洲精品综合欧美二区变态 | 色综合天天综合网国产成人网 | 亚洲欧美日韩国产一区二区三区 | 久久久久久久久免费 | 成人三级黄色 | 日韩精品在线播放 | 国产香蕉视频在线播放 | 九九热99视频 | 伊人激情网 | 手机在线看永久av片免费 | 欧美一级黄色视屏 | 黄色网中文字幕 | 国产高清在线a视频大全 | 国产99久久久国产精品免费看 | 国产91精品一区二区麻豆网站 | 国产又黄又猛又粗 | 色橹橹欧美在线观看视频高清 | 十八岁以下禁止观看的1000个网站 | 香蕉久久久久久av成人 | 中文字幕在线观看一区 | 中文在线√天堂 | 天天干,天天草 | 久久精品亚洲一区二区三区观看模式 | 国产在线精品二区 | 亚洲午夜精品电影 | 久久激情片 | 国产91免费观看 | 久草视频在线播放 | 黄色毛片观看 | 97超碰中文字幕 | 欧美a影视 | 美女久久久久久久久久 | 欧美日韩视频在线一区 | 在线观看精品视频 | 国产美女永久免费 | 国产精品一区二区三区观看 | 久久这里只精品 | 国产黄色资源 | 午夜男人影院 | 97偷拍视频| 国产一级做a爱片久久毛片a | 日韩在线在线 | 久久三级视频 | 国产a国产a国产a | 999精品| 91高清完整版在线观看 | 日韩电影在线一区 | 超碰在97| 日韩在线播放欧美字幕 | 国产精品一区二区三区免费视频 | 精品免费一区二区三区 | 久久亚洲区 | 蜜臀av在线一区二区三区 | 亚洲精品久久久蜜桃 | 二区视频在线 | 中文字幕频道 | 特级毛片在线 | 偷拍久久久 | 婷婷成人综合 | 天天天天射| 丁香 婷婷 激情 | 亚洲国产精品99久久久久久久久 | 国产精品国内免费一区二区三区 | 免费av电影网站 | av+在线播放在线播放 | 欧美日韩精品影院 | 国产 日韩 中文字幕 | 国产99精品 | 黄色一级影院 | 在线看v片| 成人电影毛片 | 国产精品视频在线观看 | 欧美日韩高清一区 | 亚洲免费小视频 | 偷拍福利视频一区二区三区 | www欧美xxxx| 欧美日韩国产伦理 | 国内丰满少妇猛烈精品播放 | 视频一区在线播放 | 麻豆视频在线免费观看 | 超碰国产在线观看 | 日韩精品免费一区二区三区 | 久久av伊人 | 色多多污污在线观看 | 久久久色 | 日本不卡一区二区三区在线观看 | 亚洲日本黄色 | 亚洲欧美日韩一区二区三区在线观看 | 欧美另类tv| 麻豆你懂的 | 成年人在线视频观看 | 国产99久久久国产精品 | 草樱av | 亚洲精品国偷拍自产在线观看蜜桃 | 色天天综合网 | 五月天视频网站 | 国产精品国产精品 | 欧美性大战久久久久 | 国产高清黄 | 九九涩涩av台湾日本热热 | 亚洲精品综合一区二区 | av电影中文 | 国产真实在线 | 国产区免费在线 | 狠狠色噜噜狠狠狠狠2021天天 | 成人97视频一区二区 | 国产群p| 久久久久女教师免费一区 | 黄色一级大片免费看 | 欧洲精品视频一区二区 | 一区二区三区电影 | 日本精品一区二区三区在线观看 | 日韩成人高清在线 | 亚洲精品天天 | 韩国在线视频一区 | 国产精品18久久久久久久 | 精品国产一区二区三区久久 | 中文字幕在线资源 | 亚洲综合色视频在线观看 | 亚洲精品视频国产 | 天天se天天cao天天干 | 亚洲国产精品久久久久婷婷884 | 深爱激情五月综合 | 久久精品久久久久电影 | 久久五月情影视 | 欧美性久久久久久 | 69视频网站| 婷婷六月色 | 全久久久久久久久久久电影 | 国内综合精品午夜久久资源 | 激情开心色 | 婷婷丁香激情综合 | 亚洲情感电影大片 | 婷婷丁香色综合狠狠色 | 国产精品mv | 最新av在线播放 | 亚洲欧美精品在线 | 国产免费黄视频在线观看 | 天无日天天操天天干 | 欧美小视频在线观看 | 亚洲精品 在线视频 | 免费看的黄色 | 麻豆极品| av无限看 | 99r国产精品 | 7777精品伊人久久久大香线蕉 | 中文字幕在线看 | 一区 二区 精品 | 五月婷婷在线观看视频 | 国产精品一区二区三区在线播放 | 成人网444ppp | 在线观看午夜 | 18久久久久久 | 中文视频一区二区 | 色视频网站在线 | 成人影视免费看 | 91超在线 | 国内精品视频免费 | 国产视频在线播放 | 亚洲精品456在线播放第一页 | 激情伊人| 日韩美在线 | 91av视频免费观看 | 伊人中文网 | www.com.黄 | 免费在线一区二区 | 日韩一级电影在线观看 | 国产又粗又硬又爽视频 | 精品国产亚洲在线 | 欧美极品少妇xbxb性爽爽视频 | 国产麻豆视频在线观看 | 婷五月激情 | 欧美久草视频 | 亚洲闷骚少妇在线观看网站 | 狠狠狠狠狠色综合 | 中文字幕黄色网址 | 国产一区二区在线免费 | 91爱在线| 亚洲黄色免费网站 | 色偷偷男人的天堂av | 国产中文伊人 | 久久综合网色—综合色88 | 久久精品影片 | 在线天堂视频 | 国产精品一区专区欧美日韩 | 亚洲1区 在线 | 国产精品美女久久久网av | 九九热视频在线播放 | 国产亚洲精品日韩在线tv黄 | 国内亚洲精品 | 精品久久九九 | 国产精品久久久久一区 | 91精品久 | 久久人人爽人人爽人人片av免费 |