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!
Pingback: PHP – Fast way to determine a key/element’s existance in an array – zome off
I tested a combined isset() and array_key_exists() function myself, and found out that a combined function is twice as slow as array_key_exists().
My function:
function array_isset($key, Array $array) {if(isset($array[$key])) {
true;
}
return array_key_exists($key, $array);
}
Check out my code here:
https://gist.github.com/1077983
In the 3rd line of your code, you should write “return true;”, otherwise array_key_exists() will always be called no matter isset() is true or false.
BTW, you could combine all those lines into just one line code:
function array_isset($key, Array $array) {
return isset($array[$key]) || array_key_exists($key, $array);
}
This will gives you the same result.
Thanks, somehow missed the return.
Now timings are closer, like they should:
Time array_key_exists(‘a’, $array): 0.68053483963013 sec
Time array_key_exists(‘b’, $array): 0.68176889419556 sec
Time array_isset(‘a’, $array): 0.7919340133667 sec
Time array_isset(‘b’, $array): 1.2284920215607 sec
Timings for your one-liner are equal to my code (with return).
But i still see that the wrapper function needs at least 1/10 extra time. So i would rather simly stick to array_key_exists() than a own wrapper function.
FYI:
I would not use “isset() || array_key_exists()” because that code assumes about a left to right order of execution. Many languages do not garantee such a order. So i try to write code that does garantuee a order. Does PHP garantuee something like that?
Your result looks interesting. Would you mind posting your testing code here so that we can dig into it?
I wonder if ‘a’ and ‘b’ are non-existing keys in the $array. For detecting an non-existing key, you better use array_key_exists() alone. isset() is a short-cut to check if the key exists. If isset() is true, then we can ensure the element exists and no need to do the array_key_exists(). However, if the element exist in the array and is set null (i.e. $array['a'] = NULL), isset() will tell you that it doesn’t exist. That’s why we need to use array_key_exists() to double confirm. Array_key_exists() will always give you the “correct” answer but it is slow so we want to use it only when it is necessary.
For an non-existing key, the wrapper function will actually go through two tests : isset() and array_key_exists(), so it definitely slower than just array_key_exists(). If the most of the keys that you are checking are non-existing, then there is no doubt to use array_key_exists() directly.
I have another post discussing the use and benchmarking of isset()+array_key_exists() method. It may interest you.
Yes, for boolean operators, PHP is doing the left-to-right order. See here: http://www.php.net/manual/en/language.operators.precedence.php
Finally I got your test code in github.
The reason why the combined method is 2x slower is explained here:
In the testing code, the combined checking is wrapped into a function array_isset(). Every time when PHP makes a function call it adds some overheads. So the measured time is actually includes those overheads. If you change your code (in the while-loop) :
if(array_isset(‘a’, $array))
into
if (isset($array['a']) || array_key_exists(‘a’, $array))
The result will be more reasonable. Here is the benchmarking result with your code with the that modification:
isset($array['a']): true – should be true
isset($array['b']): false – should be true
array_key_exists(‘a’, $array['a']): true – should be true
array_key_exists(‘b’, $array['b']): true – should be true
Time isset($array['a']): 0.23629188537598 sec (t1)
Time isset($array['b']): 0.18283319473267 sec (t2)
Time array_key_exists(‘a’, $array): 0.80693697929382 sec (t3)
Time array_key_exists(‘b’, $array): 0.80788898468018 sec (t4)
— isset() should be faster by factor x3
Time array_isset(‘a’, $array): 0.2564389705658 sec (t5)
Time array_isset(‘b’, $array): 0.97402620315552 sec (t6)
— array_isset() is much slower than array_key_exists. Damn.
Note that (t5) is much faster than (t3), and (t6) ~= (t2) + (t4) which is reasonable because it does both isset() and array_key_exists() checking.
<?php
$f= $_POST["clientno"];
$a= $_POST["name"];
$b= $_POST["address"];
$c= $_POST["city"];
$d= $_POST["pincode"];
$e= $_POST["state"];
$conn_mysql=mysql_connect("localhost","root","");
if($conn_mysql)
{
echo "Connction Created “;
}
else
{
echo “Not Created “;
}
$mysql_db=mysql_select_db(“client”);
if(!$mysql_db)
{
echo “DB Not Selected “;
}
else
{
echo “DB is Selected “;
}
$sqlinsert=”INSERT into client_mstr(clientno,name,address,city,pincode,state)values(‘$f’,'$a’,'$b’,'$c’,'$d’,'$e’)”;
$result=mysql_query(“$sqlinsert”);
if($result)
{
echo “Table Values are Inserted “;
}
else
{
echo “Data Are Not Inserted”;
}
?>
Solving My Error Or Reply Me
Undefined Index : clientno
Undefined Index : name
Undefined Index : address
Undefined Index : city
Undefined Index : pincode
Undefined Index : state