← Voltar aos artigos

operadores · precedência · lógica · sintaxe

Qual a diferença entre && e "and" no PHP (a pegadinha da precedência)

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

&& e and produzem exatamente a mesma lógica — os dois são "E". A diferença está na precedência: and e or têm prioridade menor que o =, enquanto && e || têm prioridade maior. A consequência é esta, e ela é real:

$r1 = true and false;
var_dump($r1);   // bool(true)   ← ?!

$r2 = true && false;
var_dump($r2);   // bool(false)  ← o esperado

A primeira linha não guarda o resultado do "E" — ela guarda true. O PHP não emite aviso nenhum, o código roda, e a condição que depende de $r1 toma a decisão errada. A regra prática é curta: use sempre && e ||. Mas vale entender por que isso acontece, onde a pegadinha morde (é mais restrito do que se costuma dizer) e por que essa precedência estranha existe de propósito.

O mecanismo: onde cada operador fica na fila

Precedência é a ordem em que o PHP agrupa as partes de uma expressão — o mesmo princípio de 2 + 3 * 4 valer 14 e não 20, porque * vem antes de +. A tabela do PHP, do mais forte para o mais fraco, tem esta fatia relevante:

!                    ← negação (bem no topo)
* / %
+ -
< > <= >=
== != === !==
&&                   ← E "forte"
||                   ← OU "forte"
??
? :
=  +=  -=  ...       ← ATRIBUIÇÃO
and                  ← E "fraco"
xor
or                   ← OU "fraco"

Repare que o = fica entre os dois grupos. É isso e nada mais. Quando o PHP encontra $r = true and false, ele agrupa primeiro o que é mais forte — e o = é mais forte que o and:

O que você escreveu

Sua intenção era: calcular true and false e guardar o resultado.

$r = true and false;

Como o PHP agrupa

Como = tem precedência maior que and, a atribuição é resolvida primeiro. É como se houvesse parênteses invisíveis aqui:

($r = true) and false;

O que acontece na prática

$r recebe true. Só depois o and compara o resultado da atribuição (true) com false — e joga esse resultado fora, porque ninguém o guarda.

$r = true;          // a atribuição aconteceu
true and false;     // calculado e descartado
var_dump($r);       // bool(true)

Com && o agrupamento é o oposto

&& tem precedência maior que =, então a lógica é resolvida primeiro e o resultado é atribuído.

$r = (true && false);   // parênteses invisíveis aqui
var_dump($r);           // bool(false)

O conserto quando você quer manter o and

Parênteses explícitos resolvem, porque forçam a ordem. Mas se você precisa de parênteses para o código ficar correto, mais simples é usar &&.

$r = (true and false);   // bool(false) — funciona
$r = true && false;      // bool(false) — melhor

O mesmo vale para or, com um resultado igualmente surpreendente:

$r = false or true;
var_dump($r);   // bool(false)  ← agrupou como ($r = false) or true
evite
$temPermissao = $usuario->ativo and $usuario->admin;
// vira: ($temPermissao = $usuario->ativo) and $usuario->admin
// $temPermissao só reflete "ativo" — o admin é ignorado!

if ($temPermissao) {
    liberarPainelAdmin();   // usuário comum ativo entra
}
prefira
$temPermissao = $usuario->ativo && $usuario->admin;
// agora sim: as duas condições contam

if ($temPermissao) {
    liberarPainelAdmin();
}

Onde a pegadinha não morde

Aqui está a parte que quase todo artigo sobre o assunto erra — e que evita você sair "consertando" código correto. O problema só aparece quando há um operador de precedência intermediária entre os dois lados, e na prática isso significa: atribuição. Nestes dois lugares, and e && são intercambiáveis:

// 1. dentro de um if — equivalentes
if ($a and $b) { }     // idêntico a
if ($a && $b) { }      // este

// 2. em um return — equivalentes
function f(): bool { return true and false; }   // devolve false
function g(): bool { return true && false; }    // devolve false

No if, não existe atribuição competindo pela precedência: a condição inteira é avaliada. No return, a instrução recebe a expressão completareturn não é um operador que dispute a fila, então true and false é calculado inteiro antes de voltar. Testado nas duas formas: o resultado é false em ambas.

