问题
I have a simple Email() class. It's used to send out emails from my website.
<?
Email::send($to, $subj, $msg, $options);
?>
I also have a bunch of email templates written in plain HTML pierced with a few PHP variables. E.g. /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>
In order to have the PHP vars rendered I had to include
the template into my function. But since include
does not return the contents but rather just sends it directly to the output, I had to wrap it with the buffer functions:
<?
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();
/* ... */
}
}
After that I realized that the PHP vars are not rendered as they are being inside of the function scope, so I had to globalize the variables inside of the template:
<?
global $SITE_NAME, $SITE_URL, $name;
?>
<p>Dear <?=$name?>,</p>
...
So the question is whether there is a more elegant solution to this? Mainly I am concerned about my workarounds using ob_start()
and global
. For some reason that seems to me odd. Or this is pretty much the common practice?
回答1:
You can find a more elegant solution to your problem in this answer.
Notice the usage of the PHP extract function to instantiate the template variables.
In other words, you should move the template parsing logic outside the e-mail sending function.
For example:
<?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());
?>
回答2:
One of the ways to do this is to read the file content to the variable and then, using regexps, replace the placeholders. So for example you have new-users-template.phtml. You reading it content with $content = file_get_content('new-users-templae.phtml');
. In those template you will have placeholders like %%username%%
, %%sitename%%
, %%siteurl%%
. You need to process this content with str_replace
, replacing the placeholders. Move this code to some "prepareEmailTemplate"
function and put the result of this function to your "send"
function.
回答3:
One solution is to globalize the variables needed not inside the template but inside the function 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();
/* ... */
}
Another solution is to pass those extra variables as parameters. This maybe ugly as the number of parameters in the set
function may grow a lot depending on how many of them you need in your template. To solve this issue, another way of implementing this solution is by passing those extra variables as a hash and create those variables on-the-fly (using the function eval
). Here's an example:
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();
/* ... */
}
Then when you should call send like this:
$SITE_NAME = "www.somewebsite.com";
Email::send("recipient", array('SITE_NAME' => $SITE_NAME));
来源:https://stackoverflow.com/questions/13767135/email-function-using-templates-includes-via-ob-start-and-global-vars