if ('constante' == $ variável) vs. if ($ variável == 'constante')

49

Ultimamente, tenho trabalhado muito em PHP e especificamente dentro da estrutura do WordPress. Estou percebendo muito código na forma de:

if ( 1 == $options['postlink'] )

Onde eu esperava ver:

if ( $options['postlink'] == 1 )

Esta convenção foi encontrada em certos idiomas / estruturas? Existe alguma razão para a primeira abordagem ser preferível à segunda (de uma perspectiva de processamento, de uma perspectiva de análise ou de uma perspectiva humana?)

Ou é apenas uma questão de gosto? Sempre achei melhor, ao executar um teste, que o item variável sendo testado em relação a alguma constante estivesse à esquerda. Parece mapear melhor a maneira como faríamos a pergunta em linguagem natural: "se o bolo é chocolate" em vez de "se o chocolate é o bolo".

Tom Auger
fonte
11
Eu nunca escrevo códigos assim, mas para ser justo "se o chocolate é o sabor do bolo", soa natural. A linguagem natural é mais flexível.
Rick Sladkey 5/05
4
@ Rick Pode parecer natural na linguagem, mas você não pode negar que, quando vê um código como esse, precisa parar primeiro (talvez apenas por um segundo) para pensar no que está tentando fazer.
Edgar Gonzalez
4
@ Edgar Gonzalez: Concordo, sou firmemente contra isso no código.
Rick Sladkey
3
O Capítulo 19 do Code Complete 2nd Edition (na seção "Expressões booleanas: problemas comuns com expressões booleanas") recomenda realmente essa prática pelo motivo exato indicado em muitas das respostas aqui: para impedir a atribuição em idiomas derivados de C quando a comparação foi feita .
CraigTP
4
Eu sempre vi isso conhecido como "Condições Yoda"
Brian

Respostas:

84

O principal motivo para fazer isso (chamado "condicional de Yoda") é evitar acidentes nos quais você acidentalmente usa um operador de atribuição ( =) em vez do operador de comparação igual ( ==).

Ou seja, se você cometeu o erro de fazer:

$foo = 5;
if ($foo = 1) {
  // Stuff
}

A declaração será avaliada como true(ou, no caso de algumas linguagens - como PHP - um valor verdadeiro) e você terá um erro difícil de encontrar.

Mas se você fez:

$foo = 5;
if (1 = $foo) {
  // Stuff
}

Você receberá um erro fatal porque não pode atribuir $fooa um número inteiro.

Mas, como você apontou, reverter a ordem geralmente torna as coisas menos legíveis. Portanto, muitos padrões de codificação (mas não todos, incluindo o WordPress ) sugerem ou exigem, $foo == 1apesar dos benefícios da caça aos bugs 1 == $foo.

Geralmente, meu conselho é seguir qualquer padrão de codificação estabelecido, se houver: para o WordPress, isso significa usar condicionais Yoda.

Quando não existe, e é impossível estabelecer um consenso com seus colegas, a escolha é do revendedor.

Átila
fonte
2
Lembro-me, ao projetar uma linguagem (há muito tempo), que fizemos especificamente :=o operador de atribuição (com ==teste de igualdade) para evitar esse tipo de problema.
Donal Fellows
7
Escrevi muitas, muitas linhas de código e nunca digitei acidentalmente em =vez de ==. A diferença é tão acentuada em todos os lugares que eu nunca os confundi. Por outro lado, eu li muitos trechos de código que são confusos ou difíceis de entender. Como tal, eu colocaria as prioridades na legibilidade :). Independentemente, boa resposta.
Crazy2be
5
Outro bom motivo para usar -Wall -Werrorou o equivalente do seu compilador / intérprete. Existem muito poucas situações em que uma atribuição dentro de uma condição está correta, quanto mais legível. Muitos idiomas nem permitem.
Karl Bielefeldt
7
Pedante: Embora seja if($foo = 1)avaliado trueem algumas linguagens, no PHP ele é avaliado como 1; if($foo = 20)avalia para 20; if($foo = 0)avalia como 0, o que, diferentemente dos outros, é falso. Isso pode adicionar uma camada completa de complexidade ao bug.
Charles
2
Na verdade, o WordPress Padrões de Codificação põe para Yoda Condicionais: codex.wordpress.org/WordPress_Coding_Standards#Yoda_Conditions
Tom Auger
13

É um mecanismo de codificação defensivo destinado a impedir o uso acidental do operador de atribuição.

Considere um uso indevido / erro do operador de atribuição no lugar do operador de igualdade

if ( $options['postlink'] = 1  )

O condicional acima sempre retornaria verdadeiro, mas provavelmente não é o que o programador original tinha em mente. Considere, em seu lugar, este

if( 1 = $options['postlink'])

Aqui, o PHP (e a maioria das outras linguagens) se recusaria a executar, pois é impossível atribuir qualquer coisa ao valor fixo de 1. Ao codificar todas as instruções condicionais dessa maneira, você garante automaticamente nenhum uso acidental de um operador de atribuição em uma condicional.

Alan Storm
fonte
9

Eu gosto de usar essa convenção em java para remover a possibilidade de uma exceção de ponteiro nulo. Portanto, algo assim não causará problemas ou precisará de código extra:

String foo = null;

if ("bar".equals(foo))
{
    //Do something
}
Ben Newman
fonte
3
Eu gosto disso, mas odeio o idioma geral.
Thomas Eding
3
Se um valor nulo não for válido nesse ponto do código, você já deve ter verificado isso de qualquer maneira ou projetado seu código de tal maneira que um valor nulo seria impossível.
Ed S.
6
essa parece ser uma maneira fácil de mascarar problemas. As poeiras não são limpas encolhendo-as dentro do tapete.
Lie Ryan
0

Na prática, muitos compiladores lhe darão um aviso se você escrever "if (x = 1)" em vez de "if (x == 1)" porque provavelmente é um erro.

Com o Clang, você pode evitar o aviso dizendo efetivamente ao compilador "Eu quero dizer isso e sei o que estou fazendo", e isso é feito escrevendo "if ((x = 1))". Observe os parênteses extras. Isso funciona em outras situações também. declaração if (falsa); pode avisar que a instrução nunca é executada; declaração if ((false)); não dá esse aviso.

gnasher729
fonte
Eu gosto muito disso! Evito o seguinte idioma completamente legítimo no PHP porque sempre recebo avisos no meu IDE:if ($array = getSomething()){ // ..so something with $array }
Tom Auger