Что оптимальнее: isset или array_key_exists ?

Существует два наиболее популярных способа, позволяющих узнать о наличии в заданном массиве заданного ключа:

1. isset — Определяет, была ли установлена переменная значением отличным от NULL
2. array_key_exists — Проверяет, присутствует ли в массиве указанный ключ или индекс

Пример:

$array = [
    'first' => 1,
    2 => 'second',
    'third' => null
];

$isset_result = isset($array['first']);
$ake_result   = array_key_exists('first', $array);

Какая же из них наиболее оптимальна?

Первое отличие двух этих способов в том, что isset — это языковая конструкция, а не функция, как array_key_exists.

Второе отличие в том, что isset проверяет не только лишь наличие заданного ключа в заданном массиве, а, так же, в случае нахождения значения по заданному ключу, ещё и соответствие этого значения NULL.

То есть, в следующем случае:

echo isset($array['third']) === array_key_exists('third', $array);

Результаты отработки isset и array_key_exists не будут равны и мы увидим false, т.к. в случае с isset заданный ключ найден, но значение для заданного ключа равно NULL. Следовательно, эта функция «посчитает», что заданного ключа и вовсе нет.

То есть, если вам необходимо проверить исключительно наличие ключа в заданном массиве и вас интересует исключительно его наличие (не важно, что значение под данным ключом может быть не задано или соответствовать NULL) то следует использовать array_key_exists.

Третье отличие в скорости работы.

Для тестирования скорости работы я создал достаточно большой массив (в тестах вариьровалось от 10 тысяч элементов до 10 миллионов элементов) «случайных» значений и, затем, в цикле (от 10к до 10кк итераций) я вызывал isset и array_key_exists.

Код примера:

$result = [];

// 1. Заполняем массив, в котором будем осуществлять поиск

$data = [];

$elementNames = ['perl', 'php', 'csharp', 'cpp', 'c', 'javascript', 'java'];
$elementNames_length = count($elementNames) - 1;

$numberOfElements = 10000;
for($i = 0; $i < $numberOfElements; $i++)
{
    $randomKey = mt_rand(0, $elementNames_length);

    $data['da'.mt_rand(mt_rand(100, ceil($numberOfElements/2)), $numberOfElements).'net'] = $i . $elementNames[$randomKey] . mt_rand(mt_rand(100, ceil($numberOfElements/2)), $numberOfElements);
}

// 2.1 Тестируем isset

$isset_start_time = microtime(true);

$isset_time = 0.00;
for($i = 0; $i < $numberOfElements; $i++)
{
     $flush = isset($data['da'.$numberOfElements.'net']);
}

$isset_end_time = microtime(true);

$isset_time = $isset_end_time - $isset_start_time;

// 2.2 Тестируем array_key_exists

$ake_start_time = microtime(true);

$ake_time = 0.00;
for($i = 0; $i < $numberOfElements; $i++)
{
    $flush = array_key_exists('da'.$numberOfElements.'net', $data);
}

$ake_end_time = microtime(true);
$ake_time = $ake_end_time - $ake_start_time;

// 3. Выводим результаты

$result[] = [
    'isset' => $isset_time,
    'ake'   => $ake_time
];

echo '<pre>' . print_r($result, true) . '</pre>';

Далее, тесты на массиве разных размеров (от 10к до 10млн):

1. Результат (10000 элементов):

1. isset => 0.00714898109436
2. array_key_exists => 0.0171840190887

2. Результат для 100 тыс. элементов (100000 элементов):

1. isset => 0.0732381343842
2. array_key_exists => 0.175088882446

3. Результат для 1 млн. элементов (1000000 элементов):

1. isset => 0.757771015167
2. array_key_exists => 1.79065108299

4. Результат для 10 млн. элементов (10000000 элементов):

1. isset => 7.62896299362
2. array_key_exists => 17.4600510597

Из результата очевидно, что isset быстре. На «больших» же массивах это уже становится достаточно ощутимо.

В общем, можно сделать вывод, что isset — это более оптимальный способ проверить наличие заданного ключа в заданном массиве, но следует это делать не без осторожности, т.к. если заданный ключ в заданном массиве будет найден, то isset ещё и проверит найденное значение на NULL и в случае соотвествия вернёт false.