Overview
I'm currently writing a template engine. It even supports multiple "format"s. Currently it can parse .php
files and .tpl
(specific to this engine).
I'll give you a little example of both, just to give you an Idea.
template.php:
Name: <?php echo $this->h($name) ?>
Posts:
<?php foreach($posts as $post): ?>
- <?php echo $this->h($post->name) ?> (<?php echo count($post->comments) ?> comments)
<?php echo $this->render('post/shortpost', array('post' => $post)) ?>
<?php endforeach ?>
This is basicly just a standard PHP.
template.tpl
Name: {>$name}
Posts:
{foreach($posts as $post):}
- {>$post->name} ({=count($post->comments)} comments)
{=:render('post/shortpost', array('post' => $post))}
{endforeach}
This templating "language" simply gets translated into PHP above.
Comparission
eval()
Currently these template's are parsed using eval()
.
Pro
- I don't have to change any code
Contra
- when an error occurs in a template you only get a useless error message which doesn't tell you in which file the error occurs and sometimes the line number is even wrong.
- Security? Template files are only need to be readable?
- It's difficult to debug the code.
- Code is harder to understand
- more .. ?
stream wrappers and include()
I recently read about stream wrappers in php. You even could create your own. A other solution than eval
would be to create a custom stream wrapper for every template "format" and use include to parse the template.
This has the following (potential) flaws:
Pro
- may solve the problems with showing the wrong file/line-number in error messages (has anyone experiences with this?)
- you could handle the template file exactly how to want it to be handled. Full control.
Contra
allow_url_(fopen|include)
has to be on?- it is slow? (is
eval()
slow too?) - no gain in security. include does basically the same thing as eval.
- more ... ?
EDIT: cached parsed files and include()
A third option would to to parse the template to PHP code and cache them (as suggested by @Jen-YaKovalev).
Pro
- includes caching
Contra
- if an error occurs while including the rendered template and an error occurs the error message doesn't point you to the correct file/eventually shows you the wrong line number.
- You need an extra
tmp/
directory to save the parsed files. You need write permissions for PHP/webserver. Would be more insecure because hackers would append some malicious code easier.
EDIT: stream filters and include('php://filter')
lately found the following php.net pages:
php://filter:
http://php.net/manual/en/wrappers.php.phpstrea_filter_register
http://fr2.php.net/manual/en/function.stream-filter-register.php
This would be an other possibility to solve this problem. Using include('php://filter/read=filtername/resource=file.php')
, I could include a file which would first go through the filter filtername
, before it gets executed.
Pro
- doesn't need so much code as stream wrappers
Contra
- not so much possibilities as with stream wrappers (caching?)
- security?
- speed?
Question
- Have experiences using stream wrappers for parsing template files or similar?
- Is there yet an other solution?
- Are there more pro's and contras?
- Which one would you recommend?