views:

244

answers:

3
+2  Q: 

PHP Templating

I'm writing a simple templating layer in PHP but I've got myself a little stuck. Here's how it works at the moment:

Firstly I use fetch_template to load the template contents from the database - this works (and I collect all the templates at startup if you're interested).

I use PHP variables in my template code and in the logic - e.g.:

// PHP:
$name = 'Ross';

// Tpl:
<p>Hello, my name is $name.</p>

I then use output_template (below) to parse through the variables in the template and replace them. Previously I was using template tags with a glorified str_replace template class but it was too inefficient.

/**
 * Returns a template after evaluating it
 * @param   string  $template   Template contents
 * @return  string  Template output
 */
function output_template($template) {
    eval('return "' . $template . '";');
}

My problem, if you haven't already guessed, is that the variables are not declared inside the function - therefore the function can't parse them in $template unless I put them in the global scope - which I'm not sure I want to do. That or have an array of variables as a parameter in the function (which sounds even more tedious but possible).

Does anyone have any solutions other than using the code from the function (it is only a one-liner) in my code, rather than using the function?

Thanks, Ross

P.s. I know about Smarty and the vast range of templating engines out there - I'm not looking to use them so please don't suggest them. Thanks!

+5  A: 

I'd pass an associative array with variables to replace, then extract() them.

Then you could also pass $_GLOBALS to achieve the same result.

function output_template($template, $vars) {
    extract($vars);
    eval('return "' . $template . '";');
}

Edit: you might also want to consider string subtitution instead of eval, depending on who's allowed to write your templates and on who specifies which template to load. Then there might be a problem with escaping, too...

Dave Vogt
I expect to be the only one touching anything code-wise on this system, the main reason I'm not using string vars (e.g. {VARNAME}) is because this is faster. I was skeptical at first but a friend pointed out to me how slow my original template compiler was.
Ross
+2  A: 

Also, expanding on davev's comment eval is a bit ugly.

If you can do something like

function inc_scope( $file , $vars )
{
    extract($vars); 
    ob_start(); 
    require($file); 
    return ob_get_clean(); 
}

Then you get to use plain-old-php as your templating language, and you don't get any evil-evals, and "extract" + buffering merely limits the visible scope of the php code in the require.

Kent Fredric
"evil evals" - they're only evil if you're doing something stupid like eval('echo $_GET['name'];');!
Ross
eval'ed code is much harder to follow/debug than static code. Hence the "evil" label.
troelskn
+4  A: 

Rather than run through your loop you can use include($template_name)

Or, if you want the content of the output from the template, you can do something like this:

$template_name = 'template.php';

// import the contents into this template
ob_start();
include($template_name);
$content = ob_get_clean();

// do something with $content now ...

And remember, in your template, you can use the often overlooked PHP syntax:

<?php if ($a == 5): ?>
A is equal to 5
<?php endif; ?>

Alternative syntax is available for if, while, for, foreach and switch ... perfect for manipulating the data in your template. See link text for more details.

Howard Sandford