PHP Comparação (== e ===)

Comparar é fazer uma pergunta de "sim ou não": a nota é maior que 7? A senha digitada é a certa? O estoque acabou? Os operadores de comparação fazem essas perguntas e respondem true ou false. O PHP tem dois jeitos de perguntar "é igual?": o == e o ===. Entender a diferença entre eles é uma das lições mais importantes do PHP, porque o == tem surpresas que já causaram falhas de segurança de verdade.

Você vai aprender
  • A diferença entre == ("igual", converte os tipos) e === ("idêntico", compara também o tipo).
  • As surpresas reais do ==: "1" == "01", "10" == "1e1", null == false, senhas que começam com 0e… e o que mudou do PHP 7 para o PHP 8.
  • Os operadores de diferença: !=, <> e !==.
  • Maior e menor (<, >, <=, >=), inclusive com textos e acentos.
  • O operador nave espacial <=>.
  • A regra que evita as surpresas: use ===.

Antes, é bom ter visto Tipos de Dados e Booleanos. Os resultados aparecem com o var_dump, que mostra bool(true) ou bool(false).


A ideia: "parecido" × "idêntico"

Pense em R$ 10 em dinheiro e R$ 10 no Pix. Têm o mesmo valor? Sim. São a mesma coisa? Não: um é papel na carteira, o outro é um número no banco. Depende da pergunta: "dá para pagar um lanche de R$ 10?" (sim, com os dois) ou "é uma nota de papel?" (só um deles).

O PHP tem as duas perguntas:

  • == (dois iguais) pergunta "têm o mesmo valor?". Se os tipos forem diferentes, ele converte um deles antes de comparar. Chama-se igualdade (ou comparação "frouxa").
  • === (três iguais) pergunta "têm o mesmo valor e o mesmo tipo?". Não converte nada. Chama-se identidade (ou comparação "estrita").
Um =, dois ==, três ===

O = sozinho não compara: ele guarda um valor numa variável (veja Operadores de Atribuição). Trocar == por = é um dos erros mais comuns de quem começa; ele aparece na seção Quando dá errado.


== e === na prática

<?php
$idade = 29;
var_dump($idade == 29);
var_dump($idade == 30);
var_dump($idade == "29");
var_dump($idade === "29");
var_dump($idade === 29);
$ php igual.php
bool(true)
bool(false)
bool(true)
bool(false)
bool(true)
$idade == 29
O número 29 é igual ao número 29: true.
$idade == 30
Valores diferentes: false.
$idade == "29"
De um lado o número 29 (int), do outro o texto "29" (string). O == converte o texto em número e compara: true.
$idade === "29"
O === vê tipos diferentes (int × string) e responde false na hora, sem converter.
$idade === 29
Mesmo tipo e mesmo valor: true.

Até aqui, o == parece até mais "esperto": ele entendeu que 29 e "29" são o mesmo número. O problema é que essa conversão automática às vezes faz coisas que ninguém espera.


As surpresas do ==

Quando os dois lados são textos que parecem números, o == compara como números. Quando um lado é número e o outro é texto, ou um lado é null ou booleano, ele também converte. Veja o PHP 8.5 respondendo:

<?php
var_dump(0 == "a");
var_dump("1" == "01");
var_dump("10" == "1e1");
var_dump(100 == "1e2");
var_dump(null == false);
var_dump(0 == "");
var_dump("abc" == 0);
var_dump(null == 0);
var_dump("0" == false);
var_dump("" == null);
var_dump([] == false);
var_dump("1" == " 1");
var_dump("1" == "1 ");
var_dump(1 == "1 ");
var_dump(1.0 == 1);
var_dump(1.0 === 1);
var_dump("abc" == "ABC");
$ php surpresas.php
bool(false)
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)

A tabela abaixo explica as principais. A coluna "PHP 7" mostra como era antes do PHP 8.0, que mudou as regras de comparação entre números e textos (essa coluna vem da documentação oficial; o laboratório deste guia roda só o PHP 8.5).

Comparação== no PHP 8.5No PHP 7===Por quê
0 == "a"falsetruefalseNo PHP 7, o texto "a" virava o número 0. Desde o PHP 8.0, se o texto não é numérico, o número é que vira texto: "0" == "a", falso.
"abc" == 0falsetruefalseA mesma mudança.
0 == ""falsetruefalseA mesma mudança: texto vazio não é numérico.
"1" == "01"truetruefalseOs dois textos parecem números, então são comparados como números: 1 = 1.
"10" == "1e1"truetruefalse"1e1" é notação científica: 1 × 10¹ = 10.
100 == "1e2"truetruefalse"1e2" = 1 × 10² = 100.
null == falsetruetruefalseO null é convertido para booleano: vale false.
null == 0truetruefalseOs dois "valem falso".
"0" == falsetruetruefalseO texto "0" vale false (veja Booleanos).
"" == nulltruetruefalseTexto vazio e "nada" são considerados iguais.
[] == falsetruetruefalseArray vazio vale false.
1.0 == 1truetruefalseMesmo valor, tipos diferentes (float × int).
"abc" == "ABC"falsefalsefalseMaiúsculas e minúsculas são letras diferentes.

O PHP 8 consertou as piores surpresas (0 == "a" ser verdadeiro causava falhas graves). Mas as outras continuam valendo, e elas aparecem em situações bem reais.

Surpresa na lojinha: códigos com zero à esquerda

Os produtos da lojinha da Ana têm códigos de texto. O código do caderno é "7", mas o cliente digitou "007":

<?php
$codigoProduto = "7";
$codigoDigitado = "007";

$mesmoProduto = $codigoDigitado == $codigoProduto;
var_dump($mesmoProduto);
$ php codigo.php
bool(true)

Os dois são textos, mas como "parecem números", o == comparou 7 com 7. Para códigos, CEPs, telefones e CPFs, o zero à esquerda faz diferença: "007" e "7" são códigos diferentes.

Missão: troque a comparação para que "007" e "7" sejam considerados códigos diferentes. O resultado deve ser bool(false). Depois, troque "007" por "7" e confira que dá true.

<?php
$codigoProduto = "7";
$codigoDigitado = "007";

$mesmoProduto = $codigoDigitado == $codigoProduto;
var_dump($mesmoProduto);
<?php
$codigoProduto = "7";
$codigoDigitado = "007";

$mesmoProduto = $codigoDigitado === $codigoProduto;
var_dump($mesmoProduto);

Surpresa na segurança: senhas que começam com 0e

Um texto como "0e1234" parece um número em notação científica: 0 × 101234, que é zero. Qualquer outro "0e…" só com algarismos depois também vale zero. Então:

<?php
$senhaCerta = "0e5678";
$senhaDigitada = "0e1234";
var_dump($senhaDigitada == $senhaCerta);
var_dump($senhaDigitada === $senhaCerta);
$ php senha.php
bool(true)
bool(false)

Com ==, a senha errada foi aceita! Isso não é teoria: sistemas reais compararam códigos de senha (os "hashes", veja Senhas) com == e foram invadidos assim. Com ===, os textos são comparados letra por letra, e a senha errada é recusada.

Surpresa com funções: o zero que não é "falso"

Algumas funções do PHP devolvem um número ou false. A strpos ("posição no texto", da aula Funções de String) diz em que posição um pedaço aparece, contando do zero, e devolve false se não encontrar:

<?php
$nome = "Ana Souza";
var_dump(strpos($nome, "A"));
var_dump(strpos($nome, "A") == false);
var_dump(strpos($nome, "A") === false);
var_dump(strpos($nome, "Z"));
$ php strpos.php
int(0)
bool(true)
bool(false)
bool(false)

O "A" está na posição 0 (a primeira). Mas 0 == false é verdadeiro, então a pergunta "não encontrou?" com == respondeu sim, errado. Com ===, só o false de verdade conta como "não encontrou". (O último bool(false) é a strpos dizendo que não há "Z" maiúsculo no nome.)


A regra: use ===

O === não tem nenhuma das surpresas acima: ele só diz true quando os dois lados são exatamente a mesma coisa, do mesmo tipo. Por isso a recomendação de quase todo guia de estilo de PHP é:

Regra de ouro

Compare com === e !==. Use == só quando você quer a conversão e sabe exatamente o que ela faz.

O preço do === é que você precisa cuidar dos tipos. O exemplo clássico são os dados de formulário: tudo o que vem do navegador chega como texto (veja $_GET e $_POST). Converta antes de comparar (veja Conversão de Tipos):

<?php
$idadeDigitada = "29";
var_dump($idadeDigitada === 29);
var_dump((int) $idadeDigitada === 29);
$ php form.php
bool(false)
bool(true)

O (int) transforma o texto "29" no número 29; depois disso, o === compara número com número. Assim a conversão fica visível no código, e não escondida dentro do ==.

E os números com vírgula?

Nem == nem === resolvem um problema dos float: 0.1 + 0.2 == 0.3 dá false, porque o computador guarda 0.1 e 0.2 com um errinho minúsculo. A aula int e float explica e mostra como comparar dinheiro.


Diferente: !=, <> e !==

Cada pergunta de igualdade tem a sua pergunta oposta:

  • != é o contrário de ==: "têm valores diferentes?" (com conversão). O <> é outra forma de escrever exatamente o mesmo.
  • !== é o contrário de ===: "não são idênticos?" (diferentes no valor ou no tipo).
<?php
$senha = "1234";
var_dump($senha != "1234");
var_dump($senha <> "1234");
var_dump($senha != 1234);
var_dump($senha !== 1234);
var_dump($senha !== "1234");
$ php diferente.php
bool(false)
bool(false)
bool(false)
bool(true)
bool(false)
$senha != "1234"
Os valores são iguais, então "diferente?" é false.
$senha <> "1234"
Igual ao !=. Existe por tradição (outras linguagens e o SQL usam <>); no PHP, prefira != ou, melhor, !==.
$senha != 1234
Texto × número: o != converte, acha "iguais" e responde false.
$senha !== 1234
Tipos diferentes, então não são idênticos: true.
$senha !== "1234"
Mesmo tipo e mesmo valor: são idênticos, então "não idênticos?" é false.

Maior e menor: <, >, <=, >=

<?php
$nota = 7;
var_dump($nota > 7);
var_dump($nota >= 7);
var_dump($nota < 5);
var_dump($nota <= 10);
var_dump("10" < "9");
var_dump(10 < 9);
var_dump("abacaxi" < "banana");
var_dump("Banana" < "abacaxi");
var_dump("maçã" < "mamão");
var_dump("10" < "9a");
$ php maior.php
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)
bool(false)
bool(true)
ComparaçãoResultadoPor quê
$nota > 7false7 não é maior que 7.
$nota >= 7true"Maior ou igual": 7 conta. Escreve-se >=, nunca => (que é outra coisa, usada em arrays).
"10" < "9"falseOs dois textos parecem números, então o PHP compara 10 com 9.
"abacaxi" < "banana"trueTextos comuns são comparados letra por letra, como no dicionário: a vem antes de b.
"Banana" < "abacaxi"truePara o computador, todas as maiúsculas vêm antes das minúsculas. O B maiúsculo "ganha" do a minúsculo.
"maçã" < "mamão"falseLetras acentuadas vêm depois de todas as letras sem acento. No dicionário, "maçã" vem antes de "mamão"; para o PHP, o ç vem depois do m.
"10" < "9a"true"9a" não é número, então a comparação é de texto: o caractere 1 vem antes do 9.

Para comparar números, < e > funcionam como na escola. Para colocar palavras em ordem alfabética do jeito que um brasileiro espera (maiúsculas junto com minúsculas, acentos no lugar certo), há funções próprias, que aparecem em Ordenar Arrays.


A nave espacial <=> PHP 7.0+

O operador <=> tem esse apelido porque lembra uma navezinha. Em vez de true/false, ele responde com um número, dizendo de que lado está o maior:

<?php
var_dump(1 <=> 2);
var_dump(2 <=> 2);
var_dump(3 <=> 2);
var_dump("Ana" <=> "Bia");
var_dump(7.5 <=> 7);
$ php nave.php
int(-1)
int(0)
int(1)
int(-1)
int(1)
$a <=> $b devolveQuando
-1$a é menor que $b
0são iguais (no sentido do ==)
1$a é maior que $b

Para que serve uma resposta com três valores? Para ordenar: as funções de ordenação perguntam "este vem antes, depois, ou tanto faz?", e o <=> responde exatamente isso numa conta só. Você vai usá-lo em Ordenar Arrays.

Laboratório livre: teste as suas próprias comparações. Antes de rodar, escreva num papel o que você acha que cada linha vai mostrar. Experimente "1e3" == "1000", "0.0" == "0", "Ana" <=> "ana"…

<?php
var_dump("1e3" == "1000");
var_dump("1e3" === "1000");
var_dump("0.0" == "0");
var_dump(null == "");
var_dump(null === "");
var_dump("Ana" <=> "ana");
var_dump(10 >= 10.0);

Quando dá errado

A comparação mudou a variável (um = só)
<?php
$nota = 7;
var_dump($nota = 10);
var_dump($nota);
$ php atribuir.php
int(10)
int(10)

O que aconteceu: a ideia era perguntar "a nota é 10?", mas com um = o PHP guardou 10 na variável. Não há erro nem aviso: é uma atribuição válida. A nota da Ana virou 10 sem ninguém perceber.

Como resolver: para comparar, === (ou ==). Leia em voz alta: = é "recebe", === é "é idêntico a".

Parse error: syntax error, unexpected token "=="
$ php tresiguais.php

Parse error: syntax error, unexpected token "==" in /home/ana/site/tresiguais.php on line 3

O que aconteceu: a linha era var_dump($a = == 1);, com um espaço no meio do ===. Os iguais precisam estar colados: ===, !==, <=, >=, <=>. O mesmo erro (unexpected token) aparece se você encadear comparações, como 1 < $x < 10 (veja Precedência).

