Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
456 lines (439 sloc) 23.8 KB
layout status published title author author_login author_email author_url excerpt wordpress_id wordpress_url date date_gmt categories tags comments
post
publish
true
Simple PHP Template Engine
Chad Emrys Minick
admin
cythrawll@codeangel.org
http://
PHP is a bit of a rare language as it can already template into text in markup with zero modifications or libraries. It is probably one of the big contributing factors why PHP is one of the most popular languages on the web today. (Can't be the only factor, it didn't work for ColdFusion) Most other web languages have a one or more templating languages with a different syntax that need to be learned on top of the implementing language. PHP lowers the bar to entry by allowing you to put your PHP code right into your html. But as we all know, sometime in your PHP tour, you will realize the need to separate presentation logic and the application logic. Some developers go running to some other solution that provides a different syntax. I am a bit puzzled on why this seems to be common practice, PHP can provide the same features without throwing another template syntax on top of what PHP already does. You can still achieve the separation needed with a simple class (shown at the end of this article).
14
2009-09-30 22:11:28 -0400
2009-10-01 04:11:28 -0400
Coding
PHP
PHP
Templating
HTML
Coding
id author author_email author_url date date_gmt content
81
Daniel Campbell
danny@sporkbox.us
2009-10-27 17:40:08 -0400
2009-10-27 23:40:08 -0400
This example gave me the necessary foundation to understand the concept behind template engines. It's very simple and easy to approach. I plan on using something similar to it in my backend's next version. Are there any stipulations on using this code?
id author author_email author_url date date_gmt content
82
Chad Emrys Minick
cythrawll@codeangel.org
http://
2009-10-27 17:42:41 -0400
2009-10-27 23:42:41 -0400
I officially license this code with WTFPL: http://en.wikipedia.org/wiki/WTFPL
id author author_email author_url date date_gmt content
155
Frank Munch
sm_codeangel@u5.com
2009-12-12 01:49:46 -0500
2009-12-12 07:49:46 -0500
You don't mention the most important problem with Smarty - that some syntax is very clumsy, it is not object-oriented, and parametrization is difficult. But the value of it is that it is easier to learn than PHP, and definitely less dangerous.
id author author_email author_url date date_gmt content
158
Chad Emrys Minick
cythrawll@codeangel.org
http://
2009-12-13 12:47:04 -0500
2009-12-13 18:47:04 -0500
<a href="#comment-155" rel="nofollow">@Frank Munch</a> I don't think it's easier to learn than PHP at all. There is no evidence towards that. And I think I covered the less dangerous part in the article.
id author author_email author_url date date_gmt content
272
Tomas Arribas
tomas@psycle.com
2010-02-01 09:41:12 -0500
2010-02-01 15:41:12 -0500
There is a small problem with your Template class when using arrays. Try this: [code] $view-&gt;a = array('foo'); var_dump($view-&gt;a); //foo is there, all fine $view-&gt;a[] = 'bar'; var_dump($view-&gt;a); //bar is not there! [/code] To solve this, you need to return the __get by reference, like this: [code] public function &amp;__get($name){ if (isset($this-&gt;vars[$name])) return $this-&gt;vars[$name]; else return null; } [/code] It's also advisable to overload isset and unset [code] public function __isset($name) { return isset($this-&gt;vars[$name]); } public function __unset($name) { unset($this-&gt;vars[$name]); } [/code] Cheers!
id author author_email author_url date date_gmt content
318
AntonioCS
antoniocs@gmail.com
2010-03-03 11:56:09 -0500
2010-03-03 17:56:09 -0500
Why not just use title ?&gt; since you are including in the class code and you already have the __set method so it should be simple to change to using $this in the template :)
id author author_email author_url date date_gmt content
359
Chad Emrys Minick
cythrawll@codeangel.org
http://
2010-03-11 12:23:29 -0500
2010-03-11 18:23:29 -0500
I am not sure I understand the question.
id author author_email author_url date date_gmt content
508
Refactoring PHP &laquo; Dan Bernardic
2010-06-15 00:07:16 -0400
2010-06-15 06:07:16 -0400
[...] purpose of most PHP code is to output HTML that the web server will send back to the browser. If you have a table that has 20 rows, and all [...]
id author author_email author_url date date_gmt content
589
Kim N. Lesmer
knl@bitflop.com
2010-09-07 20:58:48 -0400
2010-09-08 02:58:48 -0400
Beautiful article! Could not agree more!
id author author_email author_url date date_gmt content
1163
Christian South
csouth@xistins.com
2011-02-15 12:20:09 -0500
2011-02-15 18:20:09 -0500
<a href="#comment-318" rel="nofollow">@AntonioCS</a> <a href="#comment-359" rel="nofollow">@Chad Emrys Minick</a> I believe what he is referring to is dropping the extract($this-&gt;vars); Without your template acts as part of the view class. In that way all your vars are $this-&gt;title and $this-&gt;foo but you also have access to functions (@see view helpers like Zend_View_Helper) through the __call magic function inside of your Template class. All and All nice work.
id author author_email author_url date date_gmt content
1925
Richard
willis.rh@gmail.com
2011-04-17 13:56:00 -0400
2011-04-17 19:56:00 -0400
A similar article was written in 2003 http://www.massassi.com/php/articles/template_engines/ :)
id author author_email author_url date date_gmt content
1992
Chad Emrys Minick
cythrawll@codeangel.org
http://
2011-04-22 08:00:25 -0400
2011-04-22 14:00:25 -0400
really you still have access to class methods, even with extract(). The example I provided was the simplest template engine to show off how to do it. I really suggest that people do add in view helper support as well. Maybe I'll write another article sometime showing how to do it.
id author author_email author_url date date_gmt content
3727
Strategies for migrating live site to MVC structure? | SeekPHP.com
2011-10-18 03:33:57 -0400
2011-10-18 09:33:57 -0400
[...] definite thing you might want to look at are the ways of using templates in php. Examine the code, and see what you has to change to fit your needs (it is more of a direction, not [...]
id author author_email author_url date date_gmt content
5543
Oscar
oscar@oscarm.org
2012-03-12 12:07:22 -0400
2012-03-12 18:07:22 -0400
You woudln't need the Exception inside __set if you defined a property named 'view_template_file'
id author author_email author_url date date_gmt content
5851
Gerome
gerome@googleadmin.com
2012-04-07 09:24:21 -0400
2012-04-07 15:24:21 -0400
i also love the kiss princip. your words are completely right. template engines are so redundant. Lol they even have great disadvantages. learning a bit php is cool since it can be used on many fields. a kiss tut about using plugins prerendering data would be cool.
id author author_email author_url date date_gmt content
8488
Ben
b3n.ji@gmx.net
2012-09-26 07:01:42 -0400
2012-09-26 13:01:42 -0400
Thanks for this simple template class, but I have a question regarding multidimensonial arrays. How can I achieve to get these filled? Background: I have a while loop in which some more variables need to be filled in. I would appreciate any help on this! Thanks in advance!
id author author_email author_url date date_gmt content
8865
Что такое модель в MVC | Заметки web программиста
2012-10-20 18:08:06 -0400
2012-10-21 00:08:06 -0400
[...] can either use either native PHP templates or use some third-party templating engine. There also might be some third-party libraries, which [...]
id author author_email author_url date date_gmt content
9301
Ivo
ivoreali@gmail.com
2012-11-09 04:36:05 -0500
2012-11-09 10:36:05 -0500
Very good reading, thanks! I agree with everything you said but couldn't agree more with your clarification on Smarty templating engine. A car on top of another car, and most people just mention the advantages of the car on the top, forgetting the overload you are causing on the bottom car. I would even mention further, the car on the top would need you to learn how to drive in a different way!
id author author_email author_url date date_gmt content
9311
Jonathan
tornadojon@hotmail.com
2012-11-09 15:53:12 -0500
2012-11-09 21:53:12 -0500
I tend to disagree firstly because this breaks the OO, I always try to avoid to usage of magic methods __get and __set. Secondly how would you use this with more complicated structure like a table of results.
id author author_email author_url date date_gmt content
9524
Chad Emrys Minick
cythrawll@codeangel.org
http://
2012-11-14 05:06:08 -0500
2012-11-14 11:06:08 -0500
<a href="#comment-9311" rel="nofollow">@Jonathan </a> I am curious to why you think that assigning into properties "breaks the OO". A complicated structure like a table of results doesn't really add, or take away any complexity in the template. You can still assign the value into the scope of the template, and then loop over it the same way you would in PHP. Even do nested looping!
id author author_email author_url date date_gmt content
9526
Chad Emrys Minick
cythrawll@codeangel.org
http://
2012-11-14 05:11:05 -0500
2012-11-14 11:11:05 -0500
<a href="#comment-8488" rel="nofollow">@Ben </a> There's several ways you can do this. You can just assign a multi dimensional array into the template and loop over it like you normally would. The other way I've been thinking about doing a blog about... Using the SPL to make a sort of "lazy iterator" so that the values of the array aren't filled out until you loop over them. You can simply just assign the object into the view. As you loop over object, it will get the data you need.
id author author_email author_url date date_gmt content
10290
Dejan
dejan.marjanovic@gmail.com
2012-12-30 15:56:32 -0500
2012-12-30 21:56:32 -0500
extract($this-&gt;vars, EXTR_SKIP); Would prevent overwrite of $view_template_file.
id author author_email author_url date date_gmt content
10293
Chad Emrys Minick
cythrawll@codeangel.org
http://
2012-12-31 01:08:03 -0500
2012-12-31 07:08:03 -0500
great tip! thanks.
id author author_email author_url date date_gmt content
16139
Richie
ric96003131@hotmail.com
2013-06-20 06:01:24 -0400
2013-06-20 12:01:24 -0400
Faith is knowledge ... and in the wrong hands it can be very painful. One of the major drawbacks to your argument (which I understand being - the use of Smarty is redundant) Is without a different template language, or rules in place to stop biz logic seeping into presentation code - your asking for trouble. You can cache/compile any of these so-called "redundant" layers without affecting other layers of your code. If your building a little percy website, by all means use PHP for both templates and backend code, but if you don't have rules and enough discipline in place to prevent application seepage between these layers on a large scale project - your asking for trouble! Another point about OO in front end code. Ask yourself, what tools do you really need for the presentation layer? Repeating groups ... conditional statements ... That's actually about it. If your thinking of something more complicated, you probably have your biz logic in the wrong place. The only exception to this I would suggest are view helpers. So KISS in this case is adding layers to your apps - NO KISS are for people who us a sledgehammer for everything.
id author author_email author_url date date_gmt content
18440
How should a model be structured in MVC? | Northwind Traders Documentation
2013-08-07 11:29:53 -0400
2013-08-07 17:29:53 -0400
[...] can either use either native PHP templates or use some third-party templating engine. There also might be some third-party libraries, which [...]
id author author_email author_url date date_gmt content
19845
Firgas
firgas@gmail.com
2013-08-25 14:43:52 -0400
2013-08-25 20:43:52 -0400
Hello, this article has really persuaded me that PHP is a good choice for templating! Thanks! What do you say on the example bellow. I have tried to improve the security of the template php. Instead of "include($view_template_file);" I am first reading from the file and do some operations with it: - possibility of tag change (nobody will know this is PHP) - no use of $this variable in the template (Now you even can't see Parser class methods!!!) - only one expression per tag Than I simply run it by the eval() function. Introducing preg_replace is maybe step backwards but how to do it in a different way? Anyway, I still don't have to write my own parser for statements! "" ?&gt;")); //&lt;? // do some additional $patterns = array( &#039;//', // remove php with $this variable and multiline code '/&lt;\?\s/&#039;, // add &quot;php&quot; after each &quot;&lt;?&quot; &#039;/&lt;\?(\=|php\=|php)?\s?\$/&#039;, // automaticly echo variables ); $replace = array( &#039;&#039;, &#039;&lt;?php &#039;, &#039;do_parse($file,$values); } private function run_parsing($template_code,$template_values) { extract($template_values,EXTR_SKIP); ob_start(); eval("?&gt;".$template_code."
id author author_email author_url date date_gmt content
19846
Firgas
firgas@gmail.com
2013-08-25 14:48:11 -0400
2013-08-25 20:48:11 -0400
Sry for spamming, but code in the previous post was somehow srewed because of the PHP opening tags! Hope this time it will be good public function parse($file,$values) { $file = file_get_contents($file); // change tags if you want $file = strtr($file,array("{%"=&gt;"" ?&gt;")); //&lt;? // do some additional $patterns = array( &#039;//', // remove php with $this variable and multiline code '/&lt;\?\s/&#039;, // add &quot;php&quot; after each &quot;&lt;?&quot; &#039;/&lt;\?(\=|php\=|php)?\s?\$/&#039;, // automaticly echo variables ); $replace = array( &#039;&#039;, &#039;&lt;\?php &#039;, &#039;do_parse($file,$values); } private function run_parsing($template_code,$template_values) { extract($template_values,EXTR_SKIP); ob_start(); eval("?&gt;".$template_code."&lt;?php &quot;); //&quot; return ob_get_clean(); }
id author author_email author_url date date_gmt content
19847
Firgas
firgas@gmail.com
2013-08-25 14:56:20 -0400
2013-08-25 20:56:20 -0400
Hopefully now... I have substituted all "[?php ","%}"=&gt;" ?&gt;")); // do some additional $patterns = array( '/[\?.*(\$this\W+|\;).*\?\&gt;/', // remove php with $this variable and multiline code '/[\?\s/', // add "php" after each "[?" '/[\?(\=|php\=|php)?\s?\$/', // automaticly echo variables ); $replace = array( '', '[?php ', '[?php echo $', ); $file = preg_replace($patterns,$replace,$file); return $this-&gt;do_parse($file,$values); } private function run_parsing($template_code,$template_values) { extract($template_values,EXTR_SKIP); ob_start(); eval("?&gt;".$template_code."[?php "); return ob_get_clean(); } }
id author author_email author_url date date_gmt content
20727
PHP MVC - Template / Loading variables Issue - PHP Solutions - Developers Q &amp; A
2013-09-10 05:49:17 -0400
2013-09-10 11:49:17 -0400
[...] P.P.S. For how to implement pure php templates, read this article. [...]

PHP for templating?

PHP is a bit of a rare language as it can already template into text in markup with zero modifications or libraries. It is probably one of the big contributing factors why PHP is one of the most popular languages on the web today. (Can't be the only factor, it didn't work for ColdFusion) Most other web languages have a one or more templating languages with a different syntax that need to be learned on top of the implementing language. PHP lowers the bar to entry by allowing you to put your PHP code right into your html. But as we all know, sometime in your PHP tour, you will realize the need to separate presentation logic and the application logic. Some developers go running to some other solution that provides a different syntax. I am a bit puzzled on why this seems to be common practice, PHP can provide the same features without throwing another template syntax on top of what PHP already does. You can still achieve the separation needed with a simple class (shown at the end of this article).

I mainly see two solutions that people tend to use over PHP. One solution is to use a premade template engine like Smarty on top of PHP. The other is to use string replacement techniques on a template file.

String replacement... sucks

If you wrote your own template engine most likely using a str_replace or perhaps preg_replace to implement the embedding of dynamic parts of the code. There are two problems with this: One, it's slow; Secondly it's difficult to implement all the features needed to provide a robust templating language. Things like formatting functions, control structures etc are a bit clumsy to add to a solution like this. The other option is to implement very simple variable replacement, and then doing your formatting functions, control structures, etc. in your controller and just assign the result to variable replacement, however, that is completely against the point of having a template engine. The separation of presentation logic and app logic gets pretty blurry when you do some of the presentation logic outside of the template.

Did I mention it's a pretty slow solution?

Smarty and other template engines

Smarty and similar template engines are pretty darn redundant. Here is an example of the workflow for Smarty:

  • Smarty language is parsed
  • Compiled to PHP
  • PHP code is cached
  • PHP code is parsed
  • PHP code is compiled to opcodes
  • If you have a opcode cache, opcodes are cached
  • opcodes are ran

If you don't see the redundancy there, I'm not doing my job very well. The whole idea of Smarty is like having a car on top of a car and believing it improves your gas mileage. Most people complain that the Smarty syntax is better than PHP's for templating. Bull. There is nothing really gained in Smarty's syntax, it only looks more concise, but in reality there is not enough gains to support having the bloat on top of PHP. You save a couple of keystrokes, big deal. {$var} vs. <?=$var?>. That is micro-optimization if I ever saw it. PHP control structres and formatting are much more concise and cleaner looking than Smarty's. Smarty doesn't work with most IDE's, so with PHP you gain everything you get with your IDE (or editor), code completion, highlighting, syntax linting, and more!

common (lame) excuses

My designers don't know PHP

They also don't know the templating language you pick for them. If they are going to learn something, have them just learn enough PHP to do their templating. The syntax of something like smarty isn't really easier to learn at all.

I can't use PHP! that's not separating the presentation logic!

Actually you can achieve clear separation. See the class code below.

PHP syntax sucks for Templating

No, it's just fine. Really.

I don't trust my designers with PHP

You are using a templating engine to solve the wrong problem. Template engines are meant to achieve higher maintainability through separation of logic. What you are trying to solve is a flaw in your job culture. These days, designers don't need to write bad server side code to cause a lot of hurt, they can write some horrid client side code that can be just as bad. Also your templating engine should be flexible in case you run into a wall in implementation. You don't want to paint yourself in a architectural corner because you don't do code review. (if you really don't trust your designers, only let them make static html mockups, have a jr. developer make them into templates.)

I don't like PHP

Me either, that's why I work with Java and JSP.

The Code:

{% highlight php %}

vars[$name]; } public function __set($name, $value) { $this->vars[$name] = $value; } public function render($view_template_file) { extract($this->vars, EXTR_SKIP); ob_start(); include($view_template_file); return ob_get_clean(); } } {% endhighlight %}

Usage:

main.php template:

{% highlight html+php %} <title></title>

{% endhighlight %}

content.php:

{% highlight html+php %}

{% endhighlight %}

controller.php:

{% highlight php startinline %} $view = new Template();

$view->title = "hello, world"; $view->links = array("one", "two", "three"); $view->body = "Hi, sup";

$view->content = $view->render('content.php'); echo $view->render('main.php'); {% endhighlight %}

Other PHP templating solutions you may want to check out

PHP Savant
Zend View, Part of the Zend Framework

*EDIT* Added checks to make sure that no one tries to binding a variable named view_template_file to prevent somone doing something silly and bind the whole request to the function overriding the variable. Causing a nasty vulnerability

You can’t perform that action at this time.