iT邦幫忙

1

[PHP]簡單易用的樣板引擎

  • 分享至 

  • xImage
  •  

MVC是現在很流行的程式架構,因為按照功能分開後,更容易擴充和維護,其中的View會寫成接收外來的變數來呈現資料,不處理資料取得和商業邏輯,因此便有了各種的樣板引擎來讓這件事情更容易達成

今天要介紹的是一款PHP的樣板引擎,它沒有名稱,也不有名,來自這一篇文章Template Engine簡體翻譯,但筆者卻非常推崇,原因無他,就是非常的簡單易用,通常樣板引擎需要另外安裝,有著專用的語法,用來呈現、過濾資料,並且可以用好幾個小樣板,組合出畫面,每一個小樣板都可以重複使用,避免重複開發

而這款卻不需安裝,僅用一個class便實現樣板引擎的功能,甚至還有快取功能,不需要學新的語法,因為直接使用php語言,這有好有壞,設計師需要學習php語言,但雖然如此,用到的php其實不會太複雜,跟學習smarty相比,應該差不多難度,另外一個疑慮是,如果你的網站允許使用者上傳樣板修改版面,使用php語言變成自由度太大了,無法防止被上傳包含惡意程式碼的樣板,不過這篇文章是在2003年寫的,如今都是使用修改css的方式讓使用者修改版面,所以這個疑慮也不存在了

事不宜遲,來看看這個class到底長的怎樣

class Template {
    var $vars; /// Holds all the template variables

    /**
     * Constructor
     *
     * @param $file string the file name you want to load
     */
    function Template($file = null) {
        $this->file = $file;
    }

    /**
     * Set a template variable.
     */
    function set($name, $value) {
        $this->vars[$name] = is_object($value) ? $value->fetch() : $value;
    }

    /**
     * Open, parse, and return the template file.
     *
     * @param $file string the template file name
     */
    function fetch($file = null) {
        if(!$file) $file = $this->file;

        extract($this->vars);          // Extract the vars to local namespace
        ob_start();                    // Start output buffering
        include($file);                // Include the file
        $contents = ob_get_contents(); // Get the contents of the buffer
        ob_end_clean();                // End buffering and discard
        return $contents;              // Return the contents
    }
}

/**
 * An extension to Template that provides automatic caching of
 * template contents.
 */
class CachedTemplate extends Template {
    var $cache_id;
    var $expire;
    var $cached;

    /**
     * Constructor.
     *
     * @param $cache_id string unique cache identifier
     * @param $expire int number of seconds the cache will live
     */
    function CachedTemplate($cache_id = null, $expire = 900) {
        $this->Template();
        $this->cache_id = $cache_id ? 'cache/' . md5($cache_id) : $cache_id;
        $this->expire   = $expire;
    }

    /**
     * Test to see whether the currently loaded cache_id has a valid
     * corrosponding cache file.
     */
    function is_cached() {
        if($this->cached) return true;

        // Passed a cache_id?
        if(!$this->cache_id) return false;

        // Cache file exists?
        if(!file_exists($this->cache_id)) return false;

        // Can get the time of the file?
        if(!($mtime = filemtime($this->cache_id))) return false;

        // Cache expired?
        if(($mtime + $this->expire) < time()) {
            @unlink($this->cache_id);
            return false;
        }
        else {
            /**
             * Cache the results of this is_cached() call.  Why?  So
             * we don't have to double the overhead for each template.
             * If we didn't cache, it would be hitting the file system
             * twice as much (file_exists() & filemtime() [twice each]).
             */
            $this->cached = true;
            return true;
        }
    }

    /**
     * This function returns a cached copy of a template (if it exists),
     * otherwise, it parses it as normal and caches the content.
     *
     * @param $file string the template file
     */
    function fetch_cache($file) {
        if($this->is_cached()) {
            $fp = @fopen($this->cache_id, 'r');
            $contents = fread($fp, filesize($this->cache_id));
            fclose($fp);
            return $contents;
        }
        else {
            $contents = $this->fetch($file);

            // Write the cache
            if($fp = @fopen($this->cache_id, 'w')) {
                fwrite($fp, $contents);
                fclose($fp);
            }
            else {
                die('Unable to write cache.');
            }

            return $contents;
        }
    }
}

可以看到有2個class,第1個實現樣板功能,第2個繼承第1個進一步實現快取功能,原理相當簡單,看fetch方法便知道,利用extract傳進來的陣列變成鍵值為名稱的變數,然後使用緩衝區,將樣板檔引用執行,便會自動套用變數把html產生,將結果存在變數內,然後再輸出緩衝並回傳,就可以取得套好的html字串了,真的非常有巧思,樣板檔會長這樣子

<html>
    <head>
        <title><?=$title;?></title>
        <link href="style.css" rel="stylesheet" type="text/css" />
    </head>

    <body>
        <h1><?=$title;?></h1>

        <?=$content;?>
    </body>
</html>
<table cellpadding="3" border="0" cellspacing="1" bgcolor="#CCCCCC">
    <tr>
        <td bgcolor="#F0F0F0">Id</td>
        <td bgcolor="#F0F0F0">Name</td>
        <td bgcolor="#F0F0F0">Email</td>
        <td bgcolor="#F0F0F0">Banned</td>
    </tr>

<?php foreach($users as $user): ?>
    <tr>
        <td bgcolor="#FFFFFF" align="center"><?=$user['id'];?></td>
        <td bgcolor="#FFFFFF"><?=$user['name'];?></td>
        <td bgcolor="#FFFFFF"><a href="mailto:<?=$user['email'];?>"><?=$user['email'];?></a></td>
        <td bgcolor="#FFFFFF" align="center"><?=($user['banned'] ? 'X' : ' ');?></td>
    </tr>
<?php endforeach; ?>

</table>

絕大部分是html,少部分是php輸出,之後使用方法如下:

$tpl = new Template('index.tpl'); // this is the outer template
$tpl->set('title', 'User List');

$body = new Template('body.tpl'); // This is the inner template

/*
 * The get_list() method of the User class simply runs a query on
 * a database - nothing fancy or complex going on here.
 */
$body->set('user_list', $user->get_list());

$tpl->set('content', $body);

echo $tpl->fetch('index.tpl');

只需要讀取樣板檔,然後填入樣板檔內定義的變數,甚至可以填入另一個樣板檔,達到重複使用的效果,是不是非常簡單易用呢,最後說明一下快取的部分,每次存取的時候,判斷是否有相同快取檔存在,快取檔檔名會使用傳入的字串編成md5,作者建議使用網址帶get的參數,這樣參數不同時,快取得檔案也不同,然後可以設置快取過期時間,會自動檢查快取檔到當前時間是否已超過過期時間,若還沒則直接讀取快取檔內容,超過則重新建立,算是方便易用的快取方式喔~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言