Ou seja: se você encontrar if ($a and $b) num código legado, ele está correto — só não é o estilo recomendado. O que precisa de revisão urgente é $x = ... and ... e $x = ... or ....

Por que essa precedência esquisita existe?

Não é acidente nem herança mal resolvida: é um recurso deliberado, e conhecê-lo faz o resto fazer sentido. A precedência baixa do or permite o idioma clássico de tratamento de erro, herdado do Perl:

$recurso = abrirArquivo('dados.txt') or die('Falhou ao abrir');

Aqui o comportamento "estranho" é exatamente o desejado: $recurso recebe o valor útil retornado pela função (o handle do arquivo), e o or die(...) só dispara se esse valor for falsy. Com || o resultado seria outro — e inútil:

$recurso = abrirArquivo('dados.txt') or  die('...');   // $recurso = handle
$recurso = abrirArquivo('dados.txt') || die('...');    // $recurso = true (!)

Com ||, a expressão lógica inteira é resolvida antes da atribuição, e o que sobra é um booleano — você perde o handle e fica com um true inútil. Esse é o único caso em que a precedência baixa trabalha a seu favor, e mesmo assim o idioma é considerado datado hoje: com exceções e try/catch, o tratamento de erro moderno é mais explícito. Mas ele explica por que os dois conjuntos de operadores existem lado a lado.

O que este código imprime?

$ativo = true;
$admin = false;
$acesso = $ativo and $admin;
var_dump($acesso);
Ver resposta

Resposta certa: bool(true)$acesso recebe só o valor de $ativo

Como = tem precedência maior que and, o PHP agrupa como ($acesso = $ativo) and $admin. O $acesso recebe true (o valor de $ativo) e o and com $admin é calculado e descartado. Num sistema real, isso é uma falha de autorização: um usuário ativo, mas não administrador, passa na checagem. Trocar and por && corrige — e é por isso que a recomendação é usar &&/|| sempre.

Diagnóstico: caçar o padrão no código existente

Se você suspeita que esse bug já está no seu projeto, o alvo é bem específico — uma atribuição com and/or do lado direito:

grep -rnE '=[^=]+\b(and|or)\b' --include='*.php' .

O comando gera falsos positivos (strings, comentários, nomes com "and"), mas a lista é curta e a inspeção é rápida. Para cada ocorrência, o teste mental é único: envolva o lado direito em parênteses e veja se o resultado muda. Se mudar, você achou um bug real:

$x = $a and $b;      // valor atual
$x = ($a and $b);    // valor correto — se diferem, o original está errado

Ferramentas de análise estática (PHPStan, Psalm) e o PHP_CodeSniffer com o padrão PSR-12 apontam esse caso automaticamente — vale ligar um deles no projeto e nunca mais pensar no assunto.

Resumo de decisão

Situação Comportamento Recomendação
$x = $a && $b; Lógica primeiro, depois atribui ✅ Use sempre
$x = $a and $b; Atribui $a, depois calcula e descarta ❌ Bug silencioso
if ($a and $b) Idêntico a && Correto, mas prefira &&
return $a and $b; Idêntico a && Correto, mas prefira &&
$x = ($a and $b); Parênteses corrigem Funciona — && é mais simples
$r = f() or die(); Guarda o valor de f() Idioma antigo; hoje, exceções
&& e or na mesma expressão Resultado imprevisível Reescreva

Em uma frase: and/or ficam abaixo do = na fila, &&/|| ficam acima — e como só a atribuição fica no meio, é lá (e só lá) que a escolha errada vira bug.

no manualLogic

A página dos operadores lógicos mostra os dois conjuntos lado a lado (&&/and, ||/or, xor) e por que a linguagem mantém as duas formas — inclusive o comportamento de curto-circuito, que vale para ambas.

estudar na árvore →
no manualOperator Precedence

A tabela oficial de precedência é a referência que resolve qualquer dúvida desse tipo, não só a de and vs &&. Vale marcar: ela explica também ??, ? : e a associatividade de cada operador.

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.