Como os operadores de comparação de igualdade (== duplo é igual) e identidade (=== triplo é igual) PHP diferem?

Qual é a diferença entre == e === ?

  • Como exatamente a comparação frouxa funciona?
  • Como exatamente funciona a comparação estrita === ?

Quais seriam alguns exemplos úteis?

Diferença entre == e ===

A diferença entre o operador loose == equal e o operador strict === idêntico é explicada exatamente no manual :

Operadores de Comparação

 ┌──────────────────────┬────────────────────────── ─────────────────────────────────┐
 │ Exemplo │ Nome │ Resultado │
 ├──────────────────────┼────────────────────────── ─────────────────────────────────┤
 │ $ a == $ b │ Igual a │ TRUE se $ a for igual a $ b após o tipo de malabarismo.  │
 │ $ a === $ b │ Idêntico │ TRUE se $ a for igual a $ b, e eles forem do mesmo tipo.  │
 └──────────────────────┴────────────────────────── ─────────────────────────────────┘

Vagamente == comparação igual

Se você estiver usando o operador == , ou qualquer outro operador de comparação que use uma comparação frouxa, como != , <> Ou == , você sempre terá que olhar o contexto para ver o que, onde e porque algo é convertido para entender o que está acontecendo.

Convertendo Regras

  • Convertendo para booleano
  • Convertendo para inteiro
  • Convertendo para flutuar
  • Convertendo para string
  • Convertendo para array
  • Convertendo para Objeto
  • Convertendo para Recurso
  • Convertendo para NULL

Tabela de comparação de tipos

Como referência e exemplo, você pode ver a tabela de comparação no manual :

Comparações frouxas com ==

  ┌─────────────────────────────────────────┬─────── ┬───────────────────────────────┬─────────┬─────── ┬───────┐
 │ │ VERDADEIRO │ FALSO │ 1 │ 0 │ -1 │ "1" │ "0" │ "-1" │ NULL │ matriz () │ "php" │ "" │
 ├─────────────────────────────────────────┼─────── ┼───────────────────────────────┼─────────┼─────── ┼───────┤
 Verdadeiro Verdadeiro Falso Verdadeiro Falso Verdadeiro Verdadeiro Falso Verdadeiro Falso Falso Verdadeiro Falso
 │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ VERDADEIRO │ FALSO │ VERDADEIRO │
 │ 1 │ VERDADEIRO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 │ 0 │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ VERDADEIRO │
 │ -1 │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │
 1 "1" │ TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE.
 │ "0" │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 -1 "-1" │ TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE.
 │ NULO │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ VERDADEIRO │ FALSO │ VERDADEIRO │
 │ matriz () │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ VERDADEIRO │ FALSO │ FALSO │
 Ph "php" │ TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE.
 │ "" │ FALSO │ VERDADEIRO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ VERDADEIRO │
 └─────────────────────────────────────────┴─────── ┴───────────────────────────────┴─────────┴─────── ┴───────┘

Estrito === comparação idêntica

Se você estiver usando o operador === , ou qualquer outro operador de comparação que use comparação estrita como !== ou === , então você pode sempre ter certeza de que os tipos não serão alterados magicamente , porque não haverá conversão indo. Portanto, com comparação estrita, o tipo e o valor devem ser os mesmos, não apenas o valor.

Tabela de comparação de tipos

Como referência e exemplo, você pode ver a tabela de comparação no manual :

Comparações estritas com ===

  ┌─────────────────────────────────────────┬─────── ┬───────────────────────────────┬─────────┬─────── ┬───────┐
 │ │ VERDADEIRO │ FALSO │ 1 │ 0 │ -1 │ "1" │ "0" │ "-1" │ NULL │ matriz () │ "php" │ "" │
 ├─────────────────────────────────────────┼─────── ┼───────────────────────────────┼─────────┼─────── ┼───────┤
 │ VERDADEIRO VERDADEIRO FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO
 │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 │ 1 │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 │ 0 │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 │ -1 │ FALSO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 │ "1" │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 │ "0" │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │
 -1 "-1" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 NULL FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 │ matriz () │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ FALSO │ VERDADEIRO │ FALSO │ FALSO │
 Ph "php" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 │ "" FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO FALSO VERDADEIRO
 └─────────────────────────────────────────┴─────── ┴───────────────────────────────┴─────────┴─────── ┴───────┘

