← Voltar aos artigos

isset · empty · null · validação · tipos

isset() vs empty() vs is_null() no PHP: qual usar e quando

Publicado em 14/08/2026 · 9 min de leitura

As três parecem intercambiáveis e não são. Em uma linha cada: isset() responde "a variável existe e não é null?"; empty() responde "o valor é falsy (ou nem existe)?"; is_null() responde "o valor é exatamente null?". A diferença só machuca em valores de fronteira — e é sempre nos mesmos suspeitos: 0, '0' e a string vazia. Um formulário que usa empty() para validar a quantidade rejeita quem digitou 0; um código que usa isset() para saber se um campo veio na requisição erra quando o campo veio com valor null. Este artigo mostra a tabela completa, o mecanismo por trás e qual usar em cada situação.

O mecanismo: são duas perguntas diferentes

A confusão nasce de tratar como uma só coisa duas perguntas que não são a mesma:

  1. "Isso existe?" — a variável/chave foi definida? É território do isset().
  2. "Isso tem conteúdo útil?" — o valor significa alguma coisa? É território do empty().

isset() responde a primeira, com um detalhe: ele trata null como "não existe". Faz sentido dentro da lógica do PHP — null é literalmente "ausência de valor" —, mas é a origem de metade dos bugs, porque uma chave que existe com valor null faz o isset() devolver false.

empty() responde a segunda usando a mesma régua do if: ele converte o valor para booleano e devolve o inverso. Ou seja, empty($x) equivale a !isset($x) || !$x. Por isso ele considera "vazio" tudo que um if consideraria falso — inclusive coisas que o usuário digitou de propósito.

is_null() é a mais literal e a mais restrita: só devolve true para o valor null, exatamente igual a $x === null.

A tabela completa

Esta é a referência que resolve a dúvida na hora. Os valores foram verificados no PHP 8:

Valor isset() empty() is_null() if ($x)
variável não definida false true true ⚠️
null false true true false
false true true false false
0 true true false false
0.0 true true false false
'' (string vazia) true true false false
'0' (string zero) true true false false
' ' (um espaço) true false false true
[] (array vazio) true true false false
[0] true false false true
'abc' true false false true
'0.0' true false false true
'false' true false false true

⚠️ is_null() numa variável inexistente devolve true, mas emite Warning: Undefined variableisset() e empty() não emitem nada.

Duas linhas merecem atenção especial. A '0' é a armadilha clássica (abaixo). E o par '0.0' vs '0' costuma surpreender: a string '0.0' é verdadeira, porque só a string '0' exata (e a vazia) são falsy — '0.0', '00' e ' ' são todas truthy.

evite
// valida presença com empty
if (empty($_POST['quantidade'])) {
    erro('Informe a quantidade');
}
// rejeita '0' (válido) e aceita ' ' (espaço, inválido)
prefira
$qtd = $_POST['quantidade'] ?? '';

if (trim($qtd) === '') {
    erro('Informe a quantidade');     // só string realmente vazia
} elseif (!is_numeric($qtd)) {
    erro('A quantidade deve ser um número');
}
// '0' passa; ' ' é rejeitado; a mensagem é específica

Array: isset() mente quando o valor é null

Este é o segundo bug mais comum, e o motivo pelo qual array_key_exists() existe:

O array

Duas chaves definidas — uma com texto, outra com null. As duas existem no array.

$dados = ['nome' => 'Ana', 'apelido' => null];

isset() diz que a chave não existe

Como isset() trata null como ausência, ele devolve false para uma chave que está lá.

isset($dados['apelido']);   // false  ← mas a chave existe!
isset($dados['nome']);      // true

array_key_exists() diz a verdade sobre a existência

Esta função responde só "a chave está no array?", ignorando o valor.

array_key_exists('apelido', $dados);   // true  ← correto
array_key_exists('sobrenome', $dados); // false

Quando a diferença importa de verdade

Numa atualização parcial (PATCH), "campo ausente" e "campo enviado como null" são intenções opostas: a primeira significa "não mexa neste campo", a segunda significa "apague este campo". Só array_key_exists() distingue as duas.

if (array_key_exists('apelido', $entrada)) {
    $usuario->apelido = $entrada['apelido'];   // pode ser null: limpar
}
// se a chave não veio, o campo fica intocado

A regra

Precisa saber se a chave existe? array_key_exists(). Precisa saber se tem valor utilizável? isset() (ou ??).

// existência real  → array_key_exists
// valor utilizável → isset / ??

O caminho moderno: ?? no lugar de isset()

Em quase todo código novo, o isset() dentro de um if para definir um padrão foi substituído pelo operador null coalescing (??), que faz exatamente a mesma checagem — devolve o lado direito se o esquerdo não existir ou for null — sem emitir aviso:

// antes
$pagina = isset($_GET['pagina']) ? $_GET['pagina'] : 1;

// hoje
$pagina = $_GET['pagina'] ?? 1;

// encadeado: usa o primeiro que existir
$idioma = $_GET['lang'] ?? $_COOKIE['lang'] ?? 'pt_BR';

// atribuir só se ainda não tiver valor
$config['timeout'] ??= 30;

Isso importa por causa de um comportamento do PHP 8: acessar uma chave inexistente direto emite Warning: Undefined array key "x". O ?? silencia esse caso legitimamente — e sem a preguiça perigosa do @, que esconde todos os erros.

Uma API recebe ['nome' => 'Ana', 'bio' => null] e o código faz if (isset($dados['bio'])) { $perfil->bio = $dados['bio']; }. O usuário queria apagar a bio enviando null. O que acontece?

Ver resposta

Resposta certa: Nada acontece — a bio antiga permanece

isset($dados['bio']) devolve false quando o valor é null, mesmo com a chave presente no array. O if não entra e a bio antiga fica intacta — o usuário jura que apagou e o dado continua lá. É o caso que exige array_key_exists('bio', $dados), que separa "não enviou o campo" de "enviou o campo com null".

Resumo de decisão

Você quer saber… Use Cuidado
Se a variável existe e tem valor utilizável isset($x) Devolve false se o valor for null
Se a chave existe no array (mesmo com null) array_key_exists() Só para arrays
Se é exatamente null $x === null ou is_null($x) A variável precisa existir (senão, warning)
Definir um valor padrão $x ?? 'padrão' Não use ?:, que engole 0 e ''
Se uma string tem conteúdo trim($x) !== '' empty() rejeita '0'
Se um array tem itens $arr === [] ou count($arr) === 0 empty() funciona aqui, mas seja explícito
Se um número foi informado is_numeric($x) Nunca empty() em campo numérico

A regra que evita 90% dos problemas: empty() só é seguro quando 0 e '' significam de fato "vazio" para o seu caso — o que raramente acontece com dados de formulário. Nas outras situações, escreva a condição que você realmente quer testar. Código explícito é mais longo e infinitamente mais fácil de depurar.

no manualBooleans

Os valores que o PHP considera falsos são a base de tudo o que o empty() faz. Entender a tabela de conversão para booleano (por que '0' é falso e '0.0' é verdadeiro) resolve a categoria inteira de bugs.

estudar na árvore →
no manualArrays

Chaves de array, valores null e a diferença entre "a chave não existe" e "a chave existe vazia" são conceitos de array — a página do tipo cobre as regras completas de acesso e existência.

estudar na árvore →

Leve o estudo além do artigo

O manual inteiro do PHP como uma jornada: progresso por tópico, anotações e leitura embutida.