Alrighty I broke down and did some performance comparisons using the attached script which mimics the operation of my application's main loop for 10,000 iterations assuming 100 clients are consistently connected. Here are all the key getting methods:
function method1_get_key($arr) {
$key = 0;
while(array_key_exists($key, $arr)) {
$key++;
if (defined('PHP_INT_MAX') && ($key > PHP_INT_MAX)) {
throw new Exception('Function get_lowest_available_key failed. Key value exceeded PHP_INT_MAX (' . PHP_INT_MAX . ')');
return FALSE;
}
if (!is_int($key)) {
throw new Exception('Function get_lowest_available_key failed. Key value is not an integer');
return FALSE;
}
if ($key < 0) {
throw new Exception('Function get_lowest_available_key failed. Key value is negative');
return FALSE;
}
}
return $key;
}
function method2_get_key($arr) {
$key = 0;
while(isset($arr[$key])) {
$key++;
if (defined('PHP_INT_MAX') && ($key > PHP_INT_MAX)) {
throw new Exception('Function get_lowest_available_key failed. Key value exceeded PHP_INT_MAX (' . PHP_INT_MAX . ')');
return FALSE;
}
if (!is_int($key)) {
throw new Exception('Function get_lowest_available_key failed. Key value is not an integer');
return FALSE;
}
if ($key < 0) {
throw new Exception('Function get_lowest_available_key failed. Key value is negative');
return FALSE;
}
}
return $key;
}
function method3_get_key($arr) {
if (count($arr) == 0) return 0;
$range = range(0,max(array_keys($arr)));
if(count($range) != count($arr))
$hole = min(array_diff($range, array_keys($arr)));
else
$hole = count($arr);
if($hole <0) trigger_error('Array full! Bork bork bork!', E_USER_ERROR);
return $hole;
}
function method4_get_key($arr) {
// this is kind of cheating because we cannot guarantee uniqueness
// interestingly, it's not the fastest
return uniqid();
}
function method5_get_key($arr) {
// this is also kind of cheating because we cannot guarantee uniqueness
return rand();
}
function method6_get_key($arr) {
do {
$k = uniqid();
} while(isset($arr[$k]));
return $k;
}
function method7_get_key($arr) {
do {
$k = rand();
} while(isset($arr[$k]));
return $k;
}
function method8_get_key($arr) {
do {
$k = md5(rand());
} while(isset($arr[$k]));
return $k;
}
function method9_get_key($arr) {
do {
$k = uniqid(rand(), true);
} while(isset($arr[$k]));
return $k;
}
function method10_get_key($arr) {
do {
$k = md5(uniqid(rand(), true));
} while(isset($arr[$k]));
return $k;
}
function method11_get_key($arr) {
$keys = array_keys($arr);
do {
$k = uniqid();
} while(in_array($k, $keys));
return $k;
}
// microtime approach similar to what weedpacket
// suggested, only without nested arrays
function method12_get_key($arr) {
$keys = array_keys($arr);
do {
$mt = microtime();
$karr = explode(' ', $mt);
$k = intval(100000000 * $karr[0]);
} while (in_array($k, $keys));
return $k;
}
Of the methods that guarantee a new key rather than just returning a supposedly unique number, the grand champeen is method #7. method #8 is almost identical in performance should you want a different format of key.
As you guys said, isset is indeed faster. I made a half-assed effort to find a distinction between isset and in_array but there didn't seem to be much of one. Maybe I check that next if I'm feeling motivated.
Here's an APD table of the output if I exclude the slow ones:
My-Mac:apd sneakyimp$ ./pprofp -iR pprof.71840.0
Trace for /Users/sneakyimp/Desktop/test.php
Total Elapsed Time = 408.83
Total System Time = 67.66
Total User Time = 329.39
Real User System secs/ cumm
%Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name
--------------------------------------------------------------------------------------
100.0 389.90 408.83 315.00 329.39 64.74 67.66 1 389.9010 408.8264 0 main
1.0 3.89 3.89 3.23 3.23 0.52 0.52 100200 0.0000 0.0000 0 method10_get_key
0.7 2.89 2.89 2.46 2.46 0.40 0.40 100200 0.0000 0.0000 0 method9_get_key
0.7 2.87 2.87 1.76 1.76 0.54 0.54 100200 0.0000 0.0000 0 method6_get_key
0.7 2.83 2.83 2.32 2.32 0.39 0.39 100200 0.0000 0.0000 0 method8_get_key
0.7 2.80 2.80 1.66 1.66 0.54 0.54 100200 0.0000 0.0000 0 method4_get_key
0.5 1.85 1.85 1.49 1.49 0.27 0.27 100200 0.0000 0.0000 0 method7_get_key
0.4 1.80 1.80 1.46 1.46 0.27 0.27 100200 0.0000 0.0000 0 method5_get_key
0.0 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0014 0.0014 0 apd_set_pprof_trace
The script and some performance graphs are attached.