O operador == lança entre dois tipos diferentes, se forem diferentes, enquanto o operador === realiza uma ‘comparação de tipos’. Isso significa que somente retornará true se ambos os operandos tiverem o mesmo tipo e o mesmo valor.

Exemplos:

 1 === 1: true 1 == 1: true 1 === "1": false // 1 is an integer, "1" is a string 1 == "1": true // "1" gets casted to an integer, which is 1 "foo" === "foo": true // both operands are strings and have the same value 

Aviso : duas instâncias da mesma class com membros equivalentes NÃO correspondem ao operador === . Exemplo:

 $a = new stdClass(); $a->foo = "bar"; $b = clone $a; var_dump($a === $b); // bool(false) 

Uma imagem vale mais que mil palavras:

PHP Double Equals == igualdade gráfico:

insira a descrição da imagem aqui

PHP Triple Equals === Gráfico de igualdade:

insira a descrição da imagem aqui

Código fonte para criar estas imagens:

https://github.com/sentientmachine/php_equality_charts

meditação de guru

Aqueles que desejam manter sua sanidade, não leiam mais.

  1. ‘==’ converte operandos esquerdo e direito em números quando possível (123 == “123foo”, mas “123”! = “123foo”
  2. Uma string hexadecimal entre aspas é ocasionalmente uma flutuação e será convertida nela contra sua vontade.
  3. == não é transitivo porque (“0” é == para 0 e 0 é == para “” mas “0”! = “”)
  4. “6” == “6”, “4.2” == “4.20” e “133” == “0133”. Mas 133! = 0133, porque 0133 é octal. Mas “0x10” == “16” e “1e3” == “1000”
  5. Variáveis ​​PHP que ainda não foram declaradas são falsas.

  6. False é igual a 0, blankstring e array vazio e “0”.

  7. Quando os números são grandes o suficiente, eles são == Infinito.
  8. NAN não == em si, mas é verdade.

  9. Uma aula nova é == para 1.

  10. False é o valor mais perigoso porque False é == para a maioria das outras variables, principalmente para derrotar seu propósito.

Esperança:

Se você estiver usando PHP, não usará o operador double equals, use sempre triple equals.

Em relação ao JavaScript:

O operador === funciona da mesma forma que o operador ==, mas requer que seus operandos tenham não apenas o mesmo valor, mas também o mesmo tipo de dados.

Por exemplo, o exemplo abaixo mostrará ‘x e y são iguais’, mas não ‘x e y são idênticos’.

 var x = 4; var y = '4'; if (x == y) { alert('x and y are equal'); } if (x === y) { alert('x and y are identical'); } 

Uma adição às outras respostas relativas à comparação de objects:

== compara objects usando o nome do object e seus valores. Se dois objects forem do mesmo tipo e tiverem os mesmos valores de membros, $a == $b verdadeiro.

=== compara o ID do object interno dos objects. Mesmo se os membros forem iguais, $a !== $b se eles não forem exatamente o mesmo object.

 class TestClassA { public $a; } class TestClassB { public $a; } $a1 = new TestClassA(); $a2 = new TestClassA(); $b = new TestClassB(); $a1->a = 10; $a2->a = 10; $b->a = 10; $a1 == $a1; $a1 == $a2; // Same members $a1 != $b; // Different classs $a1 === $a1; $a1 !== $a2; // Not the same object 

Em termos mais simples:

== verifica se é equivalente (apenas valor)

=== verifica se o mesmo (valor && tipo)

Equivalente vs. Same: uma analogia

1 + 1 = 2 + 0 (equivalente)

1 + 1 = 1 + 1 (o mesmo)

No PHP:

true == 1 (verdadeiro – equivalente em valor)

true === 1 (false – não é o mesmo em valor && type)

  • true é booleano
  • 1 é int

É tudo sobre tipos de dados. Tome um BOOL (verdadeiro ou falso) por exemplo:

true também é igual a 1 e false também é igual a 0

O == não se importa com os tipos de dados ao comparar: Então, se você tivesse uma variável que é 1 (o que também pode ser true ):

$var=1;

E então compare com o == :

 if ($var == true) { echo"var is true"; } 

Mas $var na verdade não é igual a true , não é? Ele tem o valor int de 1 , que por sua vez, é igual a true.

Com === , os tipos de dados são verificados para garantir que as duas variables ​​/ objects / o que quer que esteja usando o mesmo tipo.

Então, se eu fizesse

 if ($var === true) { echo "var is true"; } 

essa condição não seria verdadeira, como $var !== true it == true (se você sabe o que quero dizer).

Por que você precisaria disso?

Simples – vamos dar uma olhada em uma das funções do PHP: array_search() :

A function array_search() simplesmente procura um valor em uma matriz e retorna a chave do elemento em que o valor foi encontrado. Se o valor não puder ser encontrado na matriz, ele retornará false . Mas, e se você fez um array_search() em um valor que foi armazenado no primeiro elemento da matriz (que teria a chave da matriz de 0 ) …. a function array_search() retornaria 0 … que é igual a falso ..

Então, se você fez:

 $arr = array("name"); if (array_search("name", $arr) == false) { // This would return 0 (the key of the element the val was found // in), but because we're using ==, we'll think the function // actually returned false...when it didn't. } 

Então, você vê como isso pode ser um problema agora?

A maioria das pessoas não usa == false ao verificar se uma function retorna false. Em vez disso, eles usam o ! . Mas, na verdade, isso é exatamente o mesmo que usar ==false , então se você fez:

 $arr = array("name"); if (!array_search("name", $arr)) // This is the same as doing (array_search("name", $arr) == false) 

Então, para coisas assim, você usaria o === vez disso, para que o tipo de dados seja verificado.

Um exemplo é que um atributo de database pode ser nulo ou “”:

 $attributeFromArray = ""; if ($attributeFromArray == ""){} //true if ($attributeFromArray === ""){} //true if ($attributeFromArray == null){} //true if ($attributeFromArray === null){} //false $attributeFromArray = null; if ($attributeFromArray == ""){} //true if ($attributeFromArray === ""){} //false if ($attributeFromArray == null){} //true if ($attributeFromArray === null){} //true 

Dado x = 5

1) Operador: == é “igual a”. x == 8 é falso
2) Operador: === é “exatamente igual a” (valor e tipo) x === 5 é verdadeiro, x === "5" é falso

 $a = 5; // 5 as an integer var_dump($a == 5); // compare value; return true var_dump($a == '5'); // compare value (ignore type); return true var_dump($a === 5); // compare type/value (integer vs. integer); return true var_dump($a === '5'); // compare type/value (integer vs. string); return false 

Tenha cuidado embora. Aqui está um problema notório.

 // 'test' is found at position 0, which is interpreted as the boolean 'false' if (strpos('testing', 'test')) { // code... } 

vs.

 // true, as strict comparison was made (0 !== false) if (strpos('testing', 'test') !== false) { // code... } 

Resumindo, === funciona da mesma maneira que == na maioria das linguagens de programação.

PHP permite que você faça comparações que realmente não fazem sentido. Exemplo:

 $y = "wauv"; $x = false; if ($x == $y) ... 

Embora isso permita alguns “atalhos” interessantes, você deve tomar cuidado, pois uma function que retorna algo que não deveria (como “erro” em vez de um número) não será detectada, e você ficará imaginando o que aconteceu.

No PHP, == compara valores e executa a conversão de tipo, se necessário (por exemplo, a string “12343sdfjskfjds” se tornará “12343” em uma comparação inteira). === irá comparar o valor AND type e retornará false se o tipo não for o mesmo.

Se você olhar no manual do PHP, verá que muitas funções retornam “false” se a function falhar, mas elas podem retornar 0 em um cenário de sucesso, e é por isso que elas recomendam fazer “if (function ()! == false) “para evitar erros.

Alguns dos exemplos

 var_dump(5 == 5); // True var_dump(5 == "5"); // True because == checks only same value not type var_dump(5 === 5); // True var_dump(5 === "5"); // False because value are same but data type are different. 

PS

== Compara o valor apenas, não se importará com os tipos de dados

vs.

=== Compara os valores e tipos de dados

Você usaria === para testar se uma function ou variável é falsa e não apenas igual a falso (zero ou uma string vazia).

 $needle = 'a'; $haystack = 'abc'; $pos = strpos($haystack, $needle); if ($pos === false) { echo $needle . ' was not found in ' . $haystack; } else { echo $needle . ' was found in ' . $haystack . ' at location ' . $pos; } 

Neste caso, strpos retornariam 0, o que equivaleria a falso no teste

 if ($pos == false) 

ou

 if (!$pos) 

que não é o que você quer aqui.

Quanto a quando usar um sobre o outro, tome por exemplo a function fwrite() no PHP.

Essa function grava conteúdo em um stream de arquivos. De acordo com o PHP, ” fwrite() retorna o número de bytes escritos, ou FALSE em erro”. Se você quiser testar se a chamada de function foi bem sucedida, este método é falho:

 if (!fwrite(stuff)) { log('error!'); } 

Ele pode retornar zero (e é considerado bem-sucedido), e sua condição ainda é acionada. O caminho certo seria:

 if (fwrite(stuff) === FALSE) { log('error!'); } 

PHP é uma linguagem fracamente tipada. Usando o operador de dupla igualdade permite uma verificação solta de uma variável.

Verificar um valor vagamente permitiria que alguns valores semelhantes, mas não iguais, igualassem o mesmo:

  • nulo
  • falso
  • 0

Todos esses valores equivalem como iguais usando o operador de dupla igualdade.

Variáveis ​​têm um tipo e um valor.

  • $ var = “test” é uma string que contém “teste”
  • $ var2 = 24 é um número inteiro que o valor é 24.

Quando você usa essas variables ​​(em PHP), às vezes você não tem o tipo bom. Por exemplo, se você fizer

 if ($var == 1) {... do something ...} 

PHP tem que converter (“para lançar”) $ var para inteiro. Nesse caso, “$ var == 1” é verdadeiro porque qualquer string não vazia é convertida em 1.

Ao usar ===, você verifica se o valor AND THE TYPE é igual, então “$ var === 1” é falso.

Isso é útil, por exemplo, quando você tem uma function que pode retornar falso (por erro) e 0 (resultado):

 if(myFunction() == false) { ... error on myFunction ... } 

Este código está errado como se myFunction() retornasse 0, fosse convertido para false e você parecesse ter um erro. O código correto é:

 if(myFunction() === false) { ... error on myFunction ... } 

porque o teste é que o valor de retorno “é um booleano e é falso” e não “pode ​​ser convertido para falso”.

O operador === deve comparar a igualdade exata de conteúdo, enquanto o operador == irá comparar a igualdade semântica. Em particular, ele irá forçar cadeias de caracteres para números.

A igualdade é um assunto vasto. Veja o artigo da Wikipedia sobre igualdade .

 < ?php /** * Comparison of two PHP objects == === * Checks for * 1. References yes yes * 2. Instances with matching attributes and its values yes no * 3. Instances with different attributes yes no **/ // There is no need to worry about comparing visibility of property or // method, because it will be the same whenever an object instance is // created, however visibility of an object can be modified during run // time using ReflectionClass() // http://php.net/manual/en/reflectionproperty.setaccessible.php // class Foo { public $foobar = 1; public function createNewProperty($name, $value) { $this->{$name} = $value; } } class Bar { } // 1. Object handles or references // Is an object a reference to itself or a clone or totally a different object? // // == true Name of two objects are same, for example, Foo() and Foo() // == false Name of two objects are different, for example, Foo() and Bar() // === true ID of two objects are same, for example, 1 and 1 // === false ID of two objects are different, for example, 1 and 2 echo "1. Object handles or references (both == and ===) 
"; $bar = new Foo(); // New object Foo() created $bar2 = new Foo(); // New object Foo() created $baz = clone $bar; // Object Foo() cloned $qux = $bar; // Object Foo() referenced $norf = new Bar(); // New object Bar() created echo "bar"; var_dump($bar); echo "baz"; var_dump($baz); echo "qux"; var_dump($qux); echo "bar2"; var_dump($bar2); echo "norf"; var_dump($norf); // Clone: == true and === false echo '$bar == $bar2'; var_dump($bar == $bar2); // true echo '$bar === $bar2'; var_dump($bar === $bar2); // false echo '$bar == $baz'; var_dump($bar == $baz); // true echo '$bar === $baz'; var_dump($bar === $baz); // false // Object reference: == true and === true echo '$bar == $qux'; var_dump($bar == $qux); // true echo '$bar === $qux'; var_dump($bar === $qux); // true // Two different objects: == false and === false echo '$bar == $norf'; var_dump($bar == $norf); // false echo '$bar === $norf'; var_dump($bar === $norf); // false // 2. Instances with matching attributes and its values (only ==). // What happens when objects (even in cloned object) have same // attributes but varying values? // $foobar value is different echo "2. Instances with matching attributes and its values (only ==)
"; $baz->foobar = 2; echo '$foobar' . " value is different
"; echo '$bar->foobar = ' . $bar->foobar . "
"; echo '$baz->foobar = ' . $baz->foobar . "
"; echo '$bar == $baz'; var_dump($bar == $baz); // false // $foobar's value is the same again $baz->foobar = 1; echo '$foobar' . " value is the same again
"; echo '$bar->foobar is ' . $bar->foobar . "
"; echo '$baz->foobar is ' . $baz->foobar . "
"; echo '$bar == $baz'; var_dump($bar == $baz); // true // Changing values of properties in $qux object will change the property // value of $bar and evaluates true always, because $qux = &$bar. $qux->foobar = 2; echo '$foobar value of both $qux and $bar is 2, because $qux = &$bar' . "
"; echo '$qux->foobar is ' . $qux->foobar . "
"; echo '$bar->foobar is ' . $bar->foobar . "
"; echo '$bar == $qux'; var_dump($bar == $qux); // true // 3. Instances with different attributes (only ==) // What happens when objects have different attributes even though // one of the attributes has same value? echo "3. Instances with different attributes (only ==)
"; // Dynamically create a property with the name in $name and value // in $value for baz object $name = 'newproperty'; $value = null; $baz->createNewProperty($name, $value); echo '$baz->newproperty is ' . $baz->{$name}; var_dump($baz); $baz->foobar = 2; echo '$foobar' . " value is same again
"; echo '$bar->foobar is ' . $bar->foobar . "
"; echo '$baz->foobar is ' . $baz->foobar . "
"; echo '$bar == $baz'; var_dump($bar == $baz); // false var_dump($bar); var_dump($baz); ?>

Todas as respostas até agora ignoram um problema perigoso com ===. Foi observado de passagem, mas não estressado, que integer e double são tipos diferentes, portanto, o seguinte código:

 $n = 1000; $d = $n + 0.0e0; echo '
'. ( ($n == $d)?'equal' :'not equal' ); echo '
'. ( ($n === $d)?'equal' :'not equal' );

dá:

  equal not equal 

Note que este não é um caso de “erro de arredondamento”. Os dois números são exatamente iguais ao último bit, mas eles têm tipos diferentes.

Este é um problema desagradável porque um programa usando === pode funcionar felizmente por anos se todos os números forem pequenos o suficiente (onde “pequeno o suficiente” depende do hardware e sistema operacional que você está executando). No entanto, se por acaso, um número inteiro for grande o suficiente para ser convertido em um duplo, seu tipo será alterado “para sempre”, mesmo que uma operação subsequente, ou muitas operações, possa trazê-lo de volta para um inteiro pequeno em valor. E fica pior. Ele pode se espalhar – a infecção dupla pode ser transmitida para qualquer coisa que toque, um cálculo de cada vez.

No mundo real, é provável que isso seja um problema em programas que lidam com datas além do ano de 2038, por exemplo. Neste momento, os registros de data e hora do UNIX (número de segundos desde 1970-01-01 00:00:00 UTC) exigirão mais de 32 bits, portanto, sua representação será “magicamente” alternada para o dobro em alguns sistemas. Portanto, se você calcular a diferença entre duas vezes, poderá acabar com alguns segundos, mas como um resultado duplo, em vez do número inteiro, que ocorre no ano de 2017.

Eu acho que isso é muito pior do que as conversões entre strings e números, porque é sutil. Acho fácil acompanhar o que é uma string e o que é um número, mas acompanhar o número de bits em um número está além de mim.

Portanto, nas respostas acima há algumas boas tabelas, mas nenhuma distinção entre 1 (como um inteiro) e 1 (duplo sutil) e 1.0 (duplo óbvio). Além disso, conselhos que você deve sempre usar === e nunca == não é grande porque === às vezes falhará onde == funciona corretamente. Além disso, o JavaScript não é equivalente a este respeito, porque ele tem apenas um tipo de número (internamente, ele pode ter diferentes representações bit-wise, mas não causa problemas para ===).

Meu conselho – não use nenhum deles. Você precisa escrever sua própria function de comparação para realmente consertar essa bagunça.