Como resolver: junte os sinais: var_dump($a === 1);.

Duas coisas diferentes foram consideradas iguais
$ php senha.php
bool(true)
bool(false)

O que aconteceu: o == converteu os valores antes de comparar (códigos com zero à esquerda, "0e…", "1e2", null × 0 × false × "").

Como resolver: troque por ===. Se os tipos forem diferentes de propósito (texto de formulário × número), converta antes, de forma visível: (int) $idadeDigitada === 29.

Encontrou na posição 0, mas o programa disse "não encontrou"
$ php strpos.php
int(0)
bool(true)
bool(false)
bool(false)

O que aconteceu: a função devolveu 0 (a primeira posição), e 0 == false é verdadeiro.

Como resolver: compare com === false ou !== false. Sempre que a documentação de uma função disser "devolve false se falhar", use comparação estrita.

A ordem alfabética saiu estranha
$ php maior.php
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)                « "Banana" < "abacaxi"
bool(false)               « "maçã" < "mamão"
bool(true)

O que aconteceu: < e > comparam textos pelo código de cada caractere: maiúsculas antes de minúsculas, acentuadas depois de todas.

Como resolver: para comparar sem ligar para maiúsculas, converta os dois lados com mb_strtolower (veja Acentos e mbstring). Para ordenar listas de palavras em português, veja Ordenar Arrays.


Referência

OperadorNomeDá true quando…Converte os tipos?
$a == $bIgualos valores são iguais depois da conversãosim
$a === $bIdênticomesmo valor e mesmo tiponão
$a != $bDiferenteos valores são diferentes depois da conversãosim
$a <> $bDiferenteigual ao !=sim
$a !== $bNão idênticovalor ou tipo diferentenão
$a < $bMenor$a é menor que $bsim
$a > $bMaior$a é maior que $bsim
$a <= $bMenor ou igual$a é menor ou igual a $bsim
$a >= $bMaior ou igual$a é maior ou igual a $bsim
$a <=> $bNave espacial(devolve -1, 0 ou 1)sim

Não existe <== nem >==: para "maior/menor" sem conversão, garanta antes que os dois lados têm o mesmo tipo.


Exercícios

1. Idêntico

Complete para comparar valor e tipo:

var_dump($codigo "007");

2. Não encontrou

Complete para perguntar, sem cair na armadilha do zero, se a strpos não encontrou o texto:

var_dump(strpos($nome, "A") );

3. Aprovada

Complete para dar true se a nota for 7 ou mais:

var_dump($nota );

4. No PHP 8.5, o que var_dump("1" == "01"); mostra?

5. Qual comparação mudou de resultado do PHP 7 para o PHP 8?

6. Quanto vale 5 <=> 9?

7. Depois de $nota = 7; var_dump($nota = 10);, quanto vale $nota?

Missão final: três comparações perigosas

Missão: as três respostas abaixo estão erradas: todas mostram true, e todas deveriam ser false (a senha está errada, o código é outro e o estoque é zero, não null). Conserte as comparações para o programa mostrar bool(false) três vezes.

<?php
// 1. A senha digitada é igual à senha certa?
$senhaCerta = "0e5678";
$senhaDigitada = "0e1234";
var_dump($senhaDigitada == $senhaCerta);

// 2. O código digitado é o mesmo do produto?
$codigoProduto = "100";
$codigoDigitado = "1e2";
var_dump($codigoDigitado == $codigoProduto);

// 3. O estoque está sem valor (null)?
$estoque = 0;
var_dump($estoque == null);
<?php
// 1. A senha digitada é igual à senha certa?
$senhaCerta = "0e5678";
$senhaDigitada = "0e1234";
var_dump($senhaDigitada === $senhaCerta);

// 2. O código digitado é o mesmo do produto?
$codigoProduto = "100";
$codigoDigitado = "1e2";
var_dump($codigoDigitado === $codigoProduto);

// 3. O estoque está sem valor (null)?
$estoque = 0;
var_dump($estoque === null);

Resumo

  • == compara valores convertendo os tipos; === compara valor e tipo, sem converter.
  • O == acha iguais "1" e "01", "10" e "1e1", "0e1234" e "0e5678", null e false, 0 e null.
  • O PHP 8 consertou 0 == "a" (era true no PHP 7), mas as outras surpresas continuam.
  • Regra: use === e !==. Converta dados de formulário antes: (int) $idade === 29.
  • != e <> são o contrário de ==; !== é o contrário de ===.
  • < e > com textos: maiúsculas antes de minúsculas, acentos depois de tudo.
  • $a <=> $b devolve -1, 0 ou 1; serve para ordenar.
  • Um = só guarda, não compara.