younishd / endobox
最小的模板引擎。
Requires
- php: ^7.0
- erusev/parsedown: ^1.6
Requires (Dev)
- phpunit/phpunit: ^6.5
README
endobox
最小的模板引擎。
🌱 原生 PHP 语法 | 📝 内置 Markdown | 🚀 最小化 API |
---|---|---|
使用纯 PHP 编写模板。无需学习新语法。 | 内置一个完整的 Markdown 解析器。是的,它可以与 PHP 结合使用! | 只需几个基本方法即可完成强大的功能。 |
文档
安装
通过 Composer 安装 endobox
composer require younishd/endobox
您需要 PHP 7.0+。
开始使用
配置 endobox 以加载应用程序模板的典型方式如下
require_once '/path/to/vendor/autoload.php'; use endobox\Endobox; $endobox = Endobox::create('path/to/templates');
您可以添加额外的模板位置
$endobox->addFolder('another/path/to/templates');
渲染模板
为您的模板实例化一个 Box
$welcome = $endobox('welcome');
通过调用 render()
使用一些变量来渲染模板
echo $welcome->render([ 'name' => "Alice" ]);
模板文件可能看起来像这样
welcome.php
<h1>Hello, <?= $name ?>!</h1>
文件扩展名
endobox 根据文件扩展名来决定如何渲染模板。
但是,在实例化模板 Box
时,会省略扩展名。
$members = $endobox('members'); // no file extension
PHP: .php
PHP 模板通过评估 PHP 标签(即 <? … ?>
)之间的代码并返回结果进行处理。
members.php
<h1>Members</h1>
<ul>
<?php foreach ($users as $u): ?>
<li><?= $u->name ?></li>
<?php endforeach ?>
</ul>
ℹ️ 技巧:
<?=
是<?php echo
的语法糖。
Markdown: .md
Markdown 模板通过 Markdown 解析器(Parsedown)进行处理,生成相应的 HTML 代码。这可以用于静态内容。
members.md
# Members - Alice - Bob - Carol
PHP+Markdown: .md.php
正如其名所示,这种模板类型结合了 PHP 和 Markdown:模板首先被评估为 PHP,然后被解析为 Markdown。非常方便。
members.md.php
# Members
<?php foreach ($users as $u): ?>
- <?= $u->name ?>
<?php endforeach ?>
HTML: .html
HTML 模板始终以原样打印。不进行进一步处理。
members.html
<h1>Members</h1> <ul> <li>Alice</li> <li>Bob</li> <li>Carol</li> </ul>
数据
数据可以通过模板中的简单 变量(例如,$foo
)访问,其中变量名对应于分配的数组键或属性。
<h1>Hello, <?= $username ?>!</h1>
分配数据
有几种方法可以将数据分配给模板框
// via assign(…) $welcome->assign([ "username" => "eve" ]); // via object property $welcome->username = "eve"; // via render(…) $welcome->render([ "username" => "eve" ]); // implicitly $welcome([ "username" => "eve" ]);
共享数据
通常,模板框彼此隔离。分配给一个框的数据在另一个框中不可见。
$welcome->username = "eve"; // not accessible to 'profile' $profile->email = "eve@example.com"; // not accessible to 'welcome'
如果它们应该共享数据,则可以 链接 它们
$welcome->link($profile);
现在,这些模板框已链接,它们共享相同的数据。
welcome.php
<h1>Hello, <?= $username ?>!</h1>
<p>Your email address is: <code><?= $email ?></code></p>
profile.php
<h1>Profile</h1>
<ul>
<li>Username: <strong><?= $username ?></strong></li>
<li>Email: <strong><?= $email ?></strong></li>
</ul>
请注意,welcome.php
打印出 $email
,它最初分配给 $profile
,而 profile.php
输出 $username
,尽管它分配给 $welcome
。
ℹ️ 技巧: 您可以使用现有的
Box
对象(而不是使用BoxFactory
对象)通过$box->create('template')
创建模板框,这的好处是 默认链接两个框。
默认值
有时提供 默认值 来打印未分配的变量可能很有用。您可以使用 PHP 7 的 空合并运算符: ??
轻松实现。
<title><?= $title ?? "Default" ?></title>
转义
转义是一种数据过滤形式,在输出为 HTML 之前对不安全、用户提供的输入进行清理。
endobox提供了两个快捷方式来访问htmlspecialchars()
函数:$escape()
及其简写版本$e()
<h1>Hello, <?= $escape($username) ?>!</h1>
<h1>Hello, <?= $e($username) ?>!</h1>
转义HTML属性
⚠️ 警告:始终使用双引号包围包含转义变量的HTML属性非常重要,否则您的模板仍然容易受到注入攻击(例如,XSS)。
<!-- Good -->
<img src="portrait.jpg" alt="<?= $e($name) ?>">
<!-- BAD -->
<img src="portrait.jpg" alt='<?= $e($name) ?>'>
<!-- BAD -->
<img src="portrait.jpg" alt=<?= $e($name) ?>>
链式调用 & 嵌套
由于您很少只处理单个模板,您可能正在寻找一种将多个模板有意义地组合在一起的方法。
链式操作
通过链式操作,我们的意思是不进行渲染而连接模板。
链式操作两个模板就像这样简单
$header($article);
现在,对$header
或$article
中的任何一个调用->render()
都会渲染这两个模板并返回连接的结果。
ℹ️ 小贴士:无需立即将模板渲染为字符串的好处是灵活性:您可以在知道模板变量的具体值之前定义由模板组成的布局。
链式操作多个模板的一般语法很简单
$first($second)($third)($fourth); // and so on
很好。
更明确(且严格等价)的形式是使用append()
或prepend()
,如下所示
$first->append($second)->append($third)->append($fourth);
或者...
$fourth->prepend($third)->prepend($second)->prepend($first);
ℹ️ 小贴士:请注意,之前看到的
Box::__invoke()
只是Box::append()
的一个别名。
您已经看到了如何将Box
对象连接在一起(或添加到前面)。
但是请注意,变量$first
、$second
、$third
和$fourth
都是Box
类型的对象,这意味着它们需要在某个时刻“复活”——可能使用在最初创建的BoxFactory
对象(在这个文档中我们将其称为$endobox
)。
换句话说,完整的代码可能看起来像这样
$first = $endobox('first'); $second = $endobox('second'); $third = $endobox('third'); echo $first($second)($third);
实际上,有一种方法可以避免这种样板代码:您可以直接将模板名称(一个string
)传递给append()
方法,而不是传递Box
对象!
所以,您可以这样写
echo $endobox('first')('second')('third');
这看起来很 trivial,但实际上有很多内容。更冗长的形式如下
echo $endobox->create('first')->append('second')->append('third');
这实际上等同于以下行
echo ($_ = $endobox->create('first')) ->append($endobox->create('second')->link($_)) ->append($endobox->create('third')->link($_));
请注意,与之前不同,这些(隐式创建的)盒子现在都自动连接在一起,这意味着它们共享相同的数据。
一般来说:从其他盒子创建的盒子默认是连接的。
嵌套
另一种相当不同的方法(可能是模板设计者而不是开发者的方法)是定义某种类型的布局模板
layout.php
<html>
<head></head>
<body>
<header><?= $header ?></header>
<article><?= $article ?></article>
<footer><?= $footer ?></footer>
然后在控制器中某个地方
$layout = $endobox('layout'); $header = $endobox('header'); // header.html $article = $endobox('article'); // article.php $footer = $endobox('footer'); // footer.html echo $layout->render([ 'header' => $header, 'article' => $article->assign([ 'title' => "How to make Lasagna" ]), 'footer' => $footer ]);
这应该没问题,但我们在这里可以删除一些样板代码:实际上$header
和$footer
并不需要成为变量。
这就是嵌套
发挥作用的地方!
使用$box()
函数在另一个模板中实例化模板Box
layout.php
<html>
<head></head>
<body>
<header><?= $box('header') ?></header>
<article><?= $article ?></article>
<footer><?= $box('footer') ?></footer>
然后简单地...
echo $endobox('layout')->render([ 'article' => $endobox('article')->assign([ 'title' => "How to make Lasagna" ]) ]);
这已经变得非常简洁,但它还可以更简洁:通过使用$box()
在另一个模板中嵌套模板Box
,这两个盒子将默认连接在一起!
这使得我们可以进一步缩减。看看这个
layout.php
<html>
<head></head>
<body>
<header><?= $box('header') ?></header>
<article><?= $box('article') ?></article>
<footer><?= $box('footer') ?></footer>
现在,所有三个模板都是使用$box()
嵌套的,因此连接到它们的父级(即$layout
)。
这使我们的控制器代码缩减到一行
echo $endobox('layout')->render([ 'title' => "How to make Lasagna" ]);
请注意,尽管实际的$title
变量出现在嵌套的article
模板中,我们还是为layout
模板分配了一个标题。
ℹ️ 小贴士:
$box()
函数也作为Box
对象的方法可用(即,在模板外部):您可以使用$box->create('template')
实例化新的盒子,其中$box
是某个已创建的Box
对象。
函数
函数是向模板添加可重用功能的一种酷炫且方便的方法(例如,过滤器、URL 构建器…)。
注册函数
您可以通过将其分配给模板 Box
(就像数据一样)来注册自己的自定义函数(即,闭包)。
以下是一个简单的函数 $day()
,它返回星期几
$calendar->day = function () { return date('l'); };
在您的模板文件中,您可以像使用任何变量一样使用它
<p>Today is <?= $day ?>.</p>
它看起来可能像这样(至少有时是这样)
<p>Today is Tuesday.</p>
您甚至可以进一步调用变量,就像调用任何函数一样,并实际上 传递一些参数。
以下是一个简单的闭包 $a()
,它将一些文本包裹在超链接标签中
$profile->a = function ($text, $href) { return sprintf('<a href="%s">%s</a>', htmlspecialchars($href), htmlspecialchars($text)); };
在您的模板中调用此函数将看起来像这样
<p>Follow me on <?= $a("GitHub", "https://github.com/younishd") ?></p>
这将产生类似这样的结果
<p>Follow me on <a href="https://github.com/younishd">GitHub</a></p>
默认函数
有一些默认的辅助函数可以立即使用(其中一些您可能已经见过)
函数 | 描述 | 示例 |
---|---|---|
$box() 或 $b() |
在另一个模板中实例化一个 Box 。 (参见 嵌套。) |
<article><?= $box('article') ?></article> |
$markdown() 或 $m() |
将文本渲染为 Markdown。当文本是用户输入/存储在数据库中时非常有用。 | <?= $markdown('这是些 _疯狂评论_!') ?> |
$escape() 或 $e() |
使用 htmlspecialchars() 清理不安全用户输入。 (参见 转义。) |
<img src="portrait.jpg" alt="<?= $e($name) ?>"> |
克隆
您可以使用内置的 clone
关键字轻松克隆模板 Box
。
$sheep = $endobox('sheep'); $cloned = clone $sheep;
克隆的盒子将具有与原始盒子相同的内容和数据。然而,链式或链接的盒子将被丢弃。
许可证
endobox 是开源软件,受 MIT 许可证 许可。