Click to See Complete Forum and Search --> : code optimisation?


mrhappiness
03-15-2005, 11:23 AM
Hi there

I'm developing my own template engine atm.
A template file being called in my script get's converted to php-code. This code is used as long as the underlying template didn't get changed.
If the underlying template got changed it's "compiled" once again.
This way I don't have to parse the template over and over again but parse it only once and reuse the produced php-code.

Please have a look at the code being produced and tell me what you think about it. How can the code be optimised t make it somewhat faster?

tia


template:<h1>{headline capitalize default "Welcome"}</h1>
<p>Welcome!<br />
I proudly present to you all your users including their rights.</p>
{loop users}
{if _first}<ul>{endif}
<li>user: {username}
{loop rights}
{if _first}<ul>{endif}
<li>{right}</li>
{if _last}</ul>{endif}
{endloop rights}</li>
{if _last}</ul>{endif}
{endloop users}produced php:<?php
/*
Template compiled using ExT 2.0.0.0
Compilation date: Tue, 15 Mar 2005 16:19:18 +0100
Compilation time: 112.5 ms
Template: user_rights.tpl
*/


/* Load needed modifiers */
require_once $this->_folders['extension_dir'].'modifiers/modifier.capitalize.php';

/* Compiled loops */
function ext_loop____user_rights_tplusers_1($content, &$this) {
$result = '';
if (is_array($content))
foreach ($content as $data) {
if (!isset($data['username'])) $data['username'] = NULL;
if (!isset($data['rights'])) $data['rights'] = NULL;
$position = isset($position) ? ++$position : 1;
$count = isset($count) ? $count : count($content);
$first = $position == 1;
$last = $position == $count;
$result .= '
'.(((isset($first) ? $first : NULL)) ? '<ul>' : '').'
<li>user: '.$data['username'].'
'.ext_loop____user_rights_tplusers_1rights_1($data['rights'], $this).'</li>
'.(((isset($last) ? $last : NULL)) ? '</ul>' : '').'
';
}
return $result;
}

function ext_loop____user_rights_tplusers_1rights_1($content, &$this) {
$result = '';
if (is_array($content))
foreach ($content as $data) {
if (!isset($data['right'])) $data['right'] = NULL;
$position = isset($position) ? ++$position : 1;
$count = isset($count) ? $count : count($content);
$first = $position == 1;
$last = $position == $count;
$result .= '
'.(((isset($first) ? $first : NULL)) ? '<ul>' : '').'
<li>'.$data['right'].'</li>
'.(((isset($last) ? $last : NULL)) ? '</ul>' : '').'
';
}
return $result;
}


/* template function */
function ext____user_rights_tpl(&$this, &$data) {
error_reporting(E_ALL);
if (!is_array($data)) $data = array();
if (!isset($data['headline'])) $data['headline'] = NULL;
if (!isset($data['users'])) $data['users'] = NULL;
if (!isset($data['default'])) $data['default'] = NULL;
$result = '<h1>'.ext_compile_modifier_capitalize($data['headline'], array(0 => $data['default'], 1 => 'Welcome')).'</h1>
<p>Welcome!<br />
I proudly present to you all your users including their rights.</p>
'.ext_loop____user_rights_tplusers_1($data['users'], $this);

return $result;} ?>$data contains all vars assigned to the template
inside loops it contains the vars assigned to this loop
$this is a refernce to the template class instance used in the script

bubblenut
03-16-2005, 06:08 PM
Looks pretty damned good to me. There's a tiny bit of redundancy which I'm only pointing out because you're asking about optimization and I'm therefore going to assume you want to be anal about your optimization.

In both of the first two functions you have these two lines in the for each.

$position = isset($position) ? ++$position : 1;
$count = isset($count) ? $count : count($content);

With both of these lines you can get rid of the condition in the foreach by doing a little initialization before you enter it.

$position = 0;
$count = count($content);
foreach($content as $data) {
//some stuff
$position++;
//some more stuff
}



$first = $position == 1;

Also, you can do away with this comparison too by initializing it to true before you enter the foreach and setting it to false at the very end of the iteration block.

$first=true;
foreach(/*stuff*/) {
/*stuff*/
$result.=/*stuff*/
$first=false;
}


Also, the isset test on $first and $last is not necessary as you set them right before. You know they are going to be set.

As you can see, these are pretty anal optimizations. The only other thing I can think of is that function calls cost, however, combining the first two functions may be a little messy, if speed is of the essence then this would have to be the way. In fact, if speed is of the essence then I would say do away with all your functions and make it completely procedural, after all, this is generated code, not intended to be read by anyone so readability need not be an issue.

mrhappiness
03-17-2005, 03:17 AM
First of all: ThanksOriginally posted by bubblenut
In both of the first two functions you have these two lines in the for each.

$position = isset($position) ? ++$position : 1;
$count = isset($count) ? $count : count($content);
moved it above the foreach, $first is initialised to true before entering the loop as well

Also, the isset test on $first and $last is not necessary as you set them right before. You know they are going to be set.No
everthing i return which is not in $data is a special var.
{_first} will be compiled into $first and the line if (!isset($first)) $first = NULL; is prepended in the function just before filling the $result var starts.
Thing is: within if-clauses i can't detect those vars properley (don't know where to write the initialisation stuff) and so my if converts every var to(isset($name_of_var) ? $name_of_var : NULL)

In fact, if speed is of the essence then I would say do away with all your functions and make it completely procedural, after all, this is generated code, not intended to be read by anyone so readability need not be an issue. I tested it and compared it with smarty which in fact does it procedural and i'm somewhat faster
And i'm able to do recursive calls with simply calling the function once again which is quite difficult if there are no functions
Another thing is that by using functions for all (including the main part of the template) i don't need to use output buffering for fetching the result

Have a look at http://www.howtodo.de/showcase/smarty_ext_compare/ and see what I mean

Any other optimization tips?

And for some explanation:
ExT2 means Extensible Template 2
You have commands, vars and modifiers.

Those 3 things are all stored in subfodlers of "extensions"-folder.
A command is used for my loop and my if for example (command.loop.php, command.if.php)

Vars contain compilation routines for special vars like {_first} and {_last} or {_unique}
(var.unique.php would for example return md5(mt_rand(1, 50).microtime()) so you can easyly stop pics from being cached by writingimg src="<some_dynamic_generated_pic_with_static_name.php"?{_unique}">

Modifiers modify the way how vars will be output.
{headline capitalize, escape} for example will capitalize all words in $date['headline'] and run htmlspecialchars on it afterwards
{_now dateformat "d.m.Y"} will take the current time (_now returns time()) and format it accoding to the string specified.

bubblenut
03-17-2005, 03:29 PM
Oh my god, I'd never really bothered looking at Smarties generated code as I've built a custom template engine. I just noticed that they use the :puke: alternative control structure syntax. That's disgusting.
With regards to yours running quicker, I'm not surprised to be honest as Smarty is much bigger and more flexible. Custom built template engines are almost always (if built by someone capable) quicker than generic versions. All I am saying is that function calls cost, prehapse not a huge amount in the grander scheme of things but you could speed up your code a little by reducing them, especially the one in the for loop.
You are absolutely right though, the flexibility you would loose by doing this would almost certainly be more damaging than any gain in speed would be beneficial.

mrhappiness
03-18-2005, 10:56 AM
Originally posted by bubblenut
I've built a custom template engineseems to come into vogue, eh? ;)I've built a custom template engineI just noticed that they use the :puke: alternative control structure syntax. That's disgusting.ack
All I am saying is that function calls cost, prehapse not a huge amount in the grander scheme of things but you could speed up your code a little by reducing them, especially the one in the for loop.ack

You are absolutely right though, the flexibility you would loose by doing this would almost certainly be more damaging than any gain in speed would be beneficial. ack :)

i think, i'll start believing in my template engine being almost finished. i really needed recursion and that was the easiest way to implement it, with combining nested loop blocks into one single function call this would be much more difficult

[offtpoic]
just wondering if i import template vars from outside the functions into the function by using array_merge... would be funny to enable recursion but don't have endless recursion
[/offtopic]

anyway, thanks for your replies

btw: smarty is bigger but not more flexible... :D
(but that's just my own not very objective opinion ;))

bubblenut
03-22-2005, 10:49 AM
Ah that's supposed to be "as I've never built a custom template engine", I've always just relied on code seperation.

As an aside, have you ever looked into PEAR's Flexy?