nitricware / tonic
无依赖的 PHP 模板引擎。
Requires
- php: >=7.4
This package is auto-updated.
Last update: 2024-09-16 21:04:55 UTC
README
超级快速且强大的模板引擎。纯 PHP,零依赖。
此 tonic 分支继续了 rgamba 的工作。
使用方法
使用 Tonic 非常简单直接。
use Tonic\Tonic; $tpl = new Tonic("demo.html"); $tpl->user_role = "member"; echo $tpl->render();
它也非常灵活。上面的代码也可以写成以下形式
$tpl = new Tonic(); echo $tpl->load("demo.html")->assign("user_role","member")->render();
显示语法
使用 Tonic
<body> <h1>Welcome {$user.name.capitalize().truncate(50)}</h1> User role: {$role.lower().if("admin","administrator").capitalize()} </body>
与全部使用 PHP 编写对比
<body> <h1>Welcome <?php echo (strlen($user["name"]) > 50 ? substr(ucwords($user["name"]),0,50)."..." : ucwords($user["name"])) ?></h1> User role: <?php if(strtolower($role) == "admin") { echo "Administrator" } else { echo ucwords($role) } ?> </body>
安装
使用 composer 进行安装
{ "require": { "nitricware/tonic": "^3.0" } }
缓存
所有 tonic 模板都会编译回原生 PHP 代码。强烈建议您使用缓存功能,这样相同的模板就不需要反复编译,从而提高服务器端的 CPU 使用率。
$tpl = new Tonic(); $tpl->cache_dir = "./cache/"; // Be sure this directory exists and has writing permissions $tpl->enable_content_cache = true; // Importante to set this to true!
修饰符
修饰符是用于以各种方式修改输出变量的函数。所有修饰符都必须以变量开头,并且可以与其他修饰符链式使用。示例
{$variable.modifier1().modifier2().modifier3()}
当使用关联数组时,我们也可以以相同的方式使用修饰符
{$my_array.item.sub_item.modifier1().modifier2().modifier3()}
处理日期
在 Tonic 模板中处理和格式化日期非常简单。
Tonic::$local_tz = 'America/New_york'; // Optionaly set the user's local tz $tpl = new Tonic(); $tpl->my_date = date_create();
并且模板
<p>Today is {$my_date.date("Y-m-d h:i a")}</p>
处理时区
<p>The local date is {$my_date.toLocal().date("Y-m-d h:i a")}</p>
这将把 $my_date
渲染为 Tonic::$local_tz
中配置的时区
自定义时区
<p>The local date is {$my_date.toTz("America/Mexico_city").date("Y-m-d h:i a")}</p>
修饰符列表
创建自定义修饰符
如果您需要自定义修饰符,可以扩展列表并创建自己的。
// This function will only prepend and append some text to the variable Tonic::extendModifier("myFunction",function($input, $prepend, $append = ""){ // $input will hold the current variable value, it's mandatory that your lambda // function has an input receiver, all other arguments are optional // We can perform input validations if(empty($prepend)) { throw new \Exception("prepend is required"); } return $prepend . $input . $append; });
并且您可以轻松使用此修饰符
<p>{$name.myFunction("hello "," goodbye")}</p>
匿名修饰符
有时您只需要从模板内部直接调用函数,其返回值是不断变化的,因此不能与静态变量链接。此外,它的值不依赖于任何变量。在这些情况下,您可以使用匿名修饰符。要做到这一点,您需要创建一个自定义修饰符,如果您需要使用其他参数,请忽略 $input
参数。
Tonic::extendModifier("imagesDir", function($input){ // Note that $input will always be empty when called this modifier anonymously return "/var/www/" . $_SESSION["theme"] . "/images"; });
然后您可以直接从模板中调用它
<img src="{$.imagesDir()}/pic.jpg" />
上下文感知
Tonic 会阻止您在应用程序中对可能导致潜在攻击的变量进行转义。每个将要显示给用户的变量都应该仔细转义,并且应该根据上下文进行转义。例如,链接的 href 属性中的变量应与 <h1>
标签中的某些变量以不同的方式进行转义。好消息是 Tonic 会为您做所有这些工作。
$tonic->assign("array",array("Name" => "Ricardo", "LastName", "Gamba")); $tonic->assign("ilegal_js","javascript: alert('Hello');");
并且 HTML
<a href="{$ilegal_js}">Click me</a> <!-- Will render: <a href="javascript%3A+alert%28%27Hello%27%29%3B">Click me</a> --> <p>The ilegal js is: {$ilegal_js}</p> <!-- Will render: <p> The ilegal js is: javascript: alert('Hello');</p> --> <a href="?{$array}">Valid link generated</a> <!-- Will render: <a href="?Name=Ricardo&LastName=Gamba">Valid link generated</a> --> <p> We can also ignore the context awareness: {$ilegal_js.ignoreContext()}</p>
包含模板
您可以在另一个模板内部包含一个模板
{include footer.html}
我们还可以获取外部页面并将其加载到当前模板中
{include http://mypage.com/static.html}
模板包含支持嵌套调用,但请注意,在模板 "A" 中包含模板 "A" 可能会导致无限循环。
控制结构
如果 / 否则
制作条件非常简单
{if $user.role eq "admin"} <h1>Hello admin</h1> {elseif $user.role.upper() eq "MEMBER" or $user.role.upper() eq "CLIENT"} <h1>Hello member</h1> {else} <h1>Hello guest</h1> {endif}
您可以使用常规逻辑运算符(==、!=、>、<、>=、<=、||、&&)或使用以下
循环
<ul> {loop $user in $users} <li>{$user.name.capitalize()}</h1> {endloop} </ul>
如果需要数组键
<ul> {loop $i,$user in $users} <li>{$i} - {$user.name.capitalize()}</h1> {endloop} </ul>
处理宏
如果结构和循环结构都可以以更 HTML 适应的方式编写,这样代码就可以更易于阅读。以下是一个示例
<ul tn-if="$users"> <li tn-loop="$user in $users">Hello {$user}</li> </ul>
这与以下内容完全相同
{if $users} <ul> {loop $user in $users} <li>Hello {$user}</li> {endloop} </ul> {endif}
本地化
Tonic 支持本地化。按照以下方式更改调用
use Tonic\Tonic; $tpl = new Tonic("demo.html", "localized.xml"); $tpl->user_role = "member"; echo $tpl->render();
如果您想使用多个本地化文件,请将数组用作第二个构造参数,如下所示
$tpl = new Tonic("demo.html", array("localized.xml", "anotherFile.xml");
文件 localized.xml
可以有任意名称(例如 EN.xml
),但必须是有效的XML。以下是它的结构
<?xml version="1.0" encoding="UTF-8"?> <Strings> <string> <key>TEXT</key> <value>Tonic will automatically load the specified localized text from the specified language file.</value> </string> </Strings>
要在模板中访问本地化字符串,请使用 {$localized.FILENAME.KEY}
,其中 KEY
是您在XML文档中使用的键,而 FILENAME
是本地化文件的名称,不包含扩展名(例如 EN
)。在这个例子中就是 {$localized.EN.TEXT}
。
模板继承
Tonic支持单模板继承。其背后的理念是保持简单。多重继承可能导致复杂且难以维护的视图。
在Tonic中,模板继承基于 blocks
。假设我们有一个以下的基础模板
base.html
<html> <head> <title>Tonic</title> </head> <body> <section tn-block="header"> <h1>Default welcome message!</h1> </section> <section> <div tn-block="content"> <p>This is the default content.</p> </div> </section> <section tn-block="footer">Tonic 2016</section> </body>
然后你有几个部分模板或视图,你想重用主 base.html
作为“骨架”。为了做到这一点,我们使用 blocks
。每个块由标签 {block name}{endblock}
定义,或由HTML属性 tn-block="name"
定义,它实际上用属性作为块的名称 name 封闭了HTML元素。
inner.html
{ extends base.html } <section tn-block="header" class="myheader"> <h1>Welcome to my inner page!</h1> </section> <p>This content WON´T be rendered at all!</p> <div tn-block="content"> <p>This is the content of my inner view. </div>
结果我们将得到以下视图
<html> <head> <title>Tonic</title> </head> <body> <section class="myheader"> <h1>Welcome to my inner page!</h1> </section> <section> <div> <p>This is the content of my inner view. </div> </section> <section>Tonic 2016</section> </body>
这里有几个键
- 标签
{ extend }
。它唯一的参数应该是相对于Tonic::$root
的模板文件(默认为./
)。 - HTML属性
tn-block="header"
定义了块,并位于HTML元素的闭合匹配标签内。 - 子模板(inner.html)中找到的所有块将有效地替换父模板(base.html)上匹配的块。如果子模板中有一个在父模板中没有定义的块,则该块将不会渲染。
- 块名称必须是字母数字的,且不能包含
$
或任何特殊字符或空格。 - 父模板(base.html)继承了子模板的上下文(作用域、变量)。
- 您只能扩展一个模板。
注意 还可以使用 {block header}{endblock}
语法来定义块。我们更喜欢使用HTML属性,因为它更简洁。示例
{block myBlock}<div><h1>Welcome</h1></div>{endblock}
与以下完全相同
<div tn-block="myBlock"><h1>Welcome</h1></div>
路线图
- 添加更多
@throws
而不是@return bool|void
。
变更日志
- 2020-07-16 - 3.3.1 - composer修复
- 2020-07-14 - 3.3 - PHP 7.4更新:添加了类型提示并移除了未使用的功能
- 2019-05-10 - 3.2 - NitricWare分支:支持本地化
- 2016-10-11 - 3.1.0 - 添加了对模板继承的支持
- 2015-03-25 - 3.0.0 - 添加了对上下文感知和条件语句、循环的宏语法的支持
- 2015-03-23 - 2.2.0 - 添加了对命名空间的支持并添加了修饰符异常
- 2015-03-20 - 2.1.0 - 添加了扩展修饰符的选项。
- 2015-03-19 - 2.0.0 - 重要更新。大多数结构的语法略有变化,与之前版本不兼容。