Signature
array_key_exists(string|int|float|bool|resource|null $key, array $array): boolPurpose
array_key_exists() answers one question: is this key present in this array? It looks only at keys. It does not care what value is stored under the key, so a key holding null, false, 0 or an empty string still counts as present.
That makes it the right tool when "the key is missing" and "the key exists but holds null" mean different things. Typical cases are optional configuration, decoded JSON payloads and partially filled form data.
Signature
Parameters
$key: the key to look for. It can be any value that is valid as an array index. PHP normalizes it the same way it does when you read or write an element. A numeric string such as"1"becomes the integer1,truebecomes1andfalsebecomes0.$array: the array to inspect. Neither parameter has a default value, so both are required.
The manual's changelog notes that since PHP 8.0 the function no longer accepts an object as the second argument. To check an object, use property_exists() instead.
Return value and failure cases
The function returns true if the key is present and false if it is not. A missing key is not an error. Passing something other than an array as $array throws a TypeError in PHP 8.
The check covers the first dimension only. Nested keys in a multidimensional array are not found, so you must descend level by level.
The manual also notes that using null as the key is deprecated as of PHP 8.5, and recommends an empty string. Since null and "" are treated alike as keys, write "" when you mean the empty-string key.
Example 1: present, null and missing
The first example compares array_key_exists() with isset() for a key whose value is null.
$settings = ['theme' => 'dark', 'sidebar' => null];
echo json_encode([
'theme' => array_key_exists('theme', $settings),
'sidebar_exists' => array_key_exists('sidebar', $settings),
'sidebar_isset' => isset($settings['sidebar']),
'missing' => array_key_exists('language', $settings),
]), "\n";{"theme":true,"sidebar_exists":true,"sidebar_isset":false,"missing":false}
isset() returns false for the sidebar key because its value is null. array_key_exists() returns true because the key is there.
Example 2: key normalization
Because keys are normalized, the type you pass does not always match the type you stored.
$items = [1 => 'one', '02' => 'two', '' => 'empty', 0 => 'zero'];
echo json_encode([
'string 1' => array_key_exists('1', $items),
'int 1' => array_key_exists(1, $items),
'string 02' => array_key_exists('02', $items),
'int 2' => array_key_exists(2, $items),
'true' => array_key_exists(true, $items),
'false' => array_key_exists(false, $items),
'empty string' => array_key_exists('', $items),
]), "\n";{"string 1":true,"int 1":true,"string 02":true,"int 2":false,"true":true,"false":true,"empty string":true}
The string "1" matches the integer key 1. The string "02" is not a canonical integer, so it stays a string key and the integer 2 does not match it.
Example 3: nested data
Since only the first level is searched, a helper that walks a path is useful for nested arrays.
function has_path(array $data, array $path): bool
{
$current = $data;
foreach ($path as $key) {
if (!is_array($current) || !array_key_exists($key, $current)) {
return false;
}
$current = $current[$key];
}
return true;
}
$data = ['a' => ['b' => null], 'top' => 1];
echo json_encode([
'top_level' => array_key_exists('b', $data),
'a_b' => has_path($data, ['a', 'b']),
'a_c' => has_path($data, ['a', 'c']),
'a_b_c' => has_path($data, ['a', 'b', 'c']),
]), "\n";{"top_level":false,"a_b":true,"a_c":false,"a_b_c":false}
The helper treats a.b as present even though its value is null. It stops safely when an intermediate value is not an array, which is why a.b.c is false.
Edge cases
- A key whose value is
nullis present, soarray_key_exists()returnstrue. - Integer-like strings are converted to integers, and booleans become
0or1. - The empty string is a valid key.
- Searching is by exact key. The function never searches values, and it never searches nested arrays.
Common mistakes
- Using
isset()whennullis a legitimate value.isset()returnsfalsefor both a missing key and anullvalue. Usearray_key_exists()when the difference matters. - Using
in_array()to check keys.in_array()checks values. To check keys, usearray_key_exists(). - Expecting a deep search. A call such as
array_key_exists('email', $user)does not look inside$user['profile']. - Passing an object. Objects have not been accepted as the second argument since PHP 8.0. Use
property_exists()for object properties. - Passing
nullas the key. It is deprecated as of PHP 8.5, so use""for the empty-string key. - Swapping the arguments. The key comes first and the array second, which is the reverse of
in_array(), where the needle comes first and the haystack second.
Related functions
isset()checks that a variable or element exists and is notnull.array_keys()returns all keys, or the keys matching a given value.in_array()checks whether a value exists in an array.property_exists()checks whether an object or class has a property.
Recap
Use array_key_exists($key, $array) to test for the presence of a key, regardless of the value stored there. It returns a plain bool. It applies normal array key normalization and checks only the first dimension. Prefer it over isset() whenever null is a meaningful stored value.
Tested examples
$settings = ['theme' => 'dark', 'sidebar' => null];
echo json_encode([
'theme' => array_key_exists('theme', $settings),
'sidebar_exists' => array_key_exists('sidebar', $settings),
'sidebar_isset' => isset($settings['sidebar']),
'missing' => array_key_exists('language', $settings),
]), "\n";
{"theme":true,"sidebar_exists":true,"sidebar_isset":false,"missing":false}
$items = [1 => 'one', '02' => 'two', '' => 'empty', 0 => 'zero'];
echo json_encode([
'string 1' => array_key_exists('1', $items),
'int 1' => array_key_exists(1, $items),
'string 02' => array_key_exists('02', $items),
'int 2' => array_key_exists(2, $items),
'true' => array_key_exists(true, $items),
'false' => array_key_exists(false, $items),
'empty string' => array_key_exists('', $items),
]), "\n";
{"string 1":true,"int 1":true,"string 02":true,"int 2":false,"true":true,"false":true,"empty string":true}
function has_path(array $data, array $path): bool
{
$current = $data;
foreach ($path as $key) {
if (!is_array($current) || !array_key_exists($key, $current)) {
return false;
}
$current = $current[$key];
}
return true;
}
$data = ['a' => ['b' => null], 'top' => 1];
echo json_encode([
'top_level' => array_key_exists('b', $data),
'a_b' => has_path($data, ['a', 'b']),
'a_c' => has_path($data, ['a', 'c']),
'a_b_c' => has_path($data, ['a', 'b', 'c']),
]), "\n";
{"top_level":false,"a_b":true,"a_c":false,"a_b_c":false}