【发布时间】:2011-04-25 05:01:18
【问题描述】:
更新-感谢所有回复。这个问题有点乱,所以如果有人感兴趣,我就发起了sequel。
我正在为朋友编写一个快速脚本,偶然发现了一种在 PHP 中进行模板的非常简单的方法。
基本上,这个想法是将html文档解析为heredoc字符串,因此其中的变量将由PHP扩展。
传递函数允许在字符串中进行表达式评估以及函数和静态方法调用:
function passthrough($s){return $s;}
$_="passthrough";
在heredoc字符串中解析文档的代码非常简单:
$t=file_get_contents('my_template.html');
eval("\$r=<<<_END_OF_FILE_\n$t\_END_OF_FILE_;\n");
echo $r;
唯一的问题是,它使用eval。
问题
谁能想到不使用
eval,但不添加解析器或大量正则表达式的方法来执行这种模板?在不编写完整解析器的情况下转义不属于 PHP 变量的杂散美元符号有什么建议吗?杂散的美元符号问题是否会导致这种方法不适合“认真”使用?
这里是一些模板化的 HTML 代码示例。
<script>var _lang = {$_(json_encode($lang))};</script>
<script src='/blah.js'></script>
<link href='/blah.css' type='text/css' rel='stylesheet'>
<form class="inquiry" method="post" action="process.php" onsubmit="return validate(this)">
<div class="filter">
<h2>
{$lang['T_FILTER_TITLE']}
</h2>
<a href='#{$lang['T_FILTER_ALL']}' onclick='applyFilter();'>
{$lang['T_FILTER_ALL']}
</a>
{$filter_html}
</div>
<table class="inventory" id="inventory_table">
{$table_rows}
<tr class="static"><th colspan="{$_($cols+1)}">
{$lang['T_FORM_HELP']}
</th></tr>
{$form_fields}
<tr class="static">
<td id="validation" class="send" colspan="{$cols}"> </td>
<td colspan="1" class="send"><input type="submit" value="{$lang['T_SEND']}" /></td>
</tr>
</table>
</form>
为什么要使用模板?
关于在 PHP 中创建模板层是否有必要进行了一些讨论,诚然,PHP 已经非常擅长模板化。
模板有用的一些简单原因:
-
你可以控制它
如果您在文件进入解释器之前对其进行预处理,您就可以更好地控制它。你可以注入东西、锁定权限、抓取恶意 php / javascript、缓存它、通过 xsl 模板运行它等等。
-
良好的 MVC 设计
模板促进了视图与模型和控制器的分离。
当您在视图中进出
<?php ?>标记时,很容易变得懒惰并执行一些数据库查询或执行一些其他服务器操作。使用像上面这样的方法,每个“块”只能使用一个语句(没有分号),所以要陷入那个陷阱要困难得多。<?= ... ?>有几乎相同的好处,但是... -
并非总是启用短标签
...我们希望我们的应用在各种配置下运行。
当我最初将一个概念组合在一起时,它一开始是一个 php 文件。但在它增长之前,我并不高兴,除非所有 php 文件开头只有一个 <?php,最后一个 ?>,最好是除了控制器、设置、图像服务器等之外的所有类。
我根本不希望在我的观点中出现太多 PHP,因为当 Dreamweaver 或其他任何东西看到这样的东西时,设计师会感到困惑:
<a href="<?php $img="$img_server/$row['pic'].png"; echo $img; ?>">
<img src="<?php echo $img; ?>" /></a>
这对于程序员来说已经够难了。一般的平面设计师不会靠近它。这样的事情更容易处理:
<a href="{$img}"><img src="{$img}" /></a>
程序员将他讨厌的代码保留在 html 之外,现在设计师可以发挥他的设计魔力了。耶!
快速更新
考虑到大家的建议,我认为预处理文件是要走的路,中间文件应该尽可能接近普通的“php模板”,模板是语法糖。当我玩它时,Eval 现在仍然在原地。 heredoc 的东西已经改变了它的角色。我稍后会写更多,并尝试回应一些答案,但现在......
<?php
class HereTemplate {
static $loops;
public function __construct () {
$loops=array();
}
public function passthrough ($v) { return $v; }
public function parse_markup ($markup, $no_escape=null, $vars=array()) {
extract($vars);
$eot='_EOT_'.rand(1,999999).'_EOT_';
$do='passthrough';
if (!$no_escape) $markup=preg_replace(
array(
'#{?{each.*(\$\w*).*(\$\w*).*(\$\w*).*}}?#',
'#{?{each.*(\$\w*).*(\$\w*).*}}?#',
'#{?{each}}?#',
'#{{#', '#}}#',
'#{_#', '#_}#',
),
array(
"<?php foreach (\\1 as \\2=>\\3) { ?>",
"<?php foreach (\\1 as \\2) { ?>",
"<?php } ?>",
"<?php echo <<<$eot\n{\$this->passthrough(", ")}\n$eot\n ?>",
"<?php ", " ?>",
),
$markup);
ob_start();
eval(" ?>$markup<?php ");
echo $markup;
return ob_get_clean();
}
public function parse_file ($file) {
// include $file;
return $this->parse_markup(file_get_contents($file));
}
}
// test stuff
$ht = new HereTemplate();
echo $ht->parse_file($argv[1]);
?>
...
<html>
{{each $_SERVER $key $value}
<div id="{{$key}}">
{{!print_r($value)}}
</div>
{each}}
</html>
【问题讨论】:
-
@alex - 左右打开和关闭 PHP 标签正是我想要避免的......
-
@no:如果你不介意,你有什么理由避免它?为了更好看?对设计师来说更容易?干杯。
-
这个问题表明糟糕的设计会导致问题。 PHP 是完美的模板系统,无需使用其他任何东西。
-
@Col。 Shrapnel: 是的,你在讲道理方面做得不太好……我更喜欢你只是看着,除非你能比以前更好地传达你的观点。
标签: php templates eval heredoc