I updated Brilliand's test code to make it's report more understandable and also statitistically truthfully by adding more randomness. Since I changed some of its tests to make them more fair the results will be different, therefore I write it as different answer.
My tests executed by: PHP 7.4.4 (cli) (built: Mar 20 2020 13:47:45) ( NTS )
<?php
function shuffle_assoc($array) {
$keys = array_keys($array);
shuffle($keys);
return array_merge(array_flip($keys), $array);
}
$c_e = new Exception('n');
function do_nothing($a, $b) {
return $a + $b;
}
function new_exception_but_not_throw($a, $b) {
try {
new Exception('k');
} catch (Exception $e) {
return $a + $b;
}
return $a + $b;
}
function new_exception_and_throw($a, $b) {
try {
throw new Exception('k');
} catch (Exception $e) {
return $a + $b;
}
return $a + $b;
}
function constant_exception_and_throw($a, $b) {
global $c_e;
try {
throw $c_e;
} catch (Exception $e) {
return $a + $b;
}
return $a + $b;
}
$tests = array(
'do_nothing with no surrounding try'=>function() {
do_nothing(5, 7);
},
'do_nothing with surrounding try'=>function() {
try {
do_nothing(5, 7);
} catch (Exception $e) {}
},
'new_exception_but_not_throw with no surrounding try'=>function() {
new_exception_but_not_throw(5, 7);
},
'new_exception_but_not_throw with surrounding try'=>function() {
try {
new_exception_but_not_throw(5, 7);
} catch (Exception $e) {}
},
'new_exception_and_throw with no surrounding try'=>function() {
new_exception_and_throw(5, 7);
},
'new_exception_and_throw with surrounding try'=>function() {
try {
new_exception_and_throw(5, 7);
} catch (Exception $e) {}
},
'constant_exception_and_throw with no surrounding try'=>function() {
constant_exception_and_throw(5, 7);
},
'constant_exception_and_throw with surrounding try'=>function() {
try {
constant_exception_and_throw(5, 7);
} catch (Exception $e) {}
},
);
$results = array_fill_keys(array_keys($tests), 0);
$testCount = 30;
const LINE_SEPARATOR = PHP_EOL; //"<br>";
for ($x = 0; $x < $testCount; ++$x) {
if (($testCount-$x) % 5 === 0) {
echo "$x test cycles done so far".LINE_SEPARATOR;
}
$tests = shuffle_assoc($tests);
foreach ($tests as $k => $f) {
$start = microtime(true);
for ($i = 0; $i < 1000000; ++$i) {
$f();
}
$results[$k] += microtime(true) - $start;
}
}
echo LINE_SEPARATOR;
foreach ($results as $type => $result) {
echo $type.' = '.number_format($result/$testCount, 4).LINE_SEPARATOR;
}
The results are following:
do_nothing with no surrounding try = 0.1873
do_nothing with surrounding try = 0.1990
new_exception_but_not_throw with no surrounding try = 1.1046
new_exception_but_not_throw with surrounding try = 1.1079
new_exception_and_throw with no surrounding try = 1.2114
new_exception_and_throw with surrounding try = 1.2208
constant_exception_and_throw with no surrounding try = 0.3214
constant_exception_and_throw with surrounding try = 0.3312
Conclusions are:
- adding extra try-catch adds ~0.01 microsecond per 1000000 iterations
- exception throwing and catching adds ~0.12 microsecond (x12 compared to previous when nothing were thrown and nothing were catched)
- exception creation adds ~0.91 microsecond (x7.6 compared to execution of try-catch mechanism calculated in previous line)
So the most expensive part is exception creation - not the throw-catch mechanism, however latter made this simple routine 2 times slower compared to do_nothing scenarion.
* all measurements in conclusions are rounded and are not pretends to be scientifically accurate.