-
-
Save klaernie/6dd1acba42afb347f9a02cdcd18a7c99 to your computer and use it in GitHub Desktop.
Benchmarking execution time of PHP constructs (list / each, foreach) vs (array_walk, array_map, array_reduce, array_filter)
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
<?php | |
/** | |
* Execution time check for: (list/each,foreach) vs (array_walk, array_map, array_reduce, array_filter) | |
* @docs to read | |
* http://www.giorgiosironi.com/2010/02/stop-writing-foreach-cycles.html | |
* http://www.pastie.org/829318 | |
* http://php.net/manual/en/function.array-walk.php#112722 | |
* http://zaemis.blogspot.com/2013/06/building-array-with-arrayreduce.html | |
* (!) http://stackoverflow.com/questions/2473989/list-of-big-o-for-php-functions/2484455#2484455 | |
* http://www.faieta.net/wp/performance-implications-of-closures-in-php/ | |
* https://alexatnet.com/articles/php-micro-optimization-tips | |
*/ | |
version_compare(phpversion(), '5.4.0', '>=') ?: die('5.4.0+ required.'); | |
define('EOL', php_sapi_name() === 'cli' ? PHP_EOL : '<br>'); | |
echo EOL, '1. Walk array and change values', EOL; | |
$walkArray1 = test_walk('array_walk'); | |
$walkArray2 = test_walk('array_walk_list_each'); | |
$walkArray3 = test_walk('array_walk_foreach'); | |
$walkArray4 = test_walk('array_walk_foreach_by_value'); | |
echo EOL, 'equality check', EOL; | |
var_dump( | |
$walkArray1 === $walkArray2, | |
$walkArray1 === $walkArray3, | |
$walkArray1 === $walkArray4 | |
); | |
echo EOL, '2. Walk array and do multiplication of elements', EOL; | |
$mapArray1 = test_map('array_map'); | |
$mapArray2 = test_map('array_map_list_each'); | |
$mapArray3 = test_map('array_map_list_each_by_value'); | |
$mapArray4 = test_map('array_map_foreach'); | |
$mapArray5 = test_map('array_map_foreach_by_value'); | |
echo EOL, 'equality check', EOL; | |
var_dump( | |
$mapArray1 === $mapArray2, | |
$mapArray1 === $mapArray3, | |
$mapArray1 === $mapArray4, | |
$mapArray1 === $mapArray5 | |
); | |
echo EOL, '3. Walk array and sum the elements', EOL; | |
$reduceArray1 = test_reduce('array_reduce'); | |
$reduceArray2 = test_reduce('array_reduce_list_each'); | |
$reduceArray3 = test_reduce('array_reduce_foreach'); | |
echo EOL, 'equality check', EOL; | |
var_dump( | |
$reduceArray1 === $reduceArray2, | |
$reduceArray1 === $reduceArray3 | |
); | |
echo EOL, '4. Walk array and filter even elements', EOL; | |
$filterArray1 = test_filter('array_filter'); | |
$filterArray2 = test_filter('array_filter_list_each'); | |
$filterArray3 = test_filter('array_filter_foreach'); | |
echo EOL, 'equality check', EOL; | |
var_dump( | |
$filterArray1 === $filterArray2, | |
$filterArray1 === $filterArray3 | |
); | |
/* ------------------------------- FUNCTIONS ------------------------------ */ | |
/* Walk array and change values | |
* array_walk(array &$array, callable $function, mixed $userData = null): bool | |
* $function ($value, $key) | |
*/ | |
/** | |
* Test list/each by array[key] | |
* | |
* @param $array | |
* @param $function | |
* @param null $userData | |
*/ | |
function array_walk_list_each(& $array, $function, $userData = null) | |
{ | |
while (list($key, $value) = each($array)) { | |
$function($array[$key], $key, $userData); | |
} | |
} | |
/** | |
* Test foreach by array[key] | |
* | |
* @param $array | |
* @param $function | |
* @param null $userData | |
*/ | |
function array_walk_foreach(& $array, $function, $userData = null) | |
{ | |
foreach ($array as $key => $value) { | |
$function($array[$key], $key, $userData); | |
} | |
} | |
/** | |
* Test foreach by value | |
* | |
* @param $array | |
* @param $function | |
* @param null $userData | |
*/ | |
function array_walk_foreach_by_value(& $array, $function, $userData = null) | |
{ | |
foreach ($array as $key => & $value) { | |
$function($value, $key, $userData); | |
} | |
} | |
/** | |
* Change value in array passed by reference | |
* | |
* @param $value | |
* @param $key | |
* @param $userData | |
*/ | |
function change_values(& $value, $key, $userData) | |
{ | |
$value = "$key => $userData"; | |
} | |
/** | |
* Walk array and change values using: list / each, foreach, array_walk() | |
* | |
* @param $function | |
* @param int $count | |
* @param int $arrayElements | |
* @return array | |
*/ | |
function test_walk($function, $count = 10000, $arrayElements = 100) | |
{ | |
$value = 'text value'; | |
$array = array_fill(0, $arrayElements, $value); | |
echo $function, ' ... '; | |
$timer = microtime(true); | |
for ($i = 0; ++$i < $count;) { | |
$function($array, 'change_values', 'user data'); | |
} | |
printf('%.4f sec' . EOL, microtime(true) - $timer); | |
return $array; | |
} | |
/* Walk array and do some math | |
* array_map(callable $function, array $array [,array $array1, ... ]): array | |
* $function ($value) | |
*/ | |
/** | |
* Test each/list by array[key] | |
* | |
* @param $function | |
* @param $array | |
* @return array | |
*/ | |
function array_map_list_each($function, $array) | |
{ | |
$squared = []; | |
while (list($key) = each($array)) { | |
$squared[$key] = $function($array[$key]); | |
} | |
return $squared; | |
} | |
/** | |
* Test each/list by value | |
* | |
* @param $function | |
* @param $array | |
* @return array | |
*/ | |
function array_map_list_each_by_value($function, $array) | |
{ | |
$squared = []; | |
while (list($key, $value) = each($array)) { | |
$squared[$key] = $function($value); | |
} | |
return $squared; | |
} | |
/** | |
* Test foreach by array[key] | |
* | |
* @param $function | |
* @param $array | |
* @return array | |
*/ | |
function array_map_foreach($function, $array) | |
{ | |
$squared = []; | |
foreach ($array as $key => $value) { | |
$squared[$key] = $function($array[$key]); | |
} | |
return $squared; | |
} | |
/** | |
* Test foreach by value | |
* | |
* @param $function | |
* @param $array | |
* @return array | |
*/ | |
function array_map_foreach_by_value($function, $array) | |
{ | |
$squared = []; | |
foreach ($array as $key => $value) { | |
$squared[$key] = $function($value); | |
} | |
return $squared; | |
} | |
/** | |
* Get array value multiplication | |
* | |
* @param $value | |
* @return integer | |
*/ | |
function multi_values($value) | |
{ | |
return $value * $value; | |
} | |
/** | |
* Walk array and do some math using: list/ each, foreach, array_map(), array_reduce() | |
* | |
* @param $function | |
* @param int $count | |
* @param int $arrayElements | |
* @return array | |
*/ | |
function test_map($function, $count = 10000, $arrayElements = 100) | |
{ | |
$digest = []; | |
$value = 4; | |
$testArray = array_fill(0, $arrayElements, $value); | |
echo $function, ' ... '; | |
$timer = microtime(true); | |
for ($i = 0; ++$i < $count;) { | |
$digest[] = $function('multi_values', $testArray); | |
} | |
printf('%.4f sec' . EOL, microtime(true) - $timer); | |
return $digest; | |
} | |
/* Walk array and do some math | |
* array_reduce(array $array, callable $function, mixed $result = null) mixed | |
* $function ($result, $item) | |
*/ | |
/** | |
* Test foreach | |
* | |
* @param array $array | |
* @param $function | |
* @param null $init | |
* @return null | |
*/ | |
function array_reduce_foreach(array $array, $function, $init = null) | |
{ | |
$acc = $init; | |
foreach ($array as $item) { | |
$acc = $function($acc, $item); | |
} | |
return $acc; | |
} | |
/** | |
* Test list/each | |
* | |
* @param array $array | |
* @param $function | |
* @param null $init | |
* @return null | |
*/ | |
function array_reduce_list_each(array $array, $function, $init = null) | |
{ | |
$acc = $init; | |
while (list(, $value) = each($array)) { | |
$acc = $function($acc, $value); | |
} | |
return $acc; | |
} | |
/** | |
* Get array values sum | |
* | |
* @param $carry | |
* @param $item | |
* @return mixed | |
*/ | |
function sum_values($carry, $item) | |
{ | |
$carry += $item; | |
return $carry; | |
} | |
/** | |
* Iteratively reduce array using: list / each, foreach, array_reduce() | |
* | |
* @param $function | |
* @param int $count | |
* @param int $arrayElements | |
* @return array | |
*/ | |
function test_reduce($function, $count = 10000, $arrayElements = 100) | |
{ | |
$digest = []; | |
$value = 13; | |
$testArray = array_fill(0, $arrayElements, $value); | |
echo $function, ' ... '; | |
$timer = microtime(true); | |
for ($i = 0; ++$i < $count;) { | |
$digest[] = $function($testArray, 'sum_values'); | |
} | |
printf('%.4f sec' . EOL, microtime(true) - $timer); | |
return $digest; | |
} | |
/* Filters elements of an array with callback | |
* array_filter(array $array, callable $function = null, $flag = 0) array | |
* $function ($value); for php 5.6 $function ($value [,$key), if $flag = ARRAY_FILTER_USE_BOTH | |
*/ | |
/** | |
* Test list/each | |
* | |
* @param $array | |
* @param $function | |
* @return array | |
*/ | |
function array_filter_list_each($array, $function) | |
{ | |
$digest = []; | |
while (list($key, $value) = each($array)) { | |
if ($function($value)) { | |
$digest[$key] = $value; | |
} | |
} | |
return $digest; | |
} | |
/** | |
* Test foreach | |
* | |
* @param $array | |
* @param $function | |
* @return array | |
*/ | |
function array_filter_foreach($array, $function) | |
{ | |
$digest = []; | |
foreach ($array as $key => $value) { | |
if ($function($value)) { | |
$digest[$key] = $value; | |
} | |
} | |
return $digest; | |
} | |
/** | |
* Returns whether the input integer is odd | |
* | |
* @param $value | |
* @return int | |
*/ | |
function filter_values($value) | |
{ | |
return ($value & 1); | |
} | |
/** | |
* Filter array values using: list / each, foreach, array_filter() | |
* | |
* @param $function | |
* @param int $count | |
* @param int $arrayElements | |
* @return array | |
*/ | |
function test_filter($function, $count = 10000, $arrayElements = 100) | |
{ | |
$digest = []; | |
$testArray = range(1, $arrayElements); | |
echo $function, ' ... '; | |
$timer = microtime(true); | |
for ($i = 0; ++$i < $count;) { | |
$digest[] = $function($testArray, 'filter_values'); | |
} | |
printf('%.4f sec' . EOL, microtime(true) - $timer); | |
return $digest; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment