array_key_exists('key', $array) retorna true se o array tem essa chave e false se não tem. Repare na ordem: a chave vem primeiro, o array depois. Ele retorna true mesmo quando o valor guardado na chave é null, que é a única coisa que o isset() não faz.
Para verificar um valor em vez de uma chave, use in_array().
array_key_exists ou isset
Os dois verificam uma chave. Eles só discordam quando o valor é null: o isset() trata um valor null como "não definido", o array_key_exists() informa o que realmente está no array.
0 e '' contam como definidos para os dois; só o null os separa. Qual você quer depende do que null significa nos seus dados:
- Use
isset()quandonullsignifica "sem valor". É o caso comum, é uma construção da linguagem (um pouco mais rápida) e aceita caminhos aninhados e variáveis indefinidas sem aviso. - Use
array_key_exists()quandonullé um valor real que você precisa distinguir de uma chave ausente: um campo JSON enviado comonull, uma coluna do banco que éNULL, uma opção definida explicitamente comonullpara limpá-la.
A página sobre isset cobre os outros usos dele, incluindo verificar várias variáveis de uma vez.
Distinguir null de ausente num payload JSON
Um caso típico em que só o array_key_exists() dá a resposta certa: uma API que atualiza um registro a partir de JSON. Um campo enviado como null significa "limpe isto", um campo omitido significa "não mexa". O isset() vê os dois como a mesma coisa.
Com isset($patch[$field]), o número de telefone continuaria, porque o null pareceria um campo ausente.
key_exists() é a mesma função
key_exists() é um alias de array_key_exists(), mantido desde as primeiras versões do PHP. Mesmos argumentos, mesmo resultado. Prefira o nome completo, que é o que os leitores esperam ver.
Tipos de chave: "1" e 1 são a mesma chave
Chaves de array são inteiros ou strings, e uma string que é um inteiro decimal simples é guardada como inteiro. Então array_key_exists('1', $arr) encontra a chave 1, e vice-versa. Uma string como '01' continua string e é outra chave.
Verificar chaves aninhadas e várias chaves
O array_key_exists() olha um nível. Para um caminho aninhado em que null não importa, isset($a['x']['y']) verifica todos os níveis de uma vez. Para um caminho em que importa, uma pequena função auxiliar percorre os níveis. Para verificar se várias chaves estão todas presentes, compare com array_diff_key().
array_flip($required) transforma a lista de nomes em chaves para que o array_diff_key() possa compará-las com as chaves da entrada; o que sobra é a lista de campos ausentes, pronta para uma mensagem de erro.
Objetos precisam de property_exists
Versões antigas do PHP aceitavam um objeto no array_key_exists(). O PHP 8 lança um TypeError. Para objetos, property_exists() verifica uma propriedade declarada ou dinâmica (mesmo uma definida como null), e isset($obj->prop) funciona como o isset() em arrays.
As duas últimas linhas mostram o outro caminho: get_object_vars() transforma as propriedades acessíveis do objeto num array, e então as funções de array se aplicam.
Perguntas frequentes
Por que isset retorna false quando array_key_exists retorna true?
A chave guarda null. isset($arr['k']) só é true se a chave existe e o valor não é null, enquanto array_key_exists('k', $arr) é true sempre que a chave está no array. Para qualquer outro valor, incluindo 0, '' e false, os dois dão a mesma resposta.
O que é key_exists no PHP?
Um alias de array_key_exists(). key_exists('id', $row) e array_key_exists('id', $row) se comportam igual. A maior parte do código usa o nome mais longo.
Como verifico se uma chave aninhada existe no PHP?
Verifique cada nível: isset($data['user']['address']['city']) verifica o caminho inteiro de uma vez e nunca avisa quando falta um nível. Se valores null precisam contar como presentes, percorra o caminho com array_key_exists() nível por nível.
Posso usar array_key_exists num objeto?
Não. Desde o PHP 8.0, passar um objeto lança um TypeError. Use property_exists($obj, 'name') para propriedades declaradas, ou isset($obj->name).