Last active
August 29, 2015 14:04
Bench various ways of natively looping over PHP arrays
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 | |
# Simple PHP 5.4+ bench script for CLI. | |
const ITERATIONS = 1000; | |
const ARRAY_SIZE = 1000; | |
define('CONDITION', 'item' . (ARRAY_SIZE - 1)); | |
error_reporting(E_ALL | E_STRICT); | |
setlocale(LC_ALL, 'C'); | |
register_shutdown_function(function () { | |
echo PHP_EOL; | |
$memory_peak_end = memory_get_peak_usage(); | |
echo 'Peak memory after test: ', format_kb($memory_peak_end), PHP_EOL; | |
echo 'Memory difference: ', format_kb($memory_peak_end, MEMORY_PEAK_START), PHP_EOL; | |
}); | |
function format_kb($size, $diff_base_size = NULL) { | |
$out = ''; | |
if (isset($diff_base_size)) { | |
$out = ($size = $size - $diff_base_size) > 0 ? '+' : ''; | |
} | |
$out .= number_format($size / 1024) . ' KB'; | |
return $out; | |
} | |
function no_op($text) { | |
return $text; | |
} | |
/** | |
* Initialization. | |
*/ | |
define('MEMORY_PEAK_START', memory_get_peak_usage()); | |
echo 'Peak memory before test: ', format_kb(MEMORY_PEAK_START), PHP_EOL; | |
echo 'Iterations: ', ITERATIONS, PHP_EOL; | |
echo 'Array size: ', ARRAY_SIZE, PHP_EOL, PHP_EOL; | |
function create_giant_array() { | |
$array = array(); | |
for ($i = 0; $i <= ARRAY_SIZE; $i++) { | |
$array[] = 'item' . $i; | |
} | |
return $array; | |
} | |
function create_giant_linkedlist() { | |
$array = new SplDoublyLinkedList(); | |
for ($i = 0; $i <= ARRAY_SIZE; $i++) { | |
$array[] = 'item' . $i; | |
} | |
return $array; | |
} | |
/** | |
* Test cases. | |
*/ | |
$tests['nothing'] = function () { | |
}; | |
$tests['no_op'] = function () { | |
$text = no_op('some string'); | |
}; | |
$tests['foreach'] = function () { | |
$array = create_giant_array(); | |
foreach ($array as $key => $value) { | |
if ($value === CONDITION) { | |
$return = $value; | |
} | |
} | |
return $return; | |
}; | |
$tests['for'] = function () { | |
$array = create_giant_array(); | |
for ($i = 0; $i < count($array); $i++) { | |
if ($array[$i] === CONDITION) { | |
$return = $array[$i]; | |
} | |
} | |
return $return; | |
}; | |
$tests['for $ii'] = function () { | |
$array = create_giant_array(); | |
for ($i = 0, $ii = count($array); $i < $ii; $i++) { | |
if ($array[$i] === CONDITION) { | |
$return = $array[$i]; | |
} | |
} | |
return $return; | |
}; | |
$tests['SplDoublyLinkedList'] = function () { | |
$array = create_giant_linkedlist(); | |
foreach ($array as $key => $value) { | |
if ($value === CONDITION) { | |
$return = $value; | |
} | |
} | |
return $return; | |
}; | |
$tests['while'] = function () { | |
$array = create_giant_array(); | |
while (FALSE !== $value = current($array)) { | |
$key = key($array); | |
if ($value === CONDITION) { | |
$return = $value; | |
} | |
next($array); | |
} | |
return $return; | |
}; | |
#### REVERSE TESTS | |
$tests['Reverse: foreach'] = function () { | |
$array = array_reverse(create_giant_array(), true); | |
foreach ($array as $key => $value) { | |
if ($value === CONDITION) { | |
$return = $value; | |
} | |
} | |
return $return; | |
}; | |
$tests['Reverse: for'] = function () { | |
$array = create_giant_array(); | |
for ($i = count($array) - 1; $i >= 0; $i--) { | |
if ($array[$i] === CONDITION) { | |
$return = $array[$i]; | |
} | |
} | |
return $return; | |
}; | |
$tests['Reverse: for $ii'] = function () { | |
return "n/a (same as: Reverse: for)"; | |
}; | |
$tests['Reverse: SplDoublyLinkedList'] = function () { | |
$array = create_giant_linkedlist(); | |
$array->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO); | |
foreach ($array as $key => $value) { | |
if ($value === CONDITION) { | |
$return = $value; | |
} | |
} | |
return $return; | |
}; | |
$tests['Reverse: while'] = function () { | |
$array = create_giant_array(); | |
end($array); | |
while (FALSE !== $value = current($array)) { | |
$key = key($array); | |
if ($value === CONDITION) { | |
$return = $value; | |
} | |
prev($array); | |
} | |
return $return; | |
}; | |
/** | |
* Test runner. | |
*/ | |
$results = array(); | |
foreach ($tests as $name => $test) { | |
$start = microtime(true); | |
for ($i = 0; $i < ITERATIONS; ++$i) { | |
$results[$name] = $test(); | |
} | |
$stop = microtime(true); | |
printf("%-30.30s %2.3f seconds -- %s\n", $name . ':', $stop - $start, var_export($results[$name], TRUE)); | |
} |
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 bench.loop.php | |
Peak memory before test: 162 KB | |
Iterations: 1000 | |
Array size: 1000 | |
nothing: 0.013 seconds -- NULL | |
no_op: 0.015 seconds -- NULL | |
foreach: 0.928 seconds -- 'item999' | |
for: 4.970 seconds -- 'item999' | |
for $ii: 0.986 seconds -- 'item999' | |
SplDoublyLinkedList: 1.351 seconds -- 'item999' | |
while: 12.709 seconds -- 'item999' | |
Reverse: foreach: 1.006 seconds -- 'item999' | |
Reverse: for: 0.985 seconds -- 'item999' | |
Reverse: for $ii: 0.011 seconds -- 'n/a (same as: Reverse: for)' | |
Reverse: SplDoublyLinkedList: 1.384 seconds -- 'item999' | |
Reverse: while: 12.782 seconds -- 'item999' | |
Peak memory after test: 339 KB | |
Memory difference: +177 KB |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment