PHP isset() and multi-dimentional array

** The issue discussed in this post has been fixed since PHP5.4.0, so the below discussion and solution are for PHP 5.3.x or lower. Thanks David for clarifying.

A few weeks ago I covered how to check the existence of an array element in PHP. In the post I explained why isset() is dangerous to check the existence of elements in an array. I also proposed a better solution (the isset()+array_key_exists() method) to do the checking.

Today I’m going to discuss another strange (and dangerous) behavior brought along with isset() function and multi-dimensional arrays.

The problem

Let’s consider this simple code:

<!--?php $a = array('test'=-->'ABC');
var_dump(isset($a['test']));                       //true
var_dump(isset($a['test']['non_exist']));          //true?!!
var_dump(isset($a['test']['non_exist']) || array_key_exists('non_exist', $a['test'])); //true again?!!!

Surprise, huh? Isset() returns true for a non-exist element!

What even worse is that the previous proposed method (the isset()+ array_key_exists() method) also gives a wrong result! This is because isset() returns true for the non_exist element so the overall OR operation will become “true”. The array_key_exists() is never implemented.

The reason

So why isset() returns true for a non-exist element? I’m not sure the exact reason but I have a guess:

PHP first look at $a[‘test’]. Since $a[‘test’] does exist, isset($a[‘test’]) returns true. Then PHP checks the 2nd dimension: the ‘non_exist’ element. As $a[‘test’] is a string, it is also considered as an array (In PHP, string is a sequential array by type-casting). When checking the sequential array where all index should be integers, the index [‘non_exist’] is **converted** to an integer which equals zero. So actually PHP is checking isset($a[‘test’][0]). Unfortunately $a[‘test’][0] does really exists (with value ‘A’). So the overall result of this checking is “true”.

To verify this guess, let’s run this code:

<!--?php $a = array(1=-->'', 2=>'ABC');
var_dump(isset($a[1])); //true
var_dump(isset($a[1]['t'])); //false => $a[1] is empty string, $a[1][0] doesn't exist
var_dump(isset($a[2])); //true
var_dump(isset($a[2]['t'])); //true => $a[2] is 'abc', so $a[2][0] exists and equals 'A'.

The result has shown that my guess is pretty reasonable.

The solution

You say: OK, I know your guess is somehow right, so how to fix it?

Usually when we check the existence of elements in multiple dimensional array, we use  something like

array_key_exists('non_exist', $a['test']); 

Yes. This is true…but if you really do so in our case, you will get this warning:

Warning: array_key_exists() expects parameter 2 to be array, string given 

Somehow for unknown reason array_key_exists() doesn’t consider string as array now and is complaining us.

So what’s the solution?

Complete array element existence checking function

Combined with what I proposed in the previous and this post, I have worked out a function that checks whether an element does exist in an array, regardless the array’s dimensions:

<!--?php function elementExists($key, $array){     if (is_array($key)) {         $curArray = $array; 		$lastKey = array_pop($key); 		foreach($key as $oneKey) { 			if (!elementExists($oneKey, $curArray)) return false; 			$curArray = $curArray[$oneKey]; 		} 		return is_array($curArray) && elementExists($lastKey, $curArray); 	} else { 		return isset($array[$key]) || array_key_exists($key, $array); 	} } $a=array(1,2,3,4, 'dim1'=-->array('dim2'=>array('dim3'=>null)));

//multi-dimension : check if $a['dim1']['dim2']['dim3']['dim4'] exists:
var_dump(elementExists(array('dim1', 'dim2', 'dim3', 'dim4'), $a)); //false

//multi-dimension : check if $a['dim1']['dim2']['dim3'] exists:
var_dump(elementExists(array('dim1', 'dim2', 'dim3'), $a)); //true

//single dimension : check if $a['dim1'] exists:
var_dump(elementExists('dim1', $a)); //true

This piece of codes looks quite awful and dirty, and its performance  is not evaluated. I think there are more elegant (and faster) codes to do the same thing. Since I’m in a hurry and got to complete my project ASAP, I prefer to leave it as it is now.

Comments are always welcomed!

Check if an array is associative or sequential(indexed) in PHP

In PHP, depending on the type of the keys in an array, the array can be identified as associative (if the key is a string like $arr[‘mykey’]) or sequential (some may call it indexed, i.e. if the key is an integer like $arr[1], $arr[2], etc.).

Although the internal representation of both associative and sequential arrays are the same in the PHP’s core (Both are ordered map), in some situations we still need to differentiate one from another. There is no built-in function to tell if an array is associative or sequential, so we have to write our own.

The most popular method to check this is to compare the keys of an array with the result of range(), like this, this and this:

function isAssoc($arr){
	return array_keys($arr) !== range(0, count($arr) - 1);

The problem of using range() is that it only works when the keys of the array are continuous integer numbers. That is, the keys of an array has to be {0,1,2,3,4,…..}. If the array’s smallest key is not 0 but 1, like {1,2,3….}, or there is a “hole” in between, like {1,2,4,5,8,…}. They will be treated as associative array.

Whether this method makes sense depends on how you define the term ”sequential array” and “associative array”. Unfortunately I didn’t find any “official” definition about them in PHP’s manual (as they doesn’t matter to PHP). My personal definition is that when there exist a non-integer key in an array, the array is not sequential. So for the arrays with keys like  {1,2,100, 1000, 1500}, it is still sequential. With this logic, my method to check associative / sequential arrays is this:

function is_asso($a) {
	foreach(array_keys($a) as $key)
		if (!is_int($key)) return TRUE;
	return FALSE;

This function will check every keys in the array until it find one that is not an integer, then it quit the loop and tell it is associative array. This function can handle sequential arrays with any starting index, and any hole in between.

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.

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:

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.


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.

$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.

Equal (==), identical (===) and array comparison in PHP

Equal (==)

If you use equal (==), you are allowing type conversion which means PHP will try to convert the two sides into the same type and then do the comparison. So even if the two sides are NOT the same thing, they MAY still be treat as the SAME.

Consider this code:

$left = "C"; 
$right = 0; 
var_dump($left == $right); 



"C" equals to 0 ?? The logic behind is : $left is a String of "C", since it is compared to $right which is a number, PHP will first convert the String "C" to a number by parsing "C" as a numeric value which is unfortunately 0, then this 0 is compares to $right which is 0, so although strange the comparison result is logically "true".

Identical (===)

On the contrary, when identical (===) is used in the comparison, PHP will not do any type conversion. PHP firstly check if the both side is of the same type. If not, then just return false. If they are of the same type, it then compare the values to see if they are the same. So it should be no wonder that the output of the below codes is "false":

$left = "5"; 
$right = 5; 
var_dump($left === $right); 



What if they are Arrays?

Consider this code:

$a = array('a'=>1, 'b'=>2, 'c'=>3);                 //reference array 
$b = array('a'=>1, 'b'=>2, 'c'=>3);                //equal and identical 
$c = array('a'=>1, 'b'=>2);                                //one element less 
$d = array('a'=>1, 'b'=>100, 'c'=>3);          //one element has different value 
$e = array('a'=>1, 'c'=>3, 'b'=>2);               //same key-value pairs but different sequence 
echo '$a == $b is ', var_dump($a ==$b); 
echo '$a === $b is ', var_dump($a === $b); 
echo '$a == $c is ', var_dump($a ==$c); 
echo '$a === $c is ', var_dump($a === $c); 
echo '$a == $d is ', var_dump($a ==$d); 
echo '$a === $d is ', var_dump($a === $d); 
echo '$a == $e is', var_dump($a ==$e); 
echo '$a === $e is', var_dump($a === $e); 


$a == $b is bool(true) 
$a === $b is bool(true) 
$a == $c is bool(false) 
$a === $c is bool(false) 
$a == $d is bool(false) 
$a === $d is bool(false) 
$a == $e is bool(true) 
$a === $e is bool(false) 

So we conclude that:

  • When two arrays are same in each key/value pair, and they have the same amount of elements, and the elements are in the same sequence, they are equal (==) and identical (===),
  • If one array has less elements than another one, they are neither equal (==) nor identical (===).
  • If one of the elements in an array has different value, the two arrays are neither equal (==) nor identical (===)
  • If two arrays have the same element, but different sequence, they are equal (==) but NOT identical (===).


  1. Type conversion during comparison in PHP (they call it type juggling):
  2. Type comparisons in PHP: