Symfony Templates and Ruby’s ERb

  • Posted by Mike Naberezny in PHP,Ruby

    After hearing the podcast, I went over to the Symfony website to check it out. I haven’t downloaded Symfony yet but I did watch this screencast. One thing that I think Symfony gets right is that it appears to use partitioned PHP code for its templates, in the spirit of Paul‘s Savant system. Putting all the “Smarty vs. Savant”-type arguments aside, the resulting templates in Symfony are nice and look very much like ERb (.rhtml) as it is used by Ruby-on-Rails. I think the ERb templates are a bit cleaner. However, it doesn’t have to stay that way.

    In Ruby, instance variables are accessed with @var_name. This is the same as self.var_name in Python or $this->var_name in PHP. If the template’s variables are scoped as instance variables of a class such as in Savant, and short_open_tag is disabled, the resulting PHP syntax can be a bit unwieldy:

    <?php echo $this->var_name ?>

    Compare this to the succinct but equally powerful ERb:

    <%= @var_name %>

    I noticed in the Symfony demo that there is no separation of scope between variables passed to the template from the controller and local variables in the template. In the screencast, $products in the template comes from the controller and is indistinguishable from the local variables $id and $title. I’d like to see them scoped properly ($this->products) but I can certainly understand why they did it this way. Using $this-> in the template everywhere quickly gets messy.

    One solution to this problem is to enable short_open_tags and then give the nod to Ruby by overloading PHP’s silence operator (@) to $this-> in the templates. This gives a very similar syntax to ERb:

    <?= @$var_name ?>

    Using the silence operator in this way won't break syntax highlighting in the IDEs, since this is legal PHP syntax on its own. The silence operator would not normally prefix a dollar sign, so keeping the dollar allows us to distinguish between normal code that should be silenced and when the operator is overloaded to $this->. Templates should never be doing operations that need to be silenced anyway.

    The syntax shown above is much shorter and more convenient but there appear to be two problems with this solution. First, relying on short_open_tag is a beginner's mistake in PHP since it's not enabled on all installations. Second, it's not practical on most installations to install an extension to do this overloading.

    Fortunately, there is an easy solution to both of these problems. At some point, the template engine must include() the templates for PHP to execute them. A stream wrapper can be registered to rewrite the @$ into $this-> and also expand short tags if short_open_tag is not enabled. The result is a short snippet of pure PHP code that gives this syntax and should also run on the majority of installations.

    Here's the proof of concept (PHP 5).

13 comments

  • comment by Maarten Manders 20 Feb 06

    Clever idea, nicely implemented. Thumbs up!

  • comment by Alan Knowles 20 Feb 06

    Please read the blog post about outputing raw PHP – It’s a bad idea, asking for trouble…

  • comment by Jake Grimley 20 Feb 06

    Mmmm…. not sure if I like this or not… I have to admit I find the idea intriguing, but it’s basically syntactic sugar.

    I think the thing that makes me most uncomfortable is that it uses a symbol with an existing meaning in PHP and replaces it to mean something else… I think if another symbol, as-yet unused by PHP, were to be picked as a stand-in for $this-> you could make an argument that you’re just extending and fixing the short-tag style in one…

  • comment by Paul M. Jones 20 Feb 06

    Hi Jake — I don’t think there are many unused symbols. Here are the non-word characters on my keyboard:

    ~ ` ! @ # $ % ^ & * ( ) – = + { } [ ] \ | : ” ; ‘ , . / ?

    I think they *all* have some special meaning to PHP. The question then is to pick the “least-worst” symbol, because there’s isn’t a “good” one. I think the @ sign, of them, is a good choice.

  • comment by Paul M. Jones 20 Feb 06

    Oh, and Mike — really neat idea man. :-)

  • comment by Jake Grimley 20 Feb 06

    Yeah point taken. If I could have made a better suggestion guess I would have in my original post.

    I suppose it’s a matter of context too, I mean in the short-tag style using = in the context of has a different meaning to using it as the assignment operator and AFAIK this symbol was chosen purely because it already had that meaning in ASP and JSP. So perhaps using @ within short tags in the interests of associating with ERB is OK.

    See — I’ve talked myself round… Now if somebody could just find some way to allow us to pass arrays to methods without using the clumsy array() syntax perhaps I’ll stop coveting RoR!

  • comment by Rod 20 Feb 06

    [If] short_open_tag is disabled, the resulting PHP syntax can be a bit unwieldy:

    var_name ?>

    Compare this to the succinct but equally powerful ERb:

    But when exactly is short_open_tag not enabled? it is by default, and therefore you can use:

    which is just as concise.

  • comment by Mike Naberezny 20 Feb 06

    It’s unwise and generally regarded as a beginner’s mistake to rely on short_open_tag because it is one of the most frequently disabled php.ini settings, especially on shared hosts. short_open_tag is enabled in php.ini-dist but disabled in php.ini-recommended.

  • comment by matt 21 Feb 06

    What about replacing all echos and prints:

    echo @$XXX

    becomes:

    echo htmlentities(XXX, ENT_QUOTES)

    Maybe change the @ to ! for printing raw data:

    !$body_text

    Hmm… Actually, just replace “echo” with “echo htmlentities(XXX, ENT_QUOTES)” and create a new function for printing raw:

    echor @$product_details

    ???

    -m

  • comment by Mike Naberezny 21 Feb 06

    That’s one way to think about it. You could also build a plugin mechanism for template helpers to do things like escaping, as Paul has done in Savant. Also, the example template class is very crude in that it does nothing to sanitize data going into it. Another way to approach this problem would be to use __set() to filter all data put into the template with a default filtration strategy, and then have a separate assign() method to allow for filtering by different strategies.

  • comment by troelskn 9 May 06

    Templates should never be doing operations that need to be silenced anyway.

    I don’t fully agree with that. I always run with full error-reporting, which can lead to some unwieldy syntax, if you aren’t sure if a variable is set. Using @ in front of the variable, makes it equal null. I use that quite often in templates.
    Maybe the I’m the one who’s doing it wrong though – could be I should just lower the error-level inside templates, to ignore warnings. Are you guys doing that ?

  • comment by anirudh 2 Mar 07

    i wan to know the clear syntax of erb tags

  • comment by matt 30 May 09

    i dont like the idea of ruby and symphony to mess up the templates with executable code. its a bloody pest. why every framework thinks the smarty way it a good one ? i dont understand …

Post a comment


Thanks for commenting. Please remember to be nice to others and keep your comment relevant to the discussion. I reserve the right to remove comments that don't meet these simple guidelines.