Skip to content

Instantly share code, notes, and snippets.

@hmic
Last active August 29, 2015 14:03
Show Gist options
  • Save hmic/3fdc9b1893f8037189f2 to your computer and use it in GitHub Desktop.
Save hmic/3fdc9b1893f8037189f2 to your computer and use it in GitHub Desktop.
A-B Test (call it benchmark) to show that php evaluates operands from left to right and does not at all evaluate operands, if the condition cannot be met anymore
define('ITERATIONS', 1000000);
define('ROUNDS', 10);
function original($singular, $args = null) {
if ($args === null) {
return true;
} else {
return false;
}
}
function modified($singular, $args = null) {
if ($args === null && func_num_args() < 2) { // this is the proposed solution. it adds (almost absolutely) no time to the check if $args === null
// if ($args === null && call_user_func(function($a) { for($i = 0; $i < $a; $i++); }, 128)) { // this is just to proof that this never happens if $args === null
return true;
} else {
return false;
}
}
function modified2($singular, $args = null) {
if (func_num_args() < 2) { // this is sufficient because of inconsistent php behaviour, AGAIN! see test below... it is (relatively) slow in every case though
return true;
} else {
return false;
}
}
$tests = array(
'original_times' => array(
'function' => 'original',
'params' => array('Test'),
'text' => 'Original ($args not set) ',
),
'original_null_times' => array(
'function' => 'original',
'params' => array('Test', null),
'text' => 'Original ($args === null)',
),
'original_not_null_times' => array(
'function' => 'original',
'params' => array('Test', false),
'text' => 'Original ($args !== null)',
),
'modified_times' => array(
'function' => 'modified',
'params' => array('Test'),
'text' => 'Modified ($args not set) ',
),
'modified_null_times' => array(
'function' => 'modified',
'params' => array('Test', null),
'text' => 'Modified ($args === null)',
),
'modified_not_null_times' => array(
'function' => 'modified',
'params' => array('Test', false),
'text' => 'Modified ($args !== null)',
),
'modified2_times' => array(
'function' => 'modified2',
'params' => array('Test'),
'text' => 'Modified2 ($args not set) ',
),
'modified2_null_times' => array(
'function' => 'modified2',
'params' => array('Test', null),
'text' => 'Modified2 ($args === null)',
),
'modified2_not_null_times' => array(
'function' => 'modified2',
'params' => array('Test', false),
'text' => 'Modified2 ($args !== null)',
),
);
foreach($tests as $key => $test) {
$$key = array();
}
for($r = ROUNDS; $r > 0; $r--) {
foreach($tests as $key => $test) {
$start_time = microtime(true);
$c = ITERATIONS;
$function = $test['function']; // do not distract the benchmark
$params = $test['params']; // my these array lookups, use local vars instead
while($c--) call_user_func_array($function, $params);
array_push($$key, microtime(true) - $start_time);
}
}
echo sprintf('Times for %s iterations in %s rounds on php-%s:%s', ITERATIONS, ROUNDS, phpversion(), PHP_EOL);
$r = 0;
foreach($tests as $key => $test) {
if($r++ % 3 == 0) echo PHP_EOL;
sort($$key);
// echo sprintf('%s%s%s', $test['text'], implode(', ', $$key), PHP_EOL);
echo sprintf('%s: %ss avg%s', $test['text'], array_sum($$key) / count($$key), PHP_EOL);
}
/* Another php-inconsistency that I came accross when testing this,
* the change reads func_num_args() < 2 instead of the proposed func_num_args() < 3:
* Default arguments are not shown in the func_get_args() and func_num_args() functions!
*/
function args_test($single, $args = null) { var_dump(func_get_args(), func_num_args()); }
echo PHP_EOL;
echo 'args_test("Test"):' . PHP_EOL;
args_test('Test');
echo PHP_EOL;
echo 'args_test("Test", null):' . PHP_EOL;
args_test('Test', null);
/*
RESULTS:
Times for 1000000 iterations in 10 rounds on php-5.5.14:
Original ($args not set) : 0.53223054409027s avg
Original ($args === null): 0.57213246822357s avg
Original ($args !== null): 0.56663253307343s avg
Modified ($args not set) : 0.58333339691162s avg
Modified ($args === null): 0.62863585948944s avg
Modified ($args !== null): 0.57763316631317s avg
Modified2 ($args not set) : 0.56753251552582s avg
Modified2 ($args === null): 0.60613462924957s avg
Modified2 ($args !== null): 0.60433461666107s avg
Times for 1000000 iterations in 10 rounds on php-5.4.30:
Original ($args not set) : 0.57273278236389s avg
Original ($args === null): 0.59973433017731s avg
Original ($args !== null): 0.59833409786224s avg
Modified ($args not set) : 0.63493618965149s avg
Modified ($args === null): 0.65893802642822s avg
Modified ($args !== null): 0.60833466053009s avg
Modified2 ($args not set) : 0.62743582725525s avg
Modified2 ($args === null): 0.65103728771210s avg
Modified2 ($args !== null): 0.65303740501404s avg
Times for 1000000 iterations in 10 rounds on php-5.3.28:
Original ($args not set) : 0.67083833217621s avg
Original ($args === null): 0.70034017562866s avg
Original ($args !== null): 0.70163998603821s avg
Modified ($args not set) : 0.76344385147095s avg
Modified ($args === null): 0.79184517860413s avg
Modified ($args !== null): 0.70774047374725s avg
Modified2 ($args not set) : 0.76374368667603s avg
Modified2 ($args === null): 0.78644495010376s avg
Modified2 ($args !== null): 0.78834505081177s avg
// This are the results for the long taking anonymous function instead of the func_num_args() call,
// to demonstrate that this function does not even execute if $args !== null:
Modified ($args not set) : 1.878107380867s avg // extra slowed down
Modified ($args === null): 1.9067091464996s avg // extra slowed down
Modified ($args !== null): 0.71474087238312s avg // same as above
args_test("Test"):
array(1) {
[0]=>
string(4) "Test"
}
int(1)
args_test("Test", null):
array(2) {
[0]=>
string(4) "Test"
[1]=>
NULL
}
int(2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment