O operador de coalescência nula tem um precedente que é diferente da maioria dos outros comparadores em PHP:
Exemplo 1:
(Incorreto)
$var['x'] = "5";
if ((int)$var['x']??0 < 1 ) {
print "less than 1"; /* outputs this */
}
else {
print "more than 1";
}
Isso resultará em " less
" porque a comparação parece ser entre $var['x']
vs 0<1
, mas certamente seria, o $var['x']??(false)
que ainda não me parece garantir que isso if
seja verdade.
Exemplo 2:
(Incorreto)
$var['x'] = "5";
if ($var['x']??5 < 1 ) {
print "less than 1"; /* still outputs this */
}
else {
print "more than 1";
}
Eu ENTENDO a saída esperada; mas NÃO entendo os passos que o PHP toma para chegar à conclusão escolhida.
Li https://www.php.net/manual/en/language.operators.precedence.php e PHP short-ternary operator ("Elvis") vs null coalescing operator, mas eles não descrevem explicitamente o raciocínio para o que percebo ser um comportamento inesperado nos exemplos 1 e 2.
Quais etapas de processamento lógico fazem com que isso funcione dessa maneira?
Exemplo 3:
( Correto )
$var['x'] = "5";
if ((int)($var['x']??0) < 1 ) {
print "less than 1";
}
else {
print "more than 1";
}
Isso resultará na more
saída " " correta.
A questão-chave aqui é a precedência do operador. Em PHP, tanto o operador de conversão
(int)
quanto o operador de comparação<
têm uma precedência maior do que o operador de coalescência nulo??
. Isso significa que no seu primeiro exemploO PHP interpreta a expressão como se você tivesse escrito:
Veja o que acontece passo a passo:
Casting:
(int)$var['x']
é avaliado primeiro, convertendo a string"5"
para o inteiro5
.Comparação: O
<
operador é avaliado em seguida. Como<
tem uma precedência maior que??
, a expressão0 < 1
é computada, produzindotrue
.Coalescência Nula: Agora o PHP avalia
5 ?? true
. Como5
não énull
, o resultado do operador de coalescência nula é5
.Verificação de condição: Em uma
if
declaração, um número diferente de zero é verdadeiro, então a condição é avaliada comotrue
, e "menor que 1" é impresso.No Exemplo 2, ocorre uma interpretação errônea semelhante:
Isto é interpretado como:
Como
$var['x']
is"5"
(um valor não nulo), o operador coalescente nulo retorna"5"
. Em PHP, uma string não vazia (diferente de"0"
) é verdadeira, então a condição é verdadeira, e "less" é impresso.No Exemplo 3, você força a ordem pretendida adicionando parênteses.
Aqui, a expressão dentro dos parênteses
$var['x']??0
é avaliada primeiro. Como$var['x']
exists, ela retorna"5"
, que é então convertido para5
. A comparação5 < 1
avalia corretamente parafalse
, então "mais de 1" é impresso.O comportamento inesperado surge porque, sem o agrupamento adequado, o PHP avalia o cast e a comparação antes de aplicar o operador de coalescência nulo. Adicionar parênteses explícitos esclarece a ordem das operações e garante que a expressão seja avaliada conforme o pretendido.