我有一个简单的Email()类。它用于从我的网站发送电子邮件。
<?
Email::send($to, $subj, $msg, $options);
?>
我还有一堆用纯HTML编写的电子邮件模板,上面有一些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 vars,我必须将模板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 var 并没有呈现,因为它们在函数作用域内,所以我不得不全球化模板内的变量:
<?
global $SITE_NAME, $SITE_URL, $name;
?>
<p>Dear <?=$name?>,</p>
...
所以问题是是否有更优雅的解决方案?主要是我担心我使用 ob_start()
和 global
的解决方法。出于某种原因,这在我看来很奇怪。或者这几乎是常见的做法?
您可以在此答案中找到更优雅的问题解决方案。
请注意 PHP 提取函数的用法来实例化模板变量。
换句话说,应将模板分析逻辑移到电子邮件发送功能之外。
例如:
<?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("me@localhost", "Subject", $tpl->parse());
?>
执行此操作的方法之一是将文件内容读取到变量,然后使用正则表达式替换占位符。例如,你有new-users-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));