Arrays7 min readExamples run on PHP 8.5.10

array_key_exists()

Learn how array_key_exists() checks whether a key is present in a PHP array, how it differs from isset() for null values, and which key edge cases matter.

Signature

array_key_exists(string|int|float|bool|resource|null $key, array $array): bool
Available since PHP 4.0.77.48.08.18.28.38.48.5All versions →

Purpose

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 integer 1, true becomes 1 and false becomes 0.
  • $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.

Example
<?php
$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";
Output
{"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.

Example
<?php
$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";
Output
{"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.

Example
<?php
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";
Output
{"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 null is present, so array_key_exists() returns true.
  • Integer-like strings are converted to integers, and booleans become 0 or 1.
  • 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

  1. Using isset() when null is a legitimate value. isset() returns false for both a missing key and a null value. Use array_key_exists() when the difference matters.
  2. Using in_array() to check keys. in_array() checks values. To check keys, use array_key_exists().
  3. Expecting a deep search. A call such as array_key_exists('email', $user) does not look inside $user['profile'].
  4. Passing an object. Objects have not been accepted as the second argument since PHP 8.0. Use property_exists() for object properties.
  5. Passing null as the key. It is deprecated as of PHP 8.5, so use "" for the empty-string key.
  6. 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.
  • isset() checks that a variable or element exists and is not null.
  • 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

Present, null-valued and missing keys compared with isset()
<?php
$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";
Output
{"theme":true,"sidebar_exists":true,"sidebar_isset":false,"missing":false}
Key normalization for numeric strings, booleans and the empty string
<?php
$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";
Output
{"string 1":true,"int 1":true,"string 02":true,"int 2":false,"true":true,"false":true,"empty string":true}
Checking nested keys with a path helper
<?php
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";
Output
{"top_level":false,"a_b":true,"a_c":false,"a_b_c":false}