If Statements in Templates

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

If Statements in Templates

Post by jackpf »

Hey everyone,

Basically, I'm thinking of making my own template system. Obviously the variable replacements part is easy...but I'm having trouble contemplating how I'm going to evaluate "if" statements.

I've managed to parse simple statements...using regex to turn it into PHP syntax, and eval() - ing the compiled code.

However, this has the limitation of being unable to handle more complex "if" statements, including elseif and else statements. I've had a look through phpBB and smarty's source...but can't figure it out. Google seems to yield no help either...

So I was just wondering if anyone had any experience with this, or had any ideas on how I would go about implementing this?

All suggestions welcome :)

Thanks,
Jack.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: If Statements in Templates

Post by Christopher »

There have been a few discussions, and even some code posted here:

viewtopic.php?f=19&t=83839
viewtopic.php?f=19&t=93782
viewtopic.php?f=50&t=90054
(#10850)
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: If Statements in Templates

Post by jackpf »

Aha, that 3rd thread gave me a few ideas.

Couldn't see any suggestions about if() statements though...That's what I'm particularly interested in.

I've had a go at doing this before, but when I got to parsing if() statements, I just gave up.

And yeah...the contraversy about using a template language...meh. I don't know if I'm actually going to use this, ever...I just thought it'd be fun to try.

I am absolutely clueless about these if statements though...any help or suggestions would be great.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: If Statements in Templates

Post by Christopher »

I am interested in this too. I think the if() part will in place once we can get the template broken into a hierarchy of nested blocks. The you would just run through the blocks and see if they are an if()/while()/for()/foreach(). My initial guess would be to use regexp to get offsets in the text for the starts and ends of all blocks. Then run through that to determine the nesting.

I am assuming that you do not want to use eval() for these templates, since that would negate the only benefit that non-PHP templates have -- security.

PS - I think many of these template systems compile into PHP code and run those templates from a cache
(#10850)
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: If Statements in Templates

Post by jackpf »

Yeah...

The only problem with regex that I've found, is that it doesn't handle nested matches very well.

For example:

Code: Select all

<?php
$syntax = 'if(condition)
{
    if(condition)
    {
        //do something
    }
}';
 
///
 
preg_match('/if\((.*?)\)\s+\{(.*?)\}/is', $syntax, $matches);
echo '<pre>'; print_r($matches);
Matches only

Code: Select all

if(condition)
{
    if(condition)
    {
        //do something
    }
And yeah...using eval would be a last resort. I tried that once, and ended up with very unreadable code for starters.
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: If Statements in Templates

Post by Eran »

I always opt for "include" based template systems instead of "search-and-replace". Why not leverage PHP's internal syntax?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: If Statements in Templates

Post by Christopher »

That's why I was thinking that the first pass is just dealing with the starts and ends of blocks. Then you ladder walk through the two arrays of offsets to deal with the nesting and what the actual statements are. Quick hack, but maybe start with something like this:

Code: Select all

preg_match_all('/\{/is', $syntax, $matches, PREG_OFFSET_CAPTURE);
echo '<pre>'; print_r($matches);
preg_match_all('/\}/is', $syntax, $matches, PREG_OFFSET_CAPTURE);
echo '<pre>'; print_r($matches);
 
(#10850)
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: If Statements in Templates

Post by jackpf »

Idk, I just think it's neater to separate the syntax and formatting.

Although I see there have been many discussions on how this should be done from the threads posted by arborint :)

I've just had the idea of using strpos() to loop through each if statement. Then match up the opening brackets to their closing brackets...hopefully being able to capture whatever's in the middle.

I cba to have a go right now...I'll play around with it tomorrow though :)



EDIT
Oh, hey, arborint...I see you've had the same idea :P Yeah...I reckon that's the way to go.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: If Statements in Templates

Post by Christopher »

jackpf wrote:Oh, hey, arborint...I see you've had the same idea :P Yeah...I reckon that's the way to go.
Obviously we can do something nicer with our delimiters to make it simpler to parse and read.
(#10850)
User avatar
jackpf
DevNet Resident
Posts: 2119
Joined: Sun Feb 15, 2009 7:22 pm
Location: Ipswich, UK

Re: If Statements in Templates

Post by jackpf »

Oh man...this is just mind boggling.

This is what I have so far (it doesn't work at all):

Code: Select all

<?php
function statements($code)
{
    preg_match_all('/if/i', $code, $offsets, PREG_OFFSET_CAPTURE);
    
    $statements = array();
    
    foreach($offsets[0] as $offset)
    {
        $offset = $offset[1];
        
        $first_open_bracket = strpos($code, '{', $offset);
        $next_close_bracket = strpos($code, '}', $offset + 1);
        
        $next_open_bracket = strpos($code, '{', $offset + 1);
        
        if($next_close_bracket < $next_open_bracket)
        {
            $statements[substr($code, $offset, strpos($code, ')', $offset))] = substr($code, $first_open_bracket, $next_close_bracket);
        }
    }
    
    print_r($statements);
}
 
header('Content-Type: text/plain');
 
$code = 'if(condition)
{
    //a
}
if(a){}';
 
 
statements($code);
Don't even ask me what it's supposed to do... :P

Surely there must be an easier way of doing this?!??!
Post Reply