我正在处理一个使用本土模板系统的网络应用程序,该系统允许将Perl代码嵌入到HTML中。这些语句由模板解析器在运行时使用eval EXPR
执行。
这非常灵活,但这些陈述分散在各处,并执行 lot 。 eval EXPR
(而不是eval BLOCK
)要求Perl每次启动解释器,我的分析显示它们是减速的合理重要来源。
许多嵌入式Perl语句非常简单。例如,模板可能有这样的行:
<p>Welcome, <!--E: $user->query('name') -->.
或者:
<p>Ticket number <!--E: $user->generate_ticket_number() --> has been generated.
也就是说,他们只是调用对象方法。但是,也有更复杂的问题。
我希望能够优化这一点,到目前为止有两个想法,这两个想法都很糟糕。第一种是重写所有模板,用USER:NAME
和USER:GENERATETICKETNUMBER
之类的标记替换简单调用,然后解析器可以扫描并调用适当的对象方法。但是,我没有处理混合HTML和Perl的模板,而是使用混合HTML,Perl和令牌的模板。
第二个想法是尝试解析嵌入的Perl,弄清楚语句想要做什么,如果它足够简单,通过符号引用调用适当的对象方法。这显然是疯了。
我有一些合理的解决方案吗?
答案 0 :(得分:9)
尝试采用类似于mod_perl
用于编译CGI的方法:
将模板转换为Perl代码。例如,您的第一个示例可能会转换为:
print "<p>Welcome, ";
print $user->query('name');
print ".\n";
围绕该代码包裹sub {
... }
,以及一些解包参数的代码(例如,样本中的$user
之类的内容)。
eval
该代码。请注意,它返回一个coderef。
重复调用该coderef。 :)
答案 1 :(得分:3)
您可以查看Mojolicious。它有templating engine,允许语法接近你正在使用的语法。您可以切换到使用它或查看其来源(单击上一个链接左侧的源)以查看是否可以绘制一些想法。
仅供参考Mojolcious模板引擎的语法允许以下格式与HTML混合使用
<% Perl code %>
<%= Perl expression, replaced with result %>
<%== Perl expression, replaced with XML escaped result %>
<%# Comment, useful for debugging %>
<%% Replaced with "<%", useful for generating templates %>
% Perl code line, treated as "<% line =%>"
%= Perl expression line, treated as "<%= line %>"
%== Perl expression line, treated as "<%== line %>"
%# Comment line, treated as "<%# line =%>"
%% Replaced with "%", useful for generating templates
答案 2 :(得分:2)
你可能想看看Text::MicroTemplate的胆量。实际上,您可能希望使用 Text :: MicroTemplate,因为它可能符合您的需求。它构建了一个子程序,可以根据需要连接字符串,就像duskwuff建议的那样。以下是build_mt('hello, <?= $_[0] ?>')
中re.pl
的结果:
$CODE1 = sub {
package Devel::REPL::Plugin::Packages::DefaultScratchpad;
use warnings;
use strict 'refs';
local $SIG{'__WARN__'} = sub {
print STDERR $_mt->_error(shift(), 4, $_from);
}
;
Text::MicroTemplate::encoded_string(sub {
my $_mt = '';
local $_MTREF = \$_mt;
my $_from = '';
$_mt .= 'hello, ';
$_from = $_[0];
$_mt .= ref $_from eq 'Text::MicroTemplate::EncodedString' ? $$_from : do {
$_from =~ s/([&><"'])/$Text::MicroTemplate::_escape_table{$1};/eg;
$_from
};
return $_mt;
}
->(@_));
};
答案 3 :(得分:0)
您不应该使用'eval'来调用模板中的方法。抱歉听起来很苛刻,但分离视图的目的是从视图层中删除处理代码。上面描述的模板系统和Template Toolkit只是传入一个对象/哈希,因此您可以访问它。
为什么不将$ user作为hashref传递:
$user = {
'name' => 'John',
'id' => '3454'
};
这将允许您通过以下方式访问“名称”:
$user->{'name'};
否则,您可能正在执行以下操作:
制作数据库查询比将哈希/对象引用传递给模板要昂贵得多。您可能需要查看一些代码分析工具,如Devel :: NYTProf,以查看代码执行的哪些部分真正减慢了您的速度。我怀疑eval是否会让你的程序陷入困境,以至于你需要优化eval。听起来像eval中的代码正在减慢你的速度。