PHP – isset() vs array_key_exists() : a better way to determine array element’s existence

The story

In the CourseYou project, we’re asked to check if an element is set in an array. That is,  we’re asked to determine whether $Arr[‘MyElement’] exists.

So we use the following code as a start.

<?php 
if (isset($Arr['MyElement'])) { 
     ... do my stuff ... 
} ?> 

This code works fine, but, it works fine for most of cases only. In some other cases (and it’s quite often actually), using this code  to check the existence of an array element can be very DANGEROUS.

What’s wrong with isset()?

Perhaps isset() is one of the most frequently used function that do a very frequent task: determine if a variable has been set. It is simple, and more importantly is FAST, is very FAST. However, the returned result of isset() can be misleading sometimes.

According to the PHP’s manual: isset() — Determine if a variable is set AND is not NULL

So the case that the isset() cause you danger is: the element does exist in the array but it is set NULL. i.e. $Arr[‘MyElemenet’] =NULL; In this case, isset() always return FALSE.  Professional programmers should be aware of this.

The right solution: array_key_exists()

The right way to check  if an element exists in an array is to use array_key_exists(). The array_key_exists() will tell if the given key or index has been “created” in the array regardless the value of the element. So to tell if elements ‘MyElement’ exists in the array $Arr, we should use this:

<?php if (array_key_exists('MyElement', $Arr)) { ... do my stuff ... } ?> 

Why array_key_exists() still sucks?

However, array_key_exits() still sucks. Yes, it’s more reliable than isset(), but it’s SLOW.  We benchmarked the array_key_exists() and isset() methods as shown below and find that array_key_exists() is almost 5 times slower than isset().

To take the speed advantage of isset() while keeping the reliable result from array_key_exists(), we combined the both: Usually an element being set NULL is a rare case, so in most of the time, isset() is still reliable. When isset() fails, we should do an additional checking by array_key_exists() to double confirm that the key really doesn’t exist. It turns out that the below code works the best:

<?php 
if (isset($Arr['MyElement']) || array_key_exists('MyElement', $Arr)) { 
      ... do my stuff ... 
} ?>


The beauty of PHP (also many other modem languages) is that it doesn’t require the whole conditional statement being fully parsed. So the PHP engine actually only evaluate the result of isset(). if isset() returns FALSE, it then evaluate array_key_exists(). If isset() returns TRUE, array_key_exists() is never evaluated. That’s saying the sequence of the two conditions cannot be reversed.

Benchmarking

We did a simple benchmarking base on the isset(), array_key_exists() and the combined method, and the result of the combined method is very promising.

<?php 
$a = array('a'=>1,'b'=>2,'c'=>3,'d'=>4, 'e'=>null); 
$s = microtime(true); 
for($i=0; $i<=100000; $i++) { 
     $t= array_key_exists('a', $a); //true 
     $t= array_key_exists('f', $a); //false
     $t= array_key_exists('e', $a); //true 
} 

$e = microtime(true); 
echo 'array_key_exists : ', ($e-$s); 

$s = microtime(true); 
for($i=0; $i<=100000; $i++) { 
     $t = isset($a['a']); //true 
     $t = isset($a['f']); //false
     $t = isset($a['e']); //false 
} 

$e = microtime(true); 
echo 'is_set : ' , ($e-$s); 

$s = microtime(true); 
for($i=0; $i<=100000; $i++) { 
     $t= (isset($a['a']) || array_key_exists('a', $a)); //true 
     $t= (isset($a['f']) || array_key_exists('f', $a)); //false
     $t= (isset($a['e']) || array_key_exists('e', $a)); //true 
} 

$e = microtime(true); 
echo 'isset() + array_key_exists : ', ($e-$s); 
?> 

The benchmarking result (average):

  • array_key_exists() : 308 ms
  • is_set() : 4.7ms
  • isset() + array_key_exists() :217ms

Latest Update: I have packaged this method to a single function, and added the checking of element existence in multiple-dimension arrays. Please check my another post: A complete element existence checking function for PHP.

9 Replies to “PHP – isset() vs array_key_exists() : a better way to determine array element’s existence”

  1. Nice..
    I’ve tried also
    isset() AND !is_null()

    array_key_exists : 2.61410689354
    is_set : 0.0547709465027
    isset() + array_key_exists : 0.0560970306396
    isset AND !is_null: 0.909719944

  2. I only find this article now. You have got a few flaws in your code. Lets start with
    $t= array_key_exists(‘f’, $a); //true
    $t = isset($a[‘f’]); //true
    Why would they return TRUE? The key doesn’t exist!

    Let’s look at the last loop:
    $t= (isset($a[‘a’]) || array_key_exists(‘a’, $a)); //true
    $t= (isset($a[‘a’]) || array_key_exists(‘f’, $a)); //true
    $t= (isset($a[‘a’]) || array_key_exists(‘e’, $a)); //true
    (Let’s not dwell on array_key_exists(‘f’, $a) returning FALSE.)
    The first condition, isset() is always run again key ‘a’. Since that key exists, array_key_exists() will never be called. Wouldn’t you say this creates a bias? No wonder the combination of isset() || array_key_exists() is almost as fast as isset() alone. Try and call
    isset($a[‘f’])
    isset($a[‘e’])
    and you will find the times will go up, because in those instances array_key_exists() will also be called.

    The biggest flaw is comparing the times to loop and from that deducing the factor that isset() is faster. Just to loop takes time. If you time that loop:
    for($i=0; $i<=100000; $i++) {
    $t=false;
    $t=false;
    $t=false;
    }
    and deduct the time it takes to run this from all other measured times, you are getting closer to the actual time it takes to run isset() and array_key_exists(). You will find that isset() is not 5 times, but at least 20 times faster.

    1. Thanks for spotting out. Yes you’re right there are some mistakes on the codes. I have corrected and updated the codes.

      Yes agree that the time measurement covers the loop and actually the loop may also dominated the overall measurement. Here my purpose is to show that the array_key_exists() is the slowest method.

  3. Yes but if a key doesn’t exist and you test for is_null it will return ‘true’. So this is no option.

    It should be isset OR is_null if you wanted to use it in the manner described in the post above.

  4. Who cares about array_key_exists performance when your web page is throwing 200+ non-indexed sql request ?

    We have far enough CPU in our server to ignore this fact for 99.999999% of projects that don’t have the load of facebook or twitter.

Leave a Reply

Your email address will not be published. Required fields are marked *