PHP – A Template Class with Simple Parser

June 18, 2009 by: Allen Sanford

It is actually very easy to create a Template system in PHP. Just about every CMS system out there uses some sort of template system. There will come a time that every developer, for one reason or another will need to create their own template system. What I have decided to do is create a starting point for a simple Template Parser system that should be ample for most, yet scalable for the rest. I am going to be following the ever growing and popular separation of logic and design, but you can still place PHP code in the template file should you choose to.

You will need two folders one named includes to put the template.php in and another named template to put the template file in. You can of coarse move these or rename them as you see fit.

First things, first, we will need a template to work with. I am going to opt to use a very simple template. FYI here we can use any delimiters for the template variable but I am going to stick with “{” and “}”. I am also going to be allowing for a simple loop structure like {menu} <li>{item}</li> {/menu}, that way you can implement a menu without knowing how many items are in the menu. OK,OK,here is the template.

?Download index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <title>{title}</title>
    </head>
    <body>
        <ul>
            {menu}
               <li><a href="{menu_link}">{menu_text}</a></li>
            {/menu}
       </ul>
       {body}
       </body>
</html>

There is our super duper simple example template. This template does is not meant to look pretty but it just shows the two styles of template variables and how we use them.

Now comes the template class its self. The template class will do things for use one display or render the template and two parse the template variables and replace them with data. It is worth noting here that we can pass a variable to the render method so instead of display to the standard output it will return a string. The option of returning the template allows for some fancy template assembly and using multiple templates. Drum Roll please …

?Download template.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
    class Template
    {
        var $l_delim = '{';
        var $r_delim = '}';
        var $object;
 
        function __construct()
        {
        }
 
        function _match_pair($string, $variable)
        {
            if ( ! preg_match("|".$this->l_delim . $variable . $this->r_delim."(.+?)".$this->l_delim . '/' . $variable . $this->r_delim."|s", $string, $match))
            {
                return FALSE;
            }
 
            return $match;
        }
 
        function parse($template, $data)
        {
 
            foreach ($data as $key => $val)
            {
                if (is_array($val))
                {
                    $template = $this->parse_pair($key, $val, $template);
                }
                else
                {
                    $template = $this->parse_single($key, (string)$val, $template);
                }
            }
 
            return $template;
        }
 
        function parse_pair($variable, $data, $string)
        {
            if (FALSE === ($match = $this->_match_pair($string, $variable)))
            {
                return $string;
            }
 
            $str = '';
            foreach ($data as $row)
            {
                $temp = $match['1'];
                foreach ($row as $key => $val)
                {
                    if ( ! is_array($val))
                    {
                        $temp = $this->parse_single($key, $val, $temp);
                    }
                    else
                    {
                        $temp = $this->parse_pair($key, $val, $temp);
                    }
                }
 
                $str .= $temp;
            }
 
            return str_replace($match['0'], $str, $string);
        }
 
        function parse_single($key, $val, $string)
        {
            return str_replace($this->l_delim.$key.$this->r_delim, $val, $string);
        }
 
        function set_delimiters($l = '{', $r = '}')
        {
            $this->l_delim = $l;
            $this->r_delim = $r;
        }
 
        function render($file = "index", $data = array(), $return = false)
        {
            $data = (is_null($data)) ? array() : $data;
            global $config;
            ob_start();
            @include_once("template/".$file.".php");
            $buffer = ob_get_contents();
            ob_end_clean();
 
            $buffer = $this->parse($buffer, $data);
 
            if ($return) return $buffer; else echo $buffer;
        }
    }
?>

Well the is the Template class if you copy and paste it, and decide to use the same delimiters for your template as I have for mine the you are good to go and just need to read the usage example below.

?Download index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
    include_once('includes/template.php');
    $template = new Template();
    $data = array(
                  "body" => "Hello World!",
                  "menu" => array(
                                   "menu_text"=> "Foo Bar",
                                   "menu_link" => "http://www.foobar.com/"
                                 )
                );
    $template->render("index", $data);
    //echo $template->render("index", $data. true); // Alternate Usage
?>

Looks like I have delivered a again. Have a Good’n!

Filed under: PHP
Tags: ,

Leave a Reply