PHP Templating

Here’s a simplified template class that was inspired by PHP Tip: Extract, Variable Variables and Templating. It supports template inheritance, it’s object oriented & got auto escaping variables. Furthermore, it doesn’t need to be compiled, since it’s using plain PHP

The class: tpl.class.php

class tpl {

    var $file;
    var $folder = 'template';
    var $vars;

    function __construct($file) {
        $this->file = $file;
    }

    /**
     * Assign variables to class attributes
     */
    function assign($name, $value) {
        // need to render child template
        if ($value instanceof self) {
            ob_start();
            foreach ($this->vars as $k => $v) {
                if (is_scalar($v) || is_array($v)) {
                    // copy variables to child template
                    $value->assign($k, $v);
                }
            }
            $value->render();
            $html = ob_get_contents();
            ob_end_clean();
            // assign output HTML to parent template variable
            $this->vars[$name] =& $html;
        } else {
            $this->vars[$name] =& $value;
        }
    }

    /**
     * Echo variables and auto escape HTML for string vars
     */
    function e($name) {
        if (is_string($this->vars[$name])) {
            echo htmlspecialchars($this->vars[$name], ENT_QUOTES, 'UTF-8');
        } else {
            echo $this->vars[$name];
        }
    }

    /**
     * Display the main template (usually master/layout template)
     * and set header
     */
    function display() {
        if (!headers_sent()) {
            header('Content-type: text/html; charset=utf-8');
        }
        $this->render();
    }

    /**
     * Include template file
     */
    private function render() {
        require_once dirname(__FILE__) .'/'. $this->folder .'/'. $this->file .'.php';
    }
}

This class is just a basic class that organize the template files, and it can be easily applied to your page controller script, so that you can separate the presentation layer and business logic part.

To use, here are some of the template files, that consist of 3 inheritance levels.

Top level: layout.tpl.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
    <title><?php echo $this->vars['title']; ?></title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
</head>

<body>
    <?php echo $this->vars['body']; ?>
</body>

</html>

Middle level: body.tpl.php

<h2><?php $this->e('blog_title'); ?></h2>
<p><?php $this->e('blog_content'); ?></p>
<hr />
<?php echo $this->vars['portlet']; ?>

Bottom level: portlet.tpl.php

<div style="width: 120px; border: 1px solid #ccc; background: #eee; text-align: center; padding: 10px;">
    <span style="color: #333; font-size: 11px; font-family: sans-serif">This is portlet<br/><?php $this->e('portlet_name'); ?></span>
</div>

Then in your page controller code, add this to the bottom of the file to render the template & output:

require_once 'tpl.class.php';

$tpl = new tpl('layout.tpl');
// assign all variables first before display the template
$tpl->assign('title', 'New Test Template');
$tpl->assign('blog_title', 'My First Post');
$tpl->assign('blog_content', 'Lorem ipsum dolor sit amet');
$tpl->assign('portlet_name', 'My lil' portlet');
$tpl->assign('portlet', new tpl('portlet.tpl')); // this variable needed by body.tpl, so assign it first
$tpl->assign('body', new tpl('body.tpl'));
$tpl->display();

The order of assigning the variables is important, because you cannot echo or access variables that are not yet assigned.

This class is very much working now, and you may add more features to it – template caching, setting custom header to support other output type (such as RSS, XML etc.), data formatting functions, language translation support, gzip support etc.

Share this...
Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInPin on Pinterest

Leave a Reply

Your email address will not be published. Required fields are marked *