转自ibm developerWorks 作者:Martin Streicher ([email protected]),
2007 年 9 月 06 日
随意混用 PHP 与其他 Web 页面标记将导致程序逻辑、HTML、层叠样式表(Cascading Style Sheets,CSS)和 JavaScript 处于混乱状态,使维护成为一项艰巨的任务。Smarty 模板引擎可以将形式与功能分离。
PHP Web 应用程序易于上手。PHP 语言的语法整洁且易于掌握。可以将 PHP 与 HTML、JavaScript 和 CSS 直接混用以快速生成可视结果。而且,把 PHP 应用程序部署到您自己的 Web 服务器或托管服务中只是小菜一碟。
但 是混用 PHP 与其他页面标记也是一项责任。PHP 代码通常是含有程序逻辑、结构化查询语言(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 把代码变量与模板占位符关联起来,而显示引擎将解释 Smarty 标记、执行循环、引用占位符和显示最终结果。Smarty 功能包括:
if
、then
、else
,可以根据输入数据选择动态显示哪些内容
<strong>{$name|upper}</strong>
大写加粗显示占位符 —— 如
$name
。
<strong>
是普通 HTML。大括号 (
{}
) 用于划定 Smarty 标记,
$name
是占位符,而
|upper
是修饰符。还可以编写自己的修饰符以扩展 Smarty 的功能。
literal
和 php
运算符来完成
literal
运算符内的所有内容都将被逐字传递给最终页面。
php
运算符中放置的代码将像嵌入到
<?php ... ?>
转义符内一样执行。
还可以通过 {include ...}
运算符重用 Smarty 模板。要提高性能,则需缓存每个模板,以避免每次使用的转换负载。Smarty Web 站点提供了丰富文档和示例。Packt Publishing 还提供一本名为 Smarty: PHP Template Programming and Applications(请参阅 参考资料)的书,该书适于学习和参考(警告:一些最新运算符并未介绍,而且其他运算符的说明也不正确,因为该书介绍的是 Smarty V2.x 的早期版本)。
|
用 Smarty 进行开发
无法通过一篇文章列举和演示 Smarty 的所有功能。但是,即使是一个如下所示的小示例,也能证明模板的力量。
把 Smarty 添加到应用程序中十分轻松:
例如,示例应用程序的文件夹内容包含 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 中显示了用浏览器访问示例应用程序的结果。
|
Example
是一个简单类,用于持久保存任意数目的已命名属性。该类最令人感兴趣的部分是第 18 行 $this->$name = $value;
。这行代码将动态创建类实例成员。例如,如果调用 $example->SetProperty( 'name', 'Groucho' )
,则可以用(传统的)$example->name
检索名称。
|
清单 2 反映了把 PHP 变量与 Smarty 占位符关联起来的一般策略。代码行 $smarty->assign( 'name', $x )
将把 PHP 变量(或数组、对象)$x 与占位符名称关联起来。模板中显示 name 的所有位置都将显示 $x 的值。
Smarty 模板是什么样的?Smarty 代码都是轻量级的,如清单 3、清单 4 和清单 5 所示。Smarty 将把大括号 ({}
) 中的所有内容都视为 Smarty 代码。因此,如果任何其他页面标记(例如嵌入式 CSS 或 JavaScript)使用大括号,则必须用 {literal}...{/literal}
把那个标记括起来,如清单 3 中所示:
|
如前所述,清单 3 将应用 {literal}
运算符来逐字渲染标记:定界符之间的所有文本都将被传递而无需进一步解释。第 3 行将显示名为 <title>
的占位符的值,该占位符与 PHP 应用程序中的标量变量相关联。如果不与 <title>
关联,则 |default:
修饰符将提供默认值。注意 Smarty 运算符中的空白。通常,必须忽略它。幸运的是,Smarty 编译器将提供有帮助的错误消息。
清单 4 页脚显示了使用 {if condition}
在渲染时做出决定。在这里,如果占位符 quote
的值已设定,则将显示 {if}
与 {/if}
之间插入的标记。代码行 {$quote|upper}
将用全大写的形式发送 quote
的值。|upper
是改变字符串输出的众多修饰符之一 —— 同时,它对于分离字符串内容与显示形式十分有用。
|
清单 5 渲染了最终页面。
|
应用程序的这个主要 Smarty 模板采用了若干个 Smarty 运算符:
include()
方法一样运行,在适当的位置立即插入和解释
filename
的内容。虽然并未显示,但是可以将变量从一个模板传递给另一个模板,这样做鼓励重用。
person
与名为
GetProperty()
的方法相关。您可以调用对象的方法和引用对象成员,像
{$person->quote}
所做的那样。
loop
属性将给占位符命名,而
name
属性将指定一个名称以供数组索引使用。在循环内,将把数组元素作为
{$placeholder[index]}
来引用。
section
一样迭代,但是提供了一个非常优秀的功能来处理一组关联数组,例如数据库查询的行列表。每个关联数组都被 “转换” 到名为
item
的索引中。例如,在清单 5 中,
person
被命名为
item
。每执行一次循环,
person
就会被指定来自数组
people
的关联数组。在那之后,在整个循环过程中,可以通过关键字引用关联数组中的值,如
{$person.signature}
。
id
属性,它将惟一地识别循环。使用此 ID 来引用反映循环状态的特殊变量集。例如,一个特殊变量是
first
,它只在循环的第一次迭代时才被设定。因此,值
$smarty.foreach.people.first
将引用与名为
people
(
people
) 的
foreach
循环 (
foreach
) 关联的特殊 Smarty 变量 (
smarty
)。正如您可能会想到的那样,还有
last
值和
iteration
值,它们从 1 开始,并随每次迭代增加(如果需要从零开始的计数器,请使用
index
而不要使用
iteration
)。
values
列表,Smarty 将像循环迭代一样在所有值中循环。将循环添加到
bgcolor
中将改变每个表行的颜色可以使表更清晰。
{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')
将利用缓存的副本,而不再渲染模板。