3
\$\begingroup\$

I'm doing something quite strange. I'm trying to create a tiny system for creating templates inline in PHP, so that I can refactor by creating multiple templates in the original script, and eventually move the templates to separate scripts.

Here's the silly/basic template library that just calls an anonymous function that gets passed in after some HTML header stuff, and then calls a footer:

<?php
// System for using simple, native php templates.

// TODO: Put this in a namespace to keep it clean and separate.

function display_page_inline($templates, $options, $data){
    $title = @$options['title'];
    echo "<html><head><title>".$title."</title></head>";

    if(is_array($templates)){
        foreach($templates as $template_function){
            $template_function($data);
        }
    } else{
        $template($data); // Call & display the template.
    }


    echo "<div>Footer</div>";
    echo "</html>";
}

?>

Here's where it's going to get strange. In the scripts I'm creating anonymous functions, saved to variables, and then passing them to the template library for outputting. To avoid having to call an array element (and check whether the element exists each time), I'm trying to export the array passed in to get standard variables in the template (e.g. $name instead of $data_array['name']). Is there a way to abstract away this behavior in PHP?

<?php
require_once('core.php');


// Inclusion of the template library
require_once('../core/inline_templates.php');
// Initialization Logic
$title = 'Bob';

// Decide what will be able to be output and put it into an array to pass to the template
$template_output_variables = array('name'=>'no name');


// The page gets displayed at the bottom.

// =================== Templates ========================================
// Todo: Potentially namespace the stuff here.
// Define the anonymous template function here, has html and such in native php here.
$contact_us = function ($template_output_variables=null){
    extract($template_output_variables); // Pull the variables.
    // Leave php in the template function.
    ?>
    <body>
    Hello World Body Text, Hello <?php h($name);?>.
    </body>

    <?php
}; // End of template function declaration.


$killer_section = function ($data=null){
    extract($data); // Pull the variables.
    ?>
    Breaking news, There is a killer among us.

    <?php
}; // End of killer section anon. function.



// Display the page.

// call & display the template via delayed execution, display it within a pre-set head and footer.
display_page_inline($templates=array($contact_us, $killer_section), $options=array('title'=>$title), $template_output_variables);



?>

It's very strange, I know, but I'm trying to do a whole new approach to refactoring, and make use of some new PHP 5.3 features while doing it. The goal is to have inline templates that I can put in any script, as many as I want, and move anywhere I want later, or merge the templates, etc.

\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

Something like this would get you most of the way there:

<?php
function h($val) {
    echo $val;
}

function template_function($template_body) {
    return function(array $template_output_variables = null) use ($template_body) {
        if ($template_output_variables !== null) {
            extract($template_output_variables);
        }
        $contents = eval('?>'.$template_body.'<?php');
        echo $contents;
    };
}


$contact_us = template_function('
    <body>
    Hello World Body Text, Hello <?php h($name);?>.
    </body>'
);

$contact_us(array('name' => 'Johnny Boy'));

But it's evil, and you will likely end up with very odd, very hard-to-debug errors once your templates are of reasonable size/complexity. It's an interesting idea though -- if you pursue it, make sure you have a thorough set of test cases ;)

The easiest way to clean it up, IMO, would be to do away with allowing raw php in the templates. I'm pretty partial to Twig, you may be able to find some inspiration there.

\$\endgroup\$
2
  • \$\begingroup\$ Yeah, I'm definitely not doing this for the security, obviously (since the templates make all of php available). If I had to share low security templates with untrusted developers, then I'd move to a templating engine altogether. Anyway, I like the idea of a function that returns an anonymous function. Less so the eval part, though. I'd much prefer to perform that part via an existing php file being included. \$\endgroup\$
    – Kzqai
    Commented Mar 19, 2012 at 19:33
  • \$\begingroup\$ Ahh, indeed. You can use include or require easily -- and cleanly as well using the ob_* functions. And you should definitely prefer them over eval. I didn't use that as my example as I was trying to keep as close to exactly-in-line with the existing code in the comment as possible. \$\endgroup\$
    – jdd
    Commented Mar 19, 2012 at 23:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.