PHP - Benchmark isset() or array_key_exists() ?

The Twitter user caioariede postet that you should array_key_exists() instead of isset(). He did not say why so i tried to check performance first and came to interesting results...

Code

First the benchmark script:

<?php

/**
 * PHP Array key exists
 */

$n = 1000000;

// First a test with a empty array
$array = array();

$time_start = microtime(true);
$i = 0;
while($i < $n){
    $devnull = isset($array[$i++]);
    //var_dump($devnull);
}
$time_end = microtime(true);
$time_while1= $time_end-$time_start;
echo number_format($time_while1, 3, '.', '')
  ." seconds - isset(array[i]) on empty array \n";
 
 
$time_start = microtime(true);
$i = 0;
while($i < $n){
    $devnull = array_key_exists($i++, $array);
    //var_dump($devnull);
}
$time_end = microtime(true);
$time_while1= $time_end-$time_start;
echo number_format($time_while1, 3, '.', '')
  ." seconds - array_key_exists(array,i) on empty array \n";

$time_start = microtime(true);
$i = 0;
while($i < $n){
    $devnull = (bool)@$array[$i++];
    //var_dump($devnull);
}
$time_end = microtime(true);
$time_while1= $time_end-$time_start;
echo number_format($time_while1, 3, '.', '')
  ." seconds - cast array[i] on empty array \n";

// Create test array
$i = 0;
$array = array();
while($i < $n) {
  $array[$i++] = true;
}

$time_start = microtime(true);
$i = 0;
while($i < $n){
    $devnull = isset($array[$i++]);
    //var_dump($devnull);
}
$time_end = microtime(true);
$time_while1= $time_end-$time_start;
echo number_format($time_while1, 3, '.', '')
  ." seconds - isset(array[i]) on full array \n";
 

$time_start = microtime(true);
$i = 0;
while($i < $n){
    $devnull = array_key_exists($i++, $array);
    //var_dump($devnull);
}
$time_end = microtime(true);
$time_while1= $time_end-$time_start;
echo number_format($time_while1, 3, '.', '')
  ." seconds - array_key_exists(array,i) on full array \n";

$time_start = microtime(true);
$i = 0;
while($i < $n){
    $devnull = (bool)@$array[$i++];
    //var_dump($devnull);
}
$time_end = microtime(true);
$time_while1= $time_end-$time_start;
echo number_format($time_while1, 3, '.', '')
  ." seconds - cast array[i] on full array \n";
 

?>

Result

0.285 seconds - isset(array[i]) on empty array
0.819 seconds - array_key_exists(array,i) on empty array
3.194 seconds - cast array[i] on empty array
0.298 seconds - isset(array[i]) on full array
0.815 seconds - array_key_exists(array,i) on full array
1.760 seconds - cast array[i] on full array

Interpretation

I tested 3 ways to check if a array key is used or not. isset($array[$key]) wich returns true if not NULL, array_key_exists($key, $array) which is also boolean and returns true if $key exists in $array. The last way is to fetch the variable in $array at $key and cast it to boolean. If a key is not used, NULL is returned which will cast to false.

I thought array_key_exists() should be much faster than isset() but it is about 60% faster. Why? I do not know for sure, hope some of you knows more.
For some reason the cast is also damn slow. Maybe is is more work to fetch the var instead of just searching for the key.

Conclusion

My conclusion is, use isset() because its faster and easier, i personally always forget if its first $key or $array in array_key_exists. Next to that is isset() less to type :D

Update

caioariede (Twitter) showed me that there IS a difference between isset() and array_key_exists(). Thanks for that hint.

isset() will return true if the variable that is accessible with that array key is not NULL. I you access a array key that is not defined yet will always return NULL.
array_key_exists searches in the key list for the key and returns true if a key was found. This will also work on something like this: "$array['key'] = NULL", isset will return false, array_key_exists will return true.

Now i could guess what is happening inside PHP.
isset() will just access the value of that array key and compare it internally with NULL and return this result. I thinks this could be done very fast and would also fit to my results.
array_key_exists() needs to search the whole list of keys till it finds a fitting one. This will take longer than just accessing the value because array_key_exists has to compare each key of the array with the searched one.
But i still do not really know why the cast is so slow. Maybe accessing the value, returning and casting it is a slower process than the other 2 techniques.

New Conclusion

I think this very small difference is not worth losing ~60% performance gain. The most situation will be done by isset(), the few scenarios where you need exactly this behaviour should be rare but now you know what to use - array_key_exists()

Code 2

Code to prove:

<?php

// Empty array
$array = array();
var_dump(isset($array['key'])); // false
var_dump(array_key_exists('key', $array)); // false

// Key is true
$array['key'] = true;
var_dump(isset($array['key'])); // true
var_dump(array_key_exists('key', $array)); // true

// Key is unset()
unset($array['key']);
var_dump(isset($array['key'])); // false
var_dump(array_key_exists('key', $array)); // false

// Key is NULL
$array['key'] = NULL;
var_dump(isset($array['key'])); // false
var_dump(array_key_exists('key', $array)); // true

?>

Related posts:


 
 
 

3 Kommentare zu “PHP - Benchmark isset() or array_key_exists() ?”

  1. Caio 19. August 2009 um 22:00

    As I posted on Twitter now, the problem is this:

    $ php -r '$foo['bar']=NULL;var_dump(isset($foo['bar']));'

    When value is NULL, isset returns FALSE. But it's set! see?

  2. Julius 19. August 2009 um 22:34

    Thats correct Caio.
    It also explains why array_key_exists is slower than isset.
    But i cant fairly remember a scenairo where i would have needed exactly that behaviour only array_key_exists() has.

    I checked documentation, it is mentioned there http://php.net/array_key_exists need to look closer next time :D

  3. nerkn 4. August 2010 um 09:06

    I use to check if the value is usable. Null I know from the mysql definition reads “a missing unknown value”.

    If I'm concerning the existance of a value I could surely use isset. If I use keys like an array, the importance is the being there, use array_key_exists is the function.

    thanks for benchmarks, I thouht there is huge difference than your results, since one is function, doing many things, and other one is lang construct.

    http://dev.mysql.com/doc/refman/5.0/en/working-with-null.html

Kommentar abgeben:


#