Friday June 13, 2008
I referenced Reinhold Weber’s optimization tricks for PHP a few days ago, and found that his claim that you would see a 4x speedup if you put the keyword static in front of a class method that was to be called statically. In reality, you get an improvement of about 60 percent.
Another one of his tips is that
Error suppression with @ is very slow.
This is misleading. It is not the @-suppression (the @ operator is called the error control operator in the PHP manual) that is very slow, it is the generation of the error in itself. I have been doing some work with Memcache for prove.no, and a typical recurring pattern of code looks like this:
$oCachedValue = @$oMemcache->get($sKey);
if ($oCachedValue === false)
{
// regenerate data (e.g. get from MySQL)
// remember to set $oCachedValue
}
// do stuff with $oCachedValue
If the Memcache daemon is not running, you will get warnings when calling $oMemcache->Get. Now, on our production server we do not display warnings to the end user, so no problem there. However, when programming, most warnings are useful, but not these. So to avoid setting error_reporting to E_ERROR, the @-suppression approach was chosen.
Now, mr. Weber’s assertion that it is the act of the @ operator that is very slow, is wrong. It is in fact the actual triggering of the error or warning by itself. I ran a quick test using the Timer class from the other day. The test measures all combinations of the following:
error_reporting set to E_ALL and E_ERROR (so that warnings will be generated, but ignored)@-suppression versus no @-suppressionThe method warning() works like this:
function warning($fWarning)
{
2 + 2;
if ($fWarning)
trigger_error('Ostekake', E_USER_WARNING);
}

The graph clearly shows that @-suppression is a little bit slower than not using @-suppression when no error is triggered. However, when triggering a warning, even though it is stopped by error_reporting() settings, takes a lot of time. The @-suppression only adds a tiny amount of overhead to that value.
However, using @-suppression can be dangerous. If you suppress a fatal error, the script will terminate with no indication as to why it terminated. The fact that there is some speed penalty also means that you should try to avoid it in tight loops.
My test was run on PHP 5.2.4 on Ubuntu. For reference, the entire code:
<?php require_once('Timer.php'); define('ITERATIONS', 100000); $t = new Timer(false, true); if ($_GET['clear']) $t->clearStatistics();function warning($fWarning) { 2 + 2; if ($fWarning) trigger_error('Ostekake', E_USER_WARNING); }error_reporting(E_ALL);$t->startClock(); for ($i = 0; $i < ITERATIONS; $i++) { warning(false); } $t->mark('Call without warning');for ($i = 0; $i < ITERATIONS; $i++) { @warning(false); } $t->mark('Call without warning (suppressed)');for ($i = 0; $i < ITERATIONS; $i++) { @warning(true); } $t->mark('Call with warning (suppressed)');error_reporting(E_ERROR);for ($i = 0; $i < ITERATIONS; $i++) { warning(false); } $t->mark('Call without warning');for ($i = 0; $i < ITERATIONS; $i++) { @warning(false); } $t->mark('Call without warning (suppressed)');for ($i = 0; $i < ITERATIONS; $i++) { warning(true); } $t->mark('Call with warning');for ($i = 0; $i < ITERATIONS; $i++) { @warning(true); } $t->mark('Call with warning (suppressed)'); $t->stopClock(true); ?>
Comments