Last active
August 29, 2015 14:03
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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