# 使用模板的好處
ThinkPHP內置了一個基于XML的性能卓越的模板引擎 ThinkTemplate,這是一個專門為ThinkPHP服務的內置模板引擎。ThinkTemplate是一個使用了XML標簽庫技術的編譯型模板引擎,支持兩種類型的模板標簽,使用了動態編譯和緩存技術,而且支持自定義標簽庫。其特點包括:
- 支持XML標簽庫和普通標簽的混合定義;
- 支持直接使用PHP代碼書寫;
- 支持文件包含;
- 支持多級標簽嵌套;
- 支持布局模板功能;
- 一次編譯多次運行,編譯和運行效率非常高;
- 模板文件和布局模板更新,自動更新模板緩存;
- 系統變量無需賦值直接輸出;
- 支持多維數組的快速輸出;
- 支持模板變量的默認值;
- 支持頁面代碼去除Html空白;
- 支持變量組合調節器和格式化功能;
- 允許定義模板禁用函數和禁用PHP語法;
- 通過標簽庫方式擴展。
每個模板文件在執行過程中都會生成一個編譯后的緩存文件,其實就是一個可以運行的PHP文件。模板緩存默認位于項目的Runtime/模塊/Cache目錄下面,以模板文件的md5編碼作為緩存文件名保存的。如果在模板標簽的使用過程中發現問題,可以嘗試通過查看模板緩存文件找到問題所在。
內置的模板引擎支持普通標簽和XML標簽方式兩種標簽定義,分別用于不同的目的:
| 標簽類型 | 描述 |
|-----|-----|
| 普通標簽 | 主要用于輸出變量和做一些基本的操作 |
| XML標簽 | 主要完成一些邏輯判斷、控制和循環輸出,并且可擴展 |
這種方式的結合保證了模板引擎的簡潔和強大的有效融合。
# 邏輯概念上的視圖
前面講了控制器和模型,分別對應 MVC 中的 M 和 C。 而ThinkPHP中的V,就是視圖,不需要定義視圖文件,只是輸出視圖時,可能需要模板文件TPL,使用時不需要定義單獨的視圖類。
# 通向模板前的道路
## 位置
決定模板所在位置的有幾個配置:
- `DEFAULT_V_LAYER` 視圖層名稱配置,默認是View,變了應用下的名稱也得變
- `DEFAULT_THEME` 默認主題名稱配置,默認空。 如果定義了View下會多主題目錄
## 模板中的變量從何而來
### 1. 控制器里assign賦值 如 `$this->assign('data', 'data');`
### 2. 控制器里的屬性 `$this->data = 'data';`
### 3. 模板中assign標簽賦值 `<assign name="data" value="data" />` 當然賦值標簽后才能獲取,前面的看之前控制器有沒有賦值data,沒有就是空了。
## 獲取模板地址
為了更方便的輸出模板文件,新版封裝了一個T函數用于生成模板文件名。
用法:
T([資源://][模塊@][主題/][控制器/]操作,[視圖分層])T函數的返回值是一個完整的模板文件名,可以直接用于display和fetch方法進行渲染輸出。
例如:
~~~
T('Public/menu');
// 返回 當前模塊/View/Public/menu.html
T('blue/Public/menu');
// 返回 當前模塊/View/blue/Public/menu.html
T('Public/menu','Tpl');
// 返回 當前模塊/Tpl/Public/menu.html
T('Public/menu');
// 如果TMPL_FILE_DEPR 為 _ 返回 當前模塊/Tpl/Public_menu.html
T('Public/menu');
// 如果TMPL_TEMPLATE_SUFFIX 為.tpl 返回 當前模塊/Tpl/Public/menu.tpl
T('Admin@Public/menu');
// 返回 Admin/View/Public/menu.html
T('Extend://Admin@Public/menu');
// 返回 Extend/Admin/View/Public/menu.html (Extend目錄取決于AUTOLOAD_NAMESPACE中的配置)
~~~
在display方法中直接使用T函數:
~~~
// 使用T函數輸出模板
$this->display(T('Admin@Public/menu'));
~~~
> T函數可以輸出不同的視圖分層模板。
## 渲染模板
渲染模板輸出最常用的是使用display方法,調用格式:
display('[模板文件]'[,'字符編碼'][,'輸出類型'])模板文件的寫法支持下面幾種:
| 用法 | 描述 |
|-----|-----|
| 不帶任何參數 | 自動定位當前操作的模板文件 |
| [模塊@][控制器:][操作] | 常用寫法,支持跨模塊 模板主題可以和theme方法配合 |
| 完整的模板文件名 | 直接使用完整的模板文件名(包括模板后綴) |
下面是一個最典型的用法,不帶任何參數:
~~~
// 不帶任何參數 自動定位當前操作的模板文件
$this->display();
~~~
表示系統會按照默認規則自動定位模板文件,其規則是:
如果當前沒有啟用模板主題則定位到:`當前模塊/默認視圖目錄/當前控制器/當前操作.html` 如果有啟用模板主題則定位到:`當前模塊/默認視圖目錄/當前主題/當前控制器/當前操作.html`
如果有更改TMPL_FILE_DEPR設置(假設 `'TMPL_FILE_DEPR'=>'_'`)的話,則上面的自動定位規則變成: `當前模塊/默認視圖目錄/當前控制器_當前操作.html` 和 `當前模塊/默認視圖目錄/當前主題/當前控制器_當前操作.html`。
所以通常display方法無需帶任何參數即可輸出對應的模板,這是模板輸出的最簡單的用法。
> 通常默認的視圖目錄是View
如果沒有按照模板定義規則來定義模板文件(或者需要調用其他控制器下面的某個模板),可以使用:
~~~
// 指定模板輸出
$this->display('edit');
~~~
表示調用當前控制器下面的edit模板
~~~
$this->display('Member:read');
~~~
表示調用Member控制器下面的read模板。
如果我們使用了模板主題功能,那么也可以支持跨主題調用,使用:
~~~
$this->theme('blue')->display('User:edit');
~~~
表示調用blue主題下面的User控制器的edit模板。
如果你不希望每個主題都重復定義一些相同的模版文件的話,還可以啟用差異主題定義方式,設置:
~~~
'TMPL_LOAD_DEFAULTTHEME'=>true
~~~
設置后,如果blue主題下面不存在edit模板的話,就會自動定位到默認主題中的edit模板。
渲染輸出不需要寫模板文件的路徑和后綴,確切地說,這里面的控制器和操作并不一定需要有實際對應的控制器和操作,只是一個目錄名稱和文件名稱而已,例如,你的項目里面可能根本沒有Public控制器,更沒有Public控制器的menu操作,但是一樣可以使用
~~~
$this->display('Public:menu');
~~~
輸出這個模板文件。理解了這個,模板輸出就清晰了。
display方法支持在渲染輸出的時候指定輸出編碼和類型,例如,可以指定編碼和類型:
~~~
$this->display('read', 'utf-8', 'text/xml');
~~~
表示輸出XML頁面類型(配合你的應用需求可以輸出很多類型)。
事情總有特例,如果的模板目錄是自定義的,或者根本不需要按模塊進行分目錄存放,那么默認的display渲染規則就不能處理,這個時候,我們就需要使用另外一種方式來應對,直接傳入模板文件名即可,例如:
~~~
$this->display('./Template/Public/menu.html');
~~~
這種方式需要指定模板路徑和后綴,這里的Template/Public目錄是位于當前項目入口文件位置下面。如果是其他的后綴文件,也支持直接輸出,例如:`$this->display('./Template/Public/menu.tpl');`
只要`./Template/Public/menu.tpl`是一個實際存在的模板文件。
> 要注意模板文件位置是相對于項目的入口文件,而不是模板目錄。
## 獲取模板內容
如果需要獲取渲染模板的輸出內容而不是直接輸出,可以使用fetch方法。
fetch方法的用法和display基本一致(只是不需要指定輸出編碼和輸出類型):
fetch('模板文件')模板文件的調用方法和display方法完全一樣,區別就在于fetch方法渲染后不是直接輸出,而是返回渲染后的內容,例如:
~~~
$content = $this->fetch('Member:edit');
~~~
使用fetch方法獲取渲染內容后,你可以進行過濾和替換等操作,或者用于對輸出的復雜需求。
### 渲染內容
如果你沒有定義任何模板文件,或者把模板內容存儲到數據庫中的話,你就需要使用show方法來渲染輸出了,show方法的調用格式:
show('渲染內容'[,'字符編碼'][,'輸出類型']) 例如,`$this->show($content);`
也可以指定編碼和類型: `$this->show($content, 'utf-8', 'text/xml');`
> show方法中的內容也可以支持模板解析。
# 模板使用的技巧
## 主題
一個模塊如果需要支持多套模板文件的話,就可以使用模板主題功能。 默認情況下,沒有開啟模板主題功能,如果需要開啟,設置 **DEFAULT_THEME** 參數即可:
~~~
// 設置默認的模板主題
'DEFAULT_THEME' => 'default'
~~~
采用模板主題后,需要在視圖目錄下面創建對應的主題目錄,和不啟用模板主題的情況相比,模板文件只是多了一層目錄:
~~~
View/User/add.html // 沒有啟用模板主題之前
View/default/User/add.html // 啟用模板主題之后
~~~
在視圖渲染輸出之前,我們可以通過動態設置來改變需要使用的模板主題。
~~~
// 在控制器中動態改變模板主題
$this->theme('blue')->display('add');
~~~
## 模板繼承
模板繼承是一項更加靈活的模板布局方式,模板繼承不同于模板布局,甚至來說,應該在模板布局的上層。模板繼承其實并不難理解,就好比類的繼承一樣,模板也可以定義一個基礎模板(或者是布局),并且其中定義相關的區塊(block),然后繼承(extend)該基礎模板的子模板中就可以對基礎模板中定義的區塊進行重載。
因此,模板繼承的優勢其實是設計基礎模板中的區塊(block)和子模板中替換這些區塊。
每個區塊由`<block></block>`標簽組成。 下面就是基礎模板中的一個典型的區塊設計(用于設計網站標題):
~~~
<block name="title"><title>網站標題</title></block>
~~~
block標簽必須指定name屬性來標識當前區塊的名稱,這個標識在當前模板中應該是唯一的,block標簽中可以包含任何模板內容,包括其他標簽和變量,例如:
~~~
<block name="title"><title>{$web_title}</title></block>
~~~
你甚至還可以在區塊中加載外部文件:
~~~
<block name="include"><include file="Public:header" /></block>
~~~
一個模板中可以定義任意多個名稱標識不重復的區塊,例如下面定義了一個`base.html`基礎模板:
~~~
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<block name="title"><title>標題</title></block>
</head>
<body>
<block name="menu">菜單</block>
<block name="left">左邊分欄</block>
<block name="main">主內容</block>
<block name="right">右邊分欄</block>
<block name="footer">底部</block>
</body>
</html>
~~~
然后我們在子模板(其實是當前操作的入口模板)中使用繼承:
~~~
<extend name="base" />
<block name="title"><title>{$title}</title></block>
<block name="menu">
<a href="/" >首頁</a>
<a href="/info/" >資訊</a>
<a href="/bbs/" >論壇</a>
</block>
<block name="left"></block>
<block name="content">
<volist name="list" id="vo">
<a href="/new/{$vo.id}">{$vo.title}</a><br/>
{$vo.content}
</volist>
</block>
<block name="right">
最新資訊:
<volist name="news" id="new">
<a href="/new/{$new.id}">{$new.title}</a><br/>
</volist>
</block>
<block name="footer">
@ThinkPHP2012 版權所有
</block>
~~~
可以看到,子模板中使用了extend標簽定義需要繼承的模板,extend標簽的用法和include標簽一樣,你也可以加載其他模板:
~~~
<extend name="Public:base" />
~~~
或者使用絕對文件路徑加載
~~~
<extend name="./Template/Public/base.html" />
~~~
在當前子模板中,只能定義區塊而不能定義其他的模板內容,否則將會直接忽略,并且只能定義基礎模板中已經定義的區塊。
例如,如果采用下面的定義:
~~~
<block name="title"><title>{$title}</title></block>
<a href="/" >首頁</a>
<a href="/info/" >資訊</a>
<a href="/bbs/" >論壇</a>
~~~
導航部分將是無效的,不會顯示在模板中。
在子模板中,可以對基礎模板中的區塊進行重載定義,如果沒有重新定義的話,則表示沿用基礎模板中的區塊定義,如果定義了一個空的區塊,則表示刪除基礎模板中的該區塊內容。 上面的例子,我們就把left區塊的內容刪除了,其他的區塊都進行了重載。
子模板中的區塊定義順序是隨意的,模板繼承的用法關鍵在于基礎模板如何布局和設計規劃了,如果結合原來的布局功能,則會更加靈活。
## 模板布局
ThinkPHP的模板引擎內置了布局模板功能支持,可以方便的實現模板布局以及布局嵌套功能。
有三種布局模板的支持方式:
### 第一種方式:全局配置方式
這種方式僅需在項目配置文件中添加相關的布局模板配置,就可以簡單實現模板布局功能,比較適用于全站使用相同布局的情況,需要配置開啟LAYOUT_ON 參數(默認不開啟),并且設置布局入口文件名LAYOUT_NAME(默認為layout)。
~~~
'LAYOUT_ON'=>true,
'LAYOUT_NAME'=>'layout',
~~~
開啟LAYOUT_ON后,我們的模板渲染流程就有所變化,例如:
~~~
namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller{
Public function add() {
$this->display('add');
}
}
~~~
在不開啟LAYOUT_ON布局模板之前,會直接渲染 `Application/Home/View/User/add.html` 模板文件,開啟之后,首先會渲染`Application/Home/View/layout.html` 模板,布局模板的寫法和其他模板的寫法類似,本身也可以支持所有的模板標簽以及包含文件,區別在于有一個特定的輸出替換變量`{__CONTENT__}`,例如,下面是一個典型的layout.html模板的寫法:
~~~
<include file="Public:header" />
{__CONTENT__}
<include file="Public:footer" />
~~~
讀取layout模板之后,會再解析`User/add.html` 模板文件,并把解析后的內容替換到layout布局模板文件的{**CONTENT**} 特定字符串。
當然可以通過設置來改變這個特定的替換字符串,例如:
~~~
'TMPL_LAYOUT_ITEM' => '{__REPLACE__}'
~~~
> 一個布局模板同時只能有一個特定替換字符串。
采用這種布局方式的情況下,一旦User/add.html 模板文件或者layout.html布局模板文件發生修改,都會導致模板重新編譯。
如果需要指定其他位置的布局模板,可以使用:
~~~
'LAYOUT_NAME'=>'Layout/layoutname',
~~~
就表示采用`Application/Home/View/Layout/layoutname.html`作為布局模板。
如果某些頁面不需要使用布局模板功能,可以在模板文件開頭加上 `{__NOLAYOUT__}` 字符串。
如果上面的User/add.html 模板文件里面包含有`{__NOLAYOUT__}`,則即使當前開啟布局模板,也不會進行布局模板解析。
### 第二種方式:模板標簽方式
這種布局模板不需要在配置文件中設置任何參數,也不需要開啟LAYOUT_ON,直接在模板文件中指定布局模板即可,相關的布局模板調整也在模板中進行。
以前面的輸出模板為例,這種方式的入口還是在User/add.html 模板,但是我們可以修改下add模板文件的內容,在頭部增加下面的布局標簽(記得首先關閉前面的LAYOUT_ON設置,否則可能出現布局循環):
~~~
<layout name="layout" />
~~~
表示當前模板文件需要使用`layout.html` 布局模板文件,而布局模板文件的寫法和上面第一種方式是一樣的。當渲染`User/add.html` 模板文件的時候,如果讀取到layout標簽,則會把當前模板的解析內容替換到layout布局模板的{**CONTENT**} 特定字符串。
一個模板文件中只能使用一個布局模板,如果模板文件中沒有使用任何layout標簽則表示當前模板不使用任何布局。
如果需要使用其他的布局模板,可以改變layout的name屬性,例如:
~~~
<layout name="newlayout" />
~~~
還可以在layout標簽里面指定要替換的特定字符串:
~~~
<layout name="Layout/newlayout" replace="{__REPLACE__}" />
~~~
由于所有include標簽引入的文件都支持layout標簽,所以,我們可以借助layout標簽和include標簽相結合的方式實現布局模板的嵌套。例如,上面的例子
~~~
<include file="Public:header" />
<div id="main" class="main" >
{__CONTENT__}
</div>
<include file="Public:footer" />
~~~
在引入的header和footer模板文件中也可以添加layout標簽,例如header模板文件的開頭添加如下標簽:
~~~
<layout name="menu" />
~~~
這樣就實現了在頭部模板中引用了menu布局模板。
也可以采用兩種布局方式的結合,可以實現更加復雜的模板布局以及嵌套功能。
### 第三種方式:使用layout控制模板布局
使用內置的layout方法可以更靈活的在程序中控制模板輸出的布局功能,尤其適用于局部需要布局或者關閉布局的情況,這種方式也不需要在配置文件中開啟LAYOUT_ON。例如:
~~~
namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller{
Public function add() {
layout(true);
$this->display('add');
}
}
~~~
表示當前的模板輸出啟用了布局模板,并且采用默認的layout布局模板。
如果當前輸出需要使用不同的布局模板,可以動態的指定布局模板名稱,例如:
~~~
namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller{
Public function add() {
layout('Layout/newlayout');
$this->display('add');
}
}
~~~
或者使用layout方法動態關閉當前模板的布局功能(這種用法可以配合第一種布局方式,例如全局配置已經開啟了布局,可以在某個頁面單獨關閉):
~~~
namespace Home\Controller;
use Think\Controller;
Class UserController extends Controller{
Public function add() {
layout(false); // 臨時關閉當前模板的布局功能
$this->display('add');
}
}
~~~
> 三種模板布局方式中,第一種和第三種是在程序中配置實現模板布局,第二種方式則是單純通過模板標簽在模板中使用布局。具體選擇什么方式,需要根據項目的實際情況來了。
## 模板注釋
模板支持注釋功能,該注釋文字在最終頁面不會顯示,僅供模板制作人員參考和識別。
## 單行注釋
格式:
~~~
{/* 注釋內容 */ } 或 {// 注釋內容 }
~~~
例如:
~~~
{// 這是模板注釋內容 }
~~~
> 注意{和注釋標記之間不能有空格。
## 多行注釋
支持多行注釋,例如:
~~~
{/* 這是模板
注釋內容*/ }
~~~
模板注釋支持多行,模板注釋在生成編譯緩存文件后會自動刪除,這一點和Html的注釋不同。
## 原樣輸出
可以使用`literal`標簽來防止模板標簽被解析,例如:
~~~
<literal>
<if condition="$name eq 1 "> value1
<elseif condition="$name eq 2"/>value2
<else /> value3
</if>
</literal>
~~~
上面的if標簽被literal標簽包含,因此if標簽里面的內容并不會被模板引擎解析,而是保持原樣輸出。
如果你的php標簽中需要輸出類似{$user} 或者 XML標簽的情況,可以通過添加literal標簽解決混淆問題,例如:
~~~
<php>echo '{$Think.config.CUSTOM.'.$key.'}';</php>
~~~
這個php標簽中的{$Think 可能會被模板引擎誤當做標簽解析,解決的辦法就是加上literal,例如:
~~~
<php><literal>echo '{$Think.config.CUSTOM.'.$key.'}';</literal></php>
~~~
Literal標簽還可以用于頁面的JS代碼外層,確保JS代碼中的某些用法和模板引擎不產生混淆。
總之,所有可能和內置模板引擎的解析規則沖突的地方都可以使用literal標簽處理。
# 模板中TP使用
Think模板引擎使用,其他的如Smarty模板可以參考手冊
## 輸出變量
在模板中輸出變量的方法很簡單,例如,在控制器中我們給模板變量賦值:
~~~
$name = 'ThinkPHP';
$this->assign('name',$name);
$this->display();
~~~
然后就可以在模板中使用:
~~~
Hello,{$name}!
~~~
模板編譯后的結果就是:
~~~
Hello,<?php echo($name);?>!
~~~
這樣,運行的時候就會在模板中顯示: `Hello,ThinkPHP!`
注意模板標簽的`{`和`$`之間不能有任何的空格,否則標簽無效。所以,下面的標簽
~~~
Hello,{ $name}!
~~~
將不會正常輸出name變量,而是直接保持不變輸出: `Hello,{ $name}!`
普通標簽默認開始標記是`{`,結束標記是 `}`。也可以通過設置`TMPL_L_DELIM`和`TMPL_R_DELIM`進行更改。例如,我們在項目配置文件中定義:
~~~
'TMPL_L_DELIM'=>'<{',
'TMPL_R_DELIM'=>'}>',
~~~
那么,上面的變量輸出標簽就應該改成:
~~~
Hello,<{$name}>!
~~~
后面的內容我們都以默認的標簽定義來說明。
模板標簽的變量輸出根據變量類型有所區別,剛才我們輸出的是字符串變量,如果是數組變量,
~~~
$data['name'] = 'ThinkPHP';
$data['email'] = 'thinkphp@qq.com';
$this->assign('data',$data);
~~~
那么,在模板中我們可以用下面的方式輸出:
~~~
Name:{$data.name}
Email:{$data.email}
~~~
或者用下面的方式也是有效:
~~~
Name:{$data['name']}
Email:{$data['email']}
~~~
> 當我們要輸出多維數組的時候,往往要采用后面一種方式。
如果data變量是一個對象(并且包含有name和email兩個屬性),那么可以用下面的方式輸出:
~~~
Name:{$data:name}
Email:{$data:email}
~~~
或者
~~~
Name:{$data->name}
Email:{$data->email}
~~~
## 系統變量
### 系統變量輸出
普通的模板變量需要首先賦值后才能在模板中輸出,但是系統變量則不需要,可以直接在模板中輸出,系統變量的輸出通常以**{$Think** 打頭,例如:
~~~
{$Think.server.script_name} // 輸出$_SERVER['SCRIPT_NAME']變量
{$Think.session.user_id} // 輸出$_SESSION['user_id']變量
{$Think.get.pageNumber} // 輸出$_GET['pageNumber']變量
{$Think.cookie.name} // 輸出$_COOKIE['name']變量
~~~
支持輸出 `$_SERVER`、`$_ENV`、 `$_POST`、 `$_GET`、 `$_REQUEST`、`$_SESSION`和 `$_COOKIE`變量。
### 常量輸出
還可以輸出常量
~~~
{$Think.const.MODULE_NAME}
~~~
或者直接使用
~~~
{$Think.MODULE_NAME}
~~~
## 配置輸出
輸出配置參數使用:
~~~
{$Think.config.db_charset}
{$Think.config.url_model}
~~~
### 語言變量
輸出語言變量可以使用:
~~~
{$Think.lang.page_error}
{$Think.lang.var_error}
~~~
## 使用函數
我們往往需要對模板輸出變量使用函數,可以使用:
~~~
{$data.name|md5}
~~~
編譯后的結果是:
~~~
<?php echo (md5($data['name'])); ?>
~~~
如果函數有多個參數需要調用,則使用:
~~~
{$create_time|date="y-m-d",###}
~~~
表示date函數傳入兩個參數,每個參數用逗號分割,這里第一個參數是`y-m-d`,第二個參數是前面要輸出的`create_time`變量,因為該變量是第二個參數,因此需要用###標識變量位置,編譯后的結果是:
~~~
<?php echo (date("y-m-d",$create_time)); ?>
~~~
如果前面輸出的變量在后面定義的函數的第一個參數,則可以直接使用:
~~~
{$data.name|substr=0,3}
~~~
表示輸出
~~~
<?php echo (substr($data['name'],0,3)); ?>
~~~
雖然也可以使用:
~~~
{$data.name|substr=###,0,3}
~~~
但完全沒用這個必要。
還可以支持多個函數過濾,多個函數之間用“|”分割即可,例如:
~~~
{$name|md5|strtoupper|substr=0,3}
~~~
編譯后的結果是:
~~~
<?php echo (substr(strtoupper(md5($name)),0,3)); ?>
~~~
函數會按照從左到右的順序依次調用。
如果你覺得這樣寫起來比較麻煩,也可以直接這樣寫:
~~~
{:substr(strtoupper(md5($name)),0,3)}
~~~
> 變量輸出使用的函數可以支持內置的PHP函數或者用戶自定義函數,甚至是靜態方法。
## 默認值輸出
我們可以給變量輸出提供默認值,例如:
~~~
{$user.nickname|default="這家伙很懶,什么也沒留下"}
~~~
對系統變量依然可以支持默認值輸出,例如:
~~~
{$Think.get.name|default="名稱為空"}
~~~
默認值和函數可以同時使用,例如:
~~~
{$Think.get.name|getName|default="名稱為空"}
~~~
> 默認值輸出可以避免報notice錯誤,當某些數組鍵值沒有定義的時候
## 使用運算符
我們可以對模板輸出使用運算符,包括對“+”“ ” “*” “/”和“%”的支持。
例如:
| 運算符 | 使用示例 |
|-----|-----|
| + | {$a+$b} |
| - | {$a-$b} |
| * | {$a*$b} |
| / | {$a/$b} |
| % | {$a%$b} |
| ++ | {$a++} 或 {++$a} |
| -- | {$a--} 或 {--$a} |
| 綜合運算 | {$a+$b*10+$c} |
在使用運算符的時候,不再支持點語法和常規的函數用法,例如:
~~~
{$user.score+10} //錯誤的
{$user['score']+10} //正確的
{$user['score']*$user['level']} //正確的
{$user['score']|myFun*10} //錯誤的
{$user['score']+myFun($user['level'])} //正確的
~~~
> 總結就是運算符只支持原生變量寫法
## 標簽庫
內置的模板引擎除了支持普通變量的輸出之外,更強大的地方在于標簽庫功能。
標簽庫類似于Java的Struts中的JSP標簽庫,每一個標簽庫是一個獨立的標簽庫文件,標簽庫中的每一個標簽完成某個功能,采用XML標簽方式(包括開放標簽和閉合標簽)。
標簽庫分為內置和擴展標簽庫,內置標簽庫是Cx標簽庫。
### 導入標簽庫
使用taglib標簽導入當前模板中需要使用的標簽庫,例如:
~~~
<taglib name="html" />
~~~
> 如果沒有定義html標簽庫的話,則導入無效。
也可以導入多個標簽庫,使用:
~~~
<taglib name="html,article" />
~~~
導入標簽庫后,就可以使用標簽庫中定義的標簽了,假設article標簽庫中定義了read標簽:
~~~
<article:read name="hello" id="data" >
{$data.id}:{$data.title}
</article:read>
~~~
在上面的標簽中,`<article:read>... </article:read>` 就是閉合標簽,起始和結束標簽必須成對出現。
如果是 `<article:read name="hello" />` 就是開放標簽。
> 閉合和開放標簽取決于標簽庫中的定義,一旦定義后就不能混淆使用,否則就會出現錯誤。
### 內置標簽
內置標簽庫無需導入即可使用,并且不需要加XML中的標簽庫前綴,ThinkPHP內置的標簽庫是Cx標簽庫,所以,Cx標簽庫中的所有標簽,我們可以在模板文件中直接使用,我們可以這樣使用:
~~~
<eq name="status" value="1">
正常
</eq>
~~~
如果Cx不是內置標簽的話,可能就需要這么使用了:
~~~
<cx:eq name="status" value="1 >
正常
</cx:eq>
~~~
更多的Cx標簽庫中的標簽用法,參考[內置標簽](#)。
內置標簽庫可以簡化模板中標簽的使用,所以,我們還可以把其他的標簽庫定義為內置標簽庫(前提是多個標簽庫沒有標簽沖突的情況),例如:
~~~
'TAGLIB_BUILD_IN' => 'cx,article'
~~~
配置后,上面的標簽用法就可以改為:
~~~
<read name="hello" id="data" >
{$data.id}:{$data.title}
</read>
~~~
### 標簽庫預加載
標簽庫預加載是指無需手動在模板文件中導入標簽庫即可使用標簽庫中的標簽,通常用于某個標簽庫需要被大多數模板使用的情況。
在應用或者模塊的配置文件中添加:
~~~
'TAGLIB_PRE_LOAD' => 'article,html'
~~~
設置后,模板文件就不再需要使用
~~~
<taglib name="html,article" />
~~~
但是仍然可以在模板中調用:
~~~
<article:read name="hello" id="data" >
{$data.id}:{$data.title}
</article:read>
~~~
## 三元運算
模板可以支持三元運算符,例如:
~~~
{$status?'正常':'錯誤'}
{$info['status']?$info['msg']:$info['error']}
~~~
> 注意:三元運算符中暫時不支持點語法。
## 內置標簽
變量輸出使用普通標簽就足夠了,但是要完成其他的控制、循環和判斷功能,就需要借助模板引擎的標簽庫功能了,系統內置標簽庫的所有標簽無需引入標簽庫即可直接使用。
內置標簽包括:
| 標簽名 | 作用 | 包含屬性 |
|-----|-----|-----|
| include | 包含外部模板文件(閉合) | file |
| import | 導入資源文件(閉合 包括js css load別名) | file,href,type,value,basepath |
| volist | 循環數組數據輸出 | name,id,offset,length,key,mod |
| foreach | 數組或對象遍歷輸出 | name,item,key |
| for | For循環數據輸出 | name,from,to,before,step |
| switch | 分支判斷輸出 | name |
| case | 分支判斷輸出(必須和switch配套使用) | value,break |
| default | 默認情況輸出(閉合 必須和switch配套使用) | 無 |
| 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 | 判斷數據是否為空 | name |
| notempty | 判斷數據是否不為空 | name |
| defined | 判斷常量是否定義 | name |
| notdefined | 判斷常量是否未定義 | name |
| define | 常量定義(閉合) | name,value |
| assign | 變量賦值(閉合) | name,value |
| if | 條件判斷輸出 | condition |
| elseif | 條件判斷輸出(閉合 必須和if標簽配套使用) | condition |
| else | 條件不成立輸出(閉合 可用于其他標簽) | 無 |
| php | 使用php代碼 | 無 |
具體使用參見官方手冊。常用的Volist的幾個參數要注意,比如變量接收的是name 不是id,奇偶判斷用mod 等。
# 自行了解的
## 修改定界符
## 模板布局
## 標簽嵌套
- 序
- 前言
- 內容簡介
- 目錄
- 基礎知識
- 起步
- 控制器
- 模型
- 模板
- 命名空間
- 進階知識
- 路由
- 配置
- 緩存
- 權限
- 擴展
- 國際化
- 安全
- 單元測試
- 拿來主義
- 調試方法
- 調試的步驟
- 調試工具
- 顯示trace信息
- 開啟調試和關閉調試的區別
- netbeans+xdebug
- Socketlog
- PHP常見錯誤
- 小黃鴨調試法,每個程序員都要知道的
- 應用場景
- 第三方登錄
- 圖片處理
- 博客
- SAE
- REST實踐
- Cli
- ajax分頁
- barcode條形碼
- excel
- 發郵件
- 漢字轉全拼和首字母,支持帶聲調
- 中文分詞
- 瀏覽器useragent解析
- freelog項目實戰
- 需求分析
- 數據庫設計
- 編碼實踐
- 前端實現
- rest接口
- 文章發布
- 文件上傳
- 視頻播放
- 音樂播放
- 圖片幻燈片展示
- 注冊和登錄
- 個人資料更新
- 第三方登錄的使用
- 后臺
- 微信的開發
- 首頁及個人主頁
- 列表
- 歸檔
- 搜索
- 分頁
- 總結經驗
- 自我提升
- 進行小項目的鍛煉
- 對現有輪子的重構和移植
- 寫技術博客
- 制作視頻教程
- 學習PHP的知識和新特性
- 和同行直接溝通、交流
- 學好英語,走向國際
- 如何參與
- 瀏覽官網和極思維還有看云
- 回答ThinkPHP新手的問題
- 嘗試發現ThinkPHP的bug,告訴官方人員或者push request
- 開發能提高效率的ThinkPHP工具
- 嘗試翻譯官方文檔
- 幫新手入門
- 創造基于ThinkPHP的產品,進行連帶推廣
- 展望未來
- OneThink
- ThinkPHP4
- 附錄