Partials are evil
Maybe not that evil but they take their toll on your loading time. The worst is when using them inside a loop as the price increases linearly. Use helpers whenever possible but make sure you load only the necessary helpers on each call and don't try to re-load helpers when inside a loop.
Re-use function results
Symfony encourages you to use methods and functions repeatedly, for example
sfContext::getInstance()->getModuleName();
. Obviously, the more calculations, the longer things take so whenever you need to re-use results, save the variable content.A good PHP structure for re-using results is:
function foo_calculate() {
static $result = null;
if (is_null($result)) {
# perform calculations
$result = calculation results...
}
return $result;
}
Escaping PHP and going back to PHP takes its toll
Using
?>xxx
is more costly than
echo 'xxx';
See code on the next paragraph.
Using many echo calls slows things down
It's better to accumulate output in a variable and call a single echo.
The following code performs simple tests so you can get a feeling of the differences in execution times. Run it a few times (when all other applications are closed) since results alter a bit every time.
public function executeCompareOutput(sfWebRequest $request) {
$times = 100000;
echo 'Looping for '.$times.' times - results in msec';
echo '<-div style="display:none">';
$start = microtime(true);
for ($x = 0; $x++ < $times;) {
echo ' '.$x;
}
echo '<-/div><-br/>'.round(1000 * (microtime(true) - $start));
$start = microtime(true);
echo '<-div style="display:none">';
for ($x = 0; $x++ < $times;) {
?> echo $x;
}
echo '-div><-br/>'.round(1000 * (microtime(true) - $start));
$start = microtime(true);
echo '<-div style="display:none">';
$sBuf = '';
for ($x = 0; $x++ < $times;) {
$sBuf .= ' '.$x;
}
echo $sBuf;
echo '-div><-br/>'.round(1000 * (microtime(true) - $start));
$start = microtime(true);
echo '<-div style="display:none">';
$sBuf = '';
for ($x = 0; $x++ < $times;) {
$sBuf .= ' ';
$sBuf .= $x;
}
echo $sBuf;
echo '-div><-br/>'.round(1000 * (microtime(true) - $start));
$start = microtime(true);
echo '<-div style="display:none">';
$GLOBALS['bufbuf'] = '';
for ($x = 0; $x++ < $times;) {
$GLOBALS['bufbuf'] .= ' '.$x;
}
echo $sBuf;
echo '-div><-br/>'.round(1000 * (microtime(true) - $start));
die('<-br/>bye');
}
Here is a sample output:
Looping for 10000 times - results in msec
3044
5503
10
15
16
bye
On this run using multiple echo calls + PHP escaping took 55 TIMES MORE than buffering the output in a variable. This clearly proves that the style suggested by Symfony templates, using many PHP echo blocks, is HIGHLY inefficient. If you have a few dozens of it in your templates and your content is cached, this is negligible. If your content is very dynamic, as is the case with Colnect, we're talking about something very worth noting.
To me it seems a bit like micromanaging your code. Perhaps you should use arrays instead of string concatenation as that is less efficient than imploding an array;-)
ReplyDeleteThough it may seem tedious, being able to decrease a page loading time from ~26 seconds to ~5 seconds was very much worth it.
ReplyDeleteWith my sample implode gave much slower results (takes ~35% longer) though I suppose the results may be different with longer strings which will require more memory allocations.