用 Smarty 分離 PHP 應用程式中的形式與功能

來源:互聯網
上載者:User

轉自ibm developerWorks 作者:Martin Streicher  (martin.streicher@linux-mag.com),

2007 年 9 月 06 日

隨意混用 PHP 與其他 Web 頁面標記將導致程式邏輯、HTML、層疊樣式表(Cascading Style Sheets,CSS)和 JavaScript 處於混亂狀態,使維護成為一項艱巨的任務。Smarty 模板引擎可以將形式與功能分離。

PHP Web 應用程式易於上手。PHP 語言的文法整潔且易於掌握。可以將 PHP 與 HTML、JavaScript 和 CSS 直接混用以快速產生可視結果。而且,把 PHP 應用程式部署到您自己的 Web 服務器或託管服務中只是小菜一碟。

但 是混用 PHP 與其他頁面標記也是一項責任。PHP 代碼通常是含有程式邏輯、結構化查詢語言 (SQL)(Structured Query Language,SQL)查詢、函數、類、開發人員注釋、HTML、CSS 樣式和指令碼的複雜 web(不是開玩笑)。更糟糕的是,把內容從 PHP、echo 發送到輸出緩衝區有很多種方法。維護這樣混亂的頁面十分費力。對代碼或標記做出無關緊要的更改會帶來嚴重破壞,並且增強頁面可能需要設計人員與程式員的共同努力。使用 PHP,形式(頁面的布局)及功能(頁面的目的和構造)將被混在一起。

在 理想情況下,形式與功能是相互獨立的。例如,CSS 和 HTML 一定應該如此。CSS 是形式,而 HTML 是功能。在使用 PHP 的情況下,如果頁面標記和代碼能夠分離將是十分理想的。代碼將處理輸入,制定決策並產生顯示資料,而標記將期待獲得資料並提供所需的支架以渲染資訊。

例如,首頁的標記可能留下一個 “填空” (fill in the blank) 以供使用者登入,以及其他預留位置以供儲存使用者的映像和重要訊息。此模板 —— 這樣命名是因為它將提供頁面顯示的模式 —— 只面向設計人員,設計人員將控制頁面的整體外觀並留下名稱、圖片和其他資料的預留位置。代碼只是為預留位置提供資料。開發人員的任務仍然主要集中在計算上。

當然,形式與功能必須協作。如果模板期望獲得以美元為單位的金額,則代碼不應當提供 URL。如果模板期望獲得對象,則代碼不應當提供列表。因此,模板系統必須將表單與函數分離,但還必須在兩者之間建立聯絡。

最流行的 Web 應用程式程式設計語言(Perl、Python、Ruby、Java)都有模板引擎,而 PHP 也不例外。在搜尋引擎中鍵入 PHP template engine,然後您可能會找到 25 個以上的選項(有關強調所研究的每個引擎功能的列表 The PHP Template Engine Roundup,請參閱 參考資料)。

一些 PHP 模板引擎進行了速度最佳化。其他 PHP 模板引擎旨在鼓勵分離表單與函數的同時簡化使用。在某些包中,預留位置是在 PHP 本身中描述的,而其他解決方案都有一種自訂的簡短程式設計語言。如何選擇模板引擎在很大程度上取決於要求,因此適宜進行少量研究和實驗。

在 這裡,我向您介紹 Smarty,它是最流行的 PHP 模板引擎之一。Smarty “代碼” 有它自己的文法和運算子擴充列表,但是系統並不難學。閱讀或瀏覽 Smarty 文檔,以便熟悉它的所有功能。從 Smarty 的小修改開始,根據需求擴充您的技能,然後越來越精通。

獲得 Smarty

Smarty Web 網站維護著一張活動郵件清單、一個支援論壇和一個 Internet Relay Chat (IRC) 論壇(請參閱 參考資料)。開發進行中,而本文基於 V2.6.18 版本,該版本發佈於 2007 年 3 月 7 日。

Smarty 有兩個方面:PHP API (API) 和顯示引擎。應用程式代碼將調用 API 把代碼變數與模板預留位置關聯起來,而顯示引擎將解釋 Smarty 標記、執行迴圈、引用預留位置和顯示最終結果。Smarty 功能包括:

用於顯示 PHP 的所有基本資料結構的運算子
顯示簡單變數,迭代整個數組或關聯陣列,以及顯示類的成員。
預留位置的預設值
如果 PHP 代碼沒有將變數與預留位置關聯,則顯示預設值。
控制運算子,例如 ifthenelse,可以根據輸入資料選擇動態顯示哪些內容
例如,設計人員可以選擇用加粗的紅色文本顯示負賬戶餘額,而用黑色文本顯示正餘額。您可以在模板中隔離此類顯示邏輯(使您可以更輕鬆地進行開發)。
迴圈控制,它將提供用於簡化構建列表和表的特殊變數
例如,可以測試迴圈的第一次迭代並建立表頭。還可以像迴圈迭代一樣迴圈執行值輪循 (round-robin) 列表,迴圈迭代非常適於改變表行的顏色。
渲染時用於改變資料的修飾符
例如,可以用 Smarty 標記 <strong>{$name|upper}</strong> 大寫加粗顯示預留位置 —— 如 $name

<strong> 是普通 HTML。大括弧 ({}) 用於劃定 Smarty 標記,$name 是預留位置,而 |upper 是修飾符。還可以編寫自己的修飾符以擴充 Smarty 的功能。

如果必須 包括指令碼和原始 PHP 代碼,可以用 literalphp 運算子來完成
literal 運算子內的所有內容都將被逐字傳遞給最終頁面。 php 運算子中放置的代碼將像嵌入到 <?php ... ?> 轉義符內一樣執行。

還可以通過 {include ...} 運算子重用 Smarty 模板。要提高效能,則需緩衝每個模板,以避免每次使用的轉換負載。Smarty Web 網站提供了豐富文檔和樣本。Packt Publishing 還提供一本名為 Smarty: PHP Template Programming and Applications(請參閱 參考資料)的書,該書適於學習和參考(警告:一些最新運算子並未介紹,而且其他運算子的說明也不正確,因為該書介紹的是 Smarty V2.x 的早期版本)。



回頁首

用 Smarty 進行開發

無法通過一篇文章列舉和示範 Smarty 的所有功能。但是,即使是一個如下所示的小樣本,也能證明模板的力量。

把 Smarty 添加到應用程式中十分輕鬆:

  1. 下載 Smarty.zip 示範代碼(請參閱 下載)。
  2. 解壓縮並把 Smarty 安裝到路徑中。
  3. 編寫要求使用 Smarty 類的應用程式。
  4. 建立兩個目錄一起放置應用程式:
    • templates 將包含模板
    • templates_c 將包含緩衝的模板

例如,應用程式範例的檔案夾內容包含 Example.class.php index.php templates/ templates_c/

模 板目錄中的檔案將由 Smarty 引擎讀取。確保 Web 服務器對那些檔案擁有適當的訪問權。另外,templates_c 的內容必須可讀可寫,因為緩衝的模板副本放置在該檔案夾中。至少要使 Web 服務器可以將資料寫入 templates_c。或者,如果不需要考慮安全問題,可以將目錄更改為模式 777

清單 1 顯示了 Example.class.php,這是一個有代表性的 PHP V5 類。清單 2 包含 index.php,即應用程式。圖 1 中顯示了用瀏覽器訪問應用程式範例的結果。

清單 1. 簡單 PHP V5 類,用於儲存任意類型的已命名屬性的隨機列表

                
<?php

//
// Example is a simple class that stores an arbitrary
// number of named properties.
//

class Example {
private $catalog = array();

public function SetProperties( $arrayVariables ) {
foreach ( $arrayVariables as $name => $value ) {
$this->SetProperty( $name, $value );
}
}

public function SetProperty( $name, $value ) {
$this->$name = $value;
$this->catalog[] = $name;
}

public function GetProperties( ) {
$result = array();
foreach ( $catalog as $name ) {
$result[$name] = $this->GetProperty( $name );
}

return( $result );
}

public function GetProperty( $name ) {
return ( $this->$name );
}
}
?>

Example 是一個簡單類,用於持久儲存任意數目的已命名屬性。該類最令人感興趣的部分是第 18 行 $this->$name = $value;。這行代碼將動態建立類執行個體成員。例如,如果調用 $example->SetProperty( 'name', 'Groucho' ),則可以用(傳統的)$example->name 檢索名稱。

清單 2. PHP 應用程式,完全沒有任何 Web 頁面標記

                
<?php
require( 'Smarty.class.php' );
require( 'Example.class.php' );

$groucho = new Example();
$groucho->SetProperty( 'name', 'Groucho' );
$groucho->SetProperty( 'quote',
'Time flies like an arrow. Fruit flies like a banana.'
);

$chico = new Example();
$chico->SetProperties( array(
'name' => 'Chico',
'quote' => "There's no such thing as a sanity clause!"
)
);

$movies = new Example();
$movies->SetProperties( array(
'movies' => array(
'A Night at the Opera',
'Horse Feathers',
'Coconuts',
'The Big Store'
))
);

$looks = new Example();
$looks->SetProperty( 'novelty', array(
array( name =>'Groucho', 'signature' => 'moustache' ),
array( name =>'Chico', 'signature' => 'hat' ),
array( name => 'Harpo', 'signature' => 'raincoat' ),
array( name => 'Zeppo', 'signature' => 'hair')
)
);

$smarty = new Smarty();
$smarty->assign( 'person', $chico );
$smarty->assign( 'people', $looks->novelty );
$smarty->assign( 'quote', $groucho->quote );
$smarty->assign( 'movies', $movies->movies );
$smarty->display( 'template.tpl' );
?>

清單 2 反映了把 PHP 變數與 Smarty 預留位置關聯起來的一般策略。程式碼 $smarty->assign( 'name', $x ) 將把 PHP 變數(或數組、對象)$x 與預留位置名稱關聯起來。模板中顯示 name 的所有位置都將顯示 $x 的值。

圖 1. 渲染最終頁面,結合表單與函數

Smarty 模板是什麼樣的?Smarty 代碼都是輕量級的,如清單 3、清單 4 和清單 5 所示。Smarty 將把大括弧 ({}) 中的所有內容都視為 Smarty 代碼。因此,如果任何其他頁面標記(例如嵌入式 CSS 或 JavaScript)使用大括弧,則必須用 {literal}...{/literal} 把那個標記括起來,如清單 3 中所示:

清單 3. 主模板中包括的簡單 header 模板

                
<html>
<head>
<title>{$title|default:'The Marx Brothers'}</title>
<style type="text/css">
{literal}
body {
font-family: Verdana, Arial, sans-serif;
margin: 5%;
}
{/literal}
</style>
</head>
<body>

如前所述,清單 3 將應用 {literal} 運算子來逐字渲染標記:定界符之間的所有文本都將被傳遞而無需進一步解釋。第 3 行將顯示名為 <title> 的預留位置的值,該預留位置與 PHP 應用程式中的標量變數相關聯。如果不與 <title> 關聯,則 |default: 修飾符將提供預設值。注意 Smarty 運算子中的空白。通常,必須忽略它。幸運的是,Smarty 編譯器將提供有協助的錯誤訊息。

清單 4 頁尾顯示了使用 {if condition} 在渲染時做出決定。在這裡,如果預留位置 quote 的值已設定,則將顯示 {if}{/if} 之間插入的標記。程式碼 {$quote|upper} 將用全大寫的形式發送 quote 的值。|upper 是改變字串輸出的眾多修飾符之一 —— 同時,它對於分離字串內容與顯示形式十分有用。

清單 4. 頁尾模板

                
<div style="clear: both;">
<p align="center">
{if $quote}
<{$style|default:'strong'}>
{$quote|upper}
</{$style|default:'strong'}>
{/if}
</p>
</div>
</body>
</html>

清單 5 渲染了最終頁面。

清單 5. 應用程式的主要 Smarty 模板

                
{include file='header.tpl'}

<p>
{$person->name} said, "{$person->quote}"
</p>

<ul>
{section name=index loop=$movies}
<li>
{$movies[index]}
</li>
{/section}
</ul>

<table>
{foreach item=person from=$people name=people}
{if $smarty.foreach.people.first}
<tr>
<th>#</th>
<th>Name</th>
<th>Signature</th>
</tr>
{/if}
<tr bgcolor="{cycle values="#eeeeee,#d0d0d0}">
<td>{$smarty.foreach.people.iteration}</td>
<td>{$person.name}</td>
<td>{$person.signature}</td>
</tr>
{foreachelse}
<tr><td>Print this only if there's no data.</td></tr>
{/foreach}
</table>

{include file='footer.tpl'}

應用程式的這個主要 Smarty 模板採用了若干個 Smarty 運算子:

{include file='filename'}
像是 PHP 自己的 include() 方法一樣運行,在適當的位置立即插入和解釋 filename 的內容。雖然並未顯示,但是可以將變數從一個模板傳遞給另一個模板,這樣做鼓勵重用。
{$person->GetProperty('name')}
假定 person 與名為 GetProperty() 的方法相關。您可以調用對象的方法和引用對象成員,像 {$person->quote} 所做的那樣。
{section name=index loop=$placeholder}
在數組內迭代。 loop 屬性將給預留位置命名,而 name 屬性將指定一個名稱以供數組索引使用。在迴圈內,將把數組元素作為 {$placeholder[index]} 來引用。
foreach
section 一樣迭代,但是提供了一個非常優秀的功能來處理一組關聯陣列,例如資料庫查詢的行列表。每個關聯陣列都被 “轉換” 到名為 item 的索引中。例如,在清單 5 中, person 被命名為 item。每執行一次迴圈, person 就會被指定來自數組 people 的關聯陣列。在那之後,在整個迴圈過程中,可以通過關鍵字引用關聯陣列中的值,如 {$person.signature}
foreach 中的 name 屬性
類似於 HTML 標籤的 id 屬性,它將惟一地識別迴圈。使用此 ID 來引用反映迴圈狀態的特殊變數集。例如,一個特殊變數是 first,它只在迴圈的第一次迭代時才被設定。因此,值 $smarty.foreach.people.first 將引用與名為 people ( people) 的 foreach 迴圈 ( foreach) 關聯的特殊 Smarty 變數 ( smarty)。正如您可能會想到的那樣,還有 last 值和 iteration 值,它們從 1 開始,並隨每次迭代增加(如果需要從零開始的計數器,請使用 index 而不要使用 iteration)。
cycle
用於構建表的優秀運算子。如果提供 values 列表,Smarty 將像迴圈迭代一樣在所有值中迴圈。將迴圈添加到 bgcolor 中將改變每個表行的顏色可以使表更清晰。
{foreachelse}
如果要迭代的數組為空白,則轉而顯示 {foreachelse}...{/foreachelse} 的內容。

既然您已經預覽了模板,那麼 清單 2 讀起來可能很簡單。跟平常一樣,清單 2 將執行計算並把渲染頁面的工作傳遞給 Smarty。程式碼 $smarty->display('template.tpl') 將渲染模板。要捕捉 Smarty 的輸出,請使用 $smarty->fetch('template.tpl')



回頁首

使用 Smarty 更聰明一點,而不是更辛苦一點

雖 然本例是經過設計的,但是它展示了 Smarty 的強大之處和靈活性以及使用它分離標記與代碼是多麼簡單。Smarty 還有更多技巧。Smarty 可能實現您所需要的幾乎所有功能。您可以將模板輸出捕捉到 Smarty 預留位置中。您可以過濾模板,無論是在編譯前,還是在編譯後,還可以在渲染輸出被顯示或擷取之前先進行處理。而且 Smarty 允許您緩衝模板。

向 PHP 代碼中添加 $smarty->caching = 1; 即可獲得上述特性。如果緩衝被啟用,則調用 display('template.tpl') 將像往常一樣渲染模板並將在緩衝中儲存一份模板副本。下一次調用 display('template.tpl') 將利用緩衝的副本,而不再渲染模板。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.