2012-12-07 26 views
3

我有一個簡單的電子郵件()類。它用於從我的網站發送電子郵件。使用模板的電子郵件功能。包括通過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的解決方法。出於某種原因,我覺得很奇怪。或者這很常見的做法?

回答

3

你可以找到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()); 

?> 
3

其中一種方法是將文件內容讀入變量,然後使用正則表達式替換佔位符。所以例如你有新用戶template.phtml。你用$content = file_get_content('new-users-templae.phtml');閱讀它的內容。在這些模板中,您將擁有像%%username%%%%sitename%%,%%siteurl%%的佔位符。您需要使用str_replace處理此內容,替換佔位符。將此代碼移至某個"prepareEmailTemplate"函數,並將此函數的結果放入您的"send"函數中。

+0

嗯..這就像smarty模板的東西的作品,對吧?然而,變量仍然需要在函數內全球化。 – Geo

+0

也許,我沒有看到裏面的Smarty代碼:)關於變量 - 你可以提供它們作爲send函數的附加參數。但更好的選擇是將模板解析代碼移動到另一個函數並將結果內容發送到函數 –

+0

您可以用這種方式實際使用現有文件,替換整個PHP部分,所以類似'str_replace( '','Some name',$ email_html);' – BenOfTheNorth

0

一種解決方案是將不在模板內但在函數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)); 
+1

我一般不喜歡全局變量的想法。在你建議的函數中將它們全局化似乎有點乾淨,但是當在模板中引入新變量時將需要不斷的類修改。這並不好玩。我喜歡你的第二個想法,把它們扔在'send'函數中。我必須嘗試一下。我**絕對**不會推薦使用eval。我會更好地更新模板來代替echo'$ extra_vars ['SITE_NAME']'。謝謝!附:恭喜你的聲譽得分! :) – Geo

+0

是的,eval可以是邪惡的;-)讓他們在模板中作爲一個數組也可以很好 –