使用模板的电子邮件功能。包括通过ob_start和全局变量
我有一个简单的电子邮件()类。它用于从我的网站发送电子邮件。使用模板的电子邮件功能。包括通过ob_start和全局变量
<?
Email::send($to, $subj, $msg, $options);
?>
我也有一堆电子邮件模板用纯PHP编写的PHP变量刺穿。例如。 /inc/email/templates/account_created.php
:
<p>Dear <?=$name?>,</p>
<p>Thank you for creating an account at <?=$SITE_NAME?>. To login use the link below:</p>
<p><a href="https://<?=$SITE_URL?>/account" target="_blank"><?=$SITE_NAME?>/account</a></p>
为了有PHP乏渲染我不得不include
模板到我的功能。但由于include
不返回的内容,而是仅仅将其直接输出,我有缓冲功能,把它包起来:
<?
abstract class Email {
public static function send($to, $subj, $msg, $options = array()) {
/* ... */
ob_start();
include '/inc/email/templates/account_created.php';
$msg = ob_get_clean();
/* ... */
}
}
之后,我意识到PHP瓦尔不会呈现,因为他们正在功能范围之内,所以只好全球化里面的模板的变量:
<?
global $SITE_NAME, $SITE_URL, $name;
?>
<p>Dear <?=$name?>,</p>
...
所以,问题是是否有更优雅的解决方案呢?主要是我担心使用ob_start()
和global
的解决方法。出于某种原因,我觉得很奇怪。或者这很常见的做法?
你可以找到this answer一个更优雅的解决您的问题。
注意使用PHP extract函数来实例化模板变量。
换句话说,您应该将模板解析逻辑移到电子邮件发送功能之外。
例如:
<?php
class SimpleTemplate {
private $_tpl = "";
private $_vars = array();
function __construct($tpl_name) {
$this->_tpl = $tpl_name;
}
public function __set($name, $value) {
$this->_vars[$name] = $value;
}
public function setVars($values) {
$this->_vars = $values;
}
public function parse() {
ob_start();
extract($this->_vars);
include $this->_tpl;
return ob_get_clean();
}
}
abstract class Email {
public static function send($to, $subj, $msg, $options = array()) {
/* ... */
}
}
$tpl = new SimpleTemplate('/inc/email/templates/account_created.php');
$tpl->name = 'Stack Overflow';
$tpl->SITE_NAME = 'site_name';
$tpl->SITE_URL = 'localhost';
Email::send("[email protected]", "Subject", $tpl->parse());
?>
其中一种方法是将文件内容读入变量,然后使用正则表达式替换占位符。所以例如你有新用户template.phtml。你用$content = file_get_content('new-users-templae.phtml');
阅读它的内容。在这些模板中,您将拥有像%%username%%
,%%sitename%%
,%%siteurl%%
的占位符。您需要使用str_replace
处理此内容,替换占位符。将此代码移至某个"prepareEmailTemplate"
函数,并将此函数的结果放入您的"send"
函数中。
一种解决方案是将不在模板内但在函数send
内部所需的变量全局化。
public static function send($to, $subj, $msg, $options = array()) {
global $SITE_NAME, $SITE_URL, $name;
/* ... */
ob_start();
include '/inc/email/templates/account_created.php';
$msg = ob_get_clean();
/* ... */
}
另一种解决方法是将这些额外的变量作为参数传递。这可能很难看,因为set
函数中的参数数量可能会增长很多,这取决于您的模板中需要多少参数。为了解决这个问题,实现这个解决方案的另一种方式是将这些额外的变量作为散列值并且即时创建这些变量(使用函数eval
)。这里有一个例子:
public static function send($to, $extra_vars = array()) {
foreach ($extra_vars as $key => $value) {
eval("\$$key = '$value';");
}
/* ... */
ob_start();
include '/inc/email/templates/account_created.php';
$msg = ob_get_clean();
/* ... */
}
然后当你应该打电话发这样的:
$SITE_NAME = "www.somewebsite.com";
Email::send("recipient", array('SITE_NAME' => $SITE_NAME));
我一般不喜欢全局变量的想法。在你建议的函数中将它们全局化似乎有点干净,但是当在模板中引入新变量时将需要不断的类修改。这并不好玩。我喜欢你的第二个想法,把它们扔在'send'函数中。我必须尝试一下。我**绝对**不会推荐使用eval。我会更好地更新模板来代替echo'$ extra_vars ['SITE_NAME']'。谢谢!附:恭喜你的声誉得分! :) – Geo
是的,eval可以是邪恶的;-)让他们在模板中作为一个数组也可以很好 –
嗯..这就像smarty模板的东西的作品,对吧?然而,变量仍然需要在函数内全球化。 – Geo
也许,我没有看到里面的Smarty代码:)关于变量 - 你可以提供它们作为send函数的附加参数。但更好的选择是将模板解析代码移动到另一个函数并将结果内容发送到函数 –
您可以用这种方式实际使用现有文件,替换整个PHP部分,所以类似'str_replace( '=name;?>','Some name',$ email_html);' – BenOfTheNorth