Как различаются операторы сравнения с равенством равенства (== double equals) и идентичности (=== triple equals)?

В чем разница между == и === ?

  • Как точно работает слабое сравнение?
  • Как точно работает строгая сопоставление === ?

Какие будут полезные примеры?

Разница между == и ===

Различие между оператором loosely == equal и строгим === идентичным оператором точно объясняется в руководстве :

Операторы сравнения

 ┌──────────┬───────────┬────────────────────────── ─────────────────────────────────┐
 │ Пример │ Имя │ Результат │
 ├──────────┼───────────┼────────────────────────── ─────────────────────────────────┤
 │ $ a == $ b │ Равно │ ИСТИНА, если $ a равно $ b после манипуляции с типом.  │
 │ $ a === $ b │ Идентично │ ИСТИНА, если $ a равно $ b, и они одного типа.  │
 └──────────┴───────────┴────────────────────────── ─────────────────────────────────┘

Недостаточно == равное сравнение

Если вы используете оператор == или любой другой оператор сравнения, который использует слабое сравнение, например != , <> или == , вам всегда нужно посмотреть на контекст, чтобы увидеть, что, где и почему что-то преобразуется, чтобы понять, что продолжается.

Преобразование правил

  • Преобразование в логическое
  • Преобразование в целое число
  • Преобразование в float
  • Преобразование в строку
  • Преобразование в массив
  • Преобразование объекта
  • Преобразование в ресурс
  • Преобразование в NULL

Таблица сравнения типов

В качестве ссылки и примера вы можете увидеть таблицу сравнения в руководстве :

Свободные сравнения с ==

  ┌─────────┬───────┬───────┬───────┬───────┬─────── ┬───────┬───────┬───────┬───────┬─────────┬─────── ┬───────┐
 │ │ ИСТИНА │ ЛОЖЬ │ 1 │ 0 │ -1 │ "1" │ "0" │ "-1" │ NULL │ array () │ "php" │ "" │
 ├─────────┼───────┼───────┼───────┼───────┼─────── ┼───────┼───────┼───────┼───────┼─────────┼─────── ┼───────┤
 │ TRUE │ TRUE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │
 │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │
 │ 1 │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ 0 │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ TRUE │ TRUE │
 │ -1 │ TRUE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ "1" │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ «0» │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ "-1" │ TRUE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ NULL │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ TRUE │ FALSE │ TRUE │
 │ array () │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ TRUE │ FALSE │ FALSE │
 │ «php» │ TRUE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │
 │ "" │ FALSE │ TRUE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ TRUE │
 └─────────┴───────┴───────┴───────┴───────┴─────── ┴───────┴───────┴───────┴───────┴─────────┴─────── ┴───────┘

Строгое === идентичное сравнение

Если вы используете оператор === или какой-либо другой оператор сравнения, который использует строгое сравнение, например, !== или === , то вы всегда можете быть уверены, что типы не будут волшебным образом изменяться, потому что конверсии не будет продолжается. Поэтому при строгом сравнении тип и значение должны быть одинаковыми, а не только значением.

Таблица сравнения типов

В качестве ссылки и примера вы можете увидеть таблицу сравнения в руководстве :

Строгие сравнения с ===

  ┌─────────┬───────┬───────┬───────┬───────┬─────── ┬───────┬───────┬───────┬───────┬─────────┬─────── ┬───────┐
 │ │ ИСТИНА │ ЛОЖЬ │ 1 │ 0 │ -1 │ "1" │ "0" │ "-1" │ NULL │ array () │ "php" │ "" │
 ├─────────┼───────┼───────┼───────┼───────┼─────── ┼───────┼───────┼───────┼───────┼─────────┼─────── ┼───────┤
 │ TRUE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ 1 │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ 0 │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ -1 │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ «1» │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ «0» │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ "-1" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │ FALSE │
 │ NULL │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │ FALSE │
 │ массив () │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │ FALSE │
 │ «php» │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │ FALSE │
 │ "" │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ FALSE │ TRUE │
 └─────────┴───────┴───────┴───────┴───────┴─────── ┴───────┴───────┴───────┴───────┴─────────┴─────── ┴───────┘

Оператор == отличает два разных типа, если они разные, а оператор === выполняет «сравнение типов». Это означает, что он вернет true только в том случае, если оба операнда имеют один и тот же тип и одно и то же значение.

Примеры:

 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 

Предупреждение : два экземпляра одного класса с эквивалентными членами НЕ соответствуют оператору === . Пример:

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

Что касается JavaScript:

Оператор === работает так же, как и оператор ==, но требует, чтобы его операнды имели не только одно и то же значение, но и тот же тип данных.

Например, пример ниже будет отображать «x и y равны», но не «x и y одинаковы».

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

Одна картинка стоит тысячи слов:

PHP Double Equals == диаграмма равенства:

введите описание изображения здесь

PHP Triple Equals === График равенства:

введите описание изображения здесь

Исходный код для создания этих изображений:

https://github.com/sentientmachine/php_equality_charts

Гуру Медитации

Те, кто хочет сохранить здравомыслие, не читают дальше.

  1. '==' преобразует левый и правый операнды в числа, когда это возможно (123 == "123foo", но "123"! = "123foo"
  2. Шестнадцатеричная строка в кавычках иногда является поплавком и будет приложена к ней против вашей воли.
  3. == не является транзитивным, потому что («0» равно == 0, а 0 – от «до», но «0»! = «»)
  4. «6» == «6», «4.2» == «4.20» и «133» == «0133». Но 133! = 0133, потому что 0133 – восьмеричный. Но «0x10» == «16» и «1e3» == «1000»
  5. Переменные PHP, которые еще не были объявлены, являются ложными.

  6. False равно 0, пустая строка и пустой массив и «0».

  7. Когда числа достаточно велики, они == Бесконечность.
  8. NAN не является самой, но это правда.

  9. Новый класс – от 1 до 1.

  10. False – это самое опасное значение, потому что False является == большинством других переменных, в основном побеждая его цель.

Надежда:

Если вы используете PHP, вы не должны использовать оператор double equals, всегда используйте тройные равные.

Добавление к другим ответам относительно сравнения объектов:

== сравнивает объекты, используя имя объекта и их значения. Если два объекта одного типа и имеют одинаковые значения, $a == $b дает true.

=== сравнивает внутренний идентификатор объекта. Даже если члены равны, $a !== $b если они не являются точно одним и тем же объектом.

 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 classes $a1 === $a1; $a1 !== $a2; // Not the same object 

Проще говоря:

== проверяет, эквивалентен (только значение)

=== проверяет, одинаково (значение && type)

Эквивалент против того же: аналогия

1 + 1 = 2 + 0 (эквивалентно)

1 + 1 = 1 + 1 (то же самое)

В PHP:

true == 1 (true – эквивалентно по значению)

true === 1 (false – не то же значение в значении && type)

  • true является логическим
  • 1 – int

Все дело в типах данных. Возьмите BOOL (true или false), например:

true также равно 1 а false также равно 0

==

$var=1;

И затем сравните с == :

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

Но $var фактически не соответствует действительности, не так ли? Он имеет значение int 1 вместо этого, которое, в свою очередь, равно true.

С === проверяются типы данных, чтобы убедиться, что две переменные / объекты / все используют один и тот же тип.

Так что, если бы я

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

это условие не будет истинным, так как $var !== true это только == true (если вы знаете, что я имею в виду).

Зачем вам это нужно?

Простой – давайте рассмотрим одну из функций PHP: array_search() :

Функция array_search() просто ищет значение в массиве и возвращает ключ элемента, в котором было найдено значение. Если значение не может быть найдено в массиве, оно возвращает false . Но что, если вы сделали array_search() для значения, которое было сохранено в первом элементе массива (который имел бы array_search() ключ из 0 ) …. array_search() вернет 0 … которая равно false.

Итак, если вы это сделали:

 $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. } 

Итак, вы видите, как это может быть проблемой сейчас?

Большинство людей не используют == false при проверке, возвращает ли функция false. Вместо этого они используют ! , Но на самом деле это точно так же, как использование ==false , поэтому, если вы это сделали:

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

Поэтому для таких вещей вы должны использовать === вместо этого, чтобы был проверен тип данных.

Одним из примеров является то, что атрибут базы данных может иметь значение null или «":

 $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 

При x = 5

1) Оператор: == «равен». x == 8 – false
2) Оператор: === «точно равен» (значение и тип) x === 5 истинно, x === "5" – false

 $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 

Будьте осторожны. Вот пресловутая проблема.

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

против

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

Короче говоря, === работает так же, как и в большинстве других языков программирования.

PHP позволяет делать сравнения, которые на самом деле не имеют смысла. Пример:

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

Хотя это позволяет некоторые интересные «ярлыки», вы должны остерегаться, так как функция, которая возвращает что-то, что она не должна (например, «ошибка», а не число) не будет поймана, и вам будет интересно узнать, что произошло.

В PHP == сравнивает значения и при необходимости выполняет преобразование типов (например, строка «12343sdfjskfjds» станет «12343» в целых сравнениях). === будет сравнивать значение типа И и вернет false, если тип не совпадает.

Если вы посмотрите в руководстве по PHP, вы увидите, что многие функции возвращают «false», если функция выходит из строя, но они могут возвращать 0 в успешном сценарии, поэтому они рекомендуют делать «if (function ()! == false) ", чтобы избежать ошибок.

Немногие из примеров

 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

== Сравнивает только значение, оно не будет беспокоиться о типах данных

против

=== Сравнивает значения и типы данных

Вы должны использовать === для проверки того, является ли функция или переменная ложной, а не просто приравнивается к false (ноль или пустая строка).

 $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; } 

В этом случае strpos вернет 0, который будет равен false в тесте

 if ($pos == false) 

или

 if (!$pos) 

который вам не нужен.

Что касается того, когда использовать один над другим, возьмите, например, функцию fwrite() в PHP.

Эта функция записывает содержимое в поток файлов. Согласно PHP, « fwrite() возвращает количество записанных байтов или FALSE при ошибке». Если вы хотите проверить, был ли вызов функции успешным, этот метод является ошибочным:

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

Он может возвращать ноль (и считается успешным), и ваше состояние все равно срабатывает. Правильный путь:

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

Переменные имеют тип и значение.

  • $ var = "test" – строка, содержащая "test"
  • $ var2 = 24 – целое значение vhose равно 24.

Когда вы используете эти переменные (в PHP), иногда у вас нет хорошего типа. Например, если вы это сделаете

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

PHP должен преобразовать ("to cast") $ var в integer. В этом случае «$ var == 1» истинно, потому что любая непустая строка отлита до 1.

При использовании === вы проверяете, что значение AND THE TYPE равно, поэтому «$ var === 1» является ложным.

Это полезно, например, когда у вас есть функция, которая может вернуть false (при ошибке) и 0 (результат):

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

Этот код неверен, как если myFunction() возвращает 0, он присваивается false, и у вас, кажется, есть ошибка. Правильный код:

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

потому что тест состоит в том, что возвращаемое значение «является логическим и ложным», а не «может быть отправлено на false».

Предполагается, что оператор === сравнивает точное соответствие содержания, в то время как оператор == сравнивает семантическое равенство. В частности, он будет принуждать строки к цифрам.

Равенство – обширный предмет. См. Статью Википедии о равенстве .

 <?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 ===) <br />"; $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 ==) <br />"; $baz->foobar = 2; echo '$foobar' . " value is different <br />"; echo '$bar->foobar = ' . $bar->foobar . "<br />"; echo '$baz->foobar = ' . $baz->foobar . "<br />"; 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 <br />"; echo '$bar->foobar is ' . $bar->foobar . "<br />"; echo '$baz->foobar is ' . $baz->foobar . "<br />"; 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' . "<br />"; echo '$qux->foobar is ' . $qux->foobar . "<br />"; echo '$bar->foobar is ' . $bar->foobar . "<br />"; 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 ==) <br />"; // 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 <br />"; echo '$bar->foobar is ' . $bar->foobar . "<br />"; echo '$baz->foobar is ' . $baz->foobar . "<br />"; echo '$bar == $baz'; var_dump($bar == $baz); // false var_dump($bar); var_dump($baz); ?> 

PHP – это свободно типизированный язык. Использование оператора с двойным равным допускает свободную проверку переменной.

Понятно, что проверка значения может привести к тому, что некоторые аналогичные, но не равные значения будут равными:

  • «»
  • ноль
  • ложный
  • 0

Все эти значения будут равны равным с использованием оператора с двойным равенством.

Все ответы до сих пор игнорируют опасную проблему с ===. Было замечено попутно, но не подчеркнуто, что целые и двойные разные типы, поэтому следующий код:

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

дает:

  equal not equal 

Обратите внимание, что это не случай «ошибки округления». Два числа точно равны до последнего бита, но у них разные типы.

Это неприятная проблема, потому что программа, использующая ===, может работать счастливо в течение многих лет, если все числа достаточно малы (где «достаточно мало» зависит от оборудования и ОС, на которых вы работаете). Однако, если случайно, целое число оказывается достаточно большим, чтобы преобразовать его в double, его тип изменяется «навсегда», даже если последующая операция или многие операции могут вернуть ее к небольшому целому значению. И все хуже. Он может распространяться – двойная инфекция может передаваться по всему, что она затрагивает, по одному вычислению за раз.

В реальном мире это, вероятно, будет проблемой в программах, которые обрабатывают даты за пределами 2038 года, например. В это время отметки времени UNIX (количество секунд с 1970-01-01 00:00:00 UTC) потребуют более 32 бит, поэтому их представление «волшебным образом» переключится на двойное на некоторых системах. Поэтому, если вы подсчитаете разницу между двумя моментами, вы можете закончиться за пару секунд, но как двойной, а не целочисленный результат, который возникает в 2017 году.

Я думаю, что это намного хуже, чем переходы между строками и цифрами, потому что они тонкие. Мне легко следить за тем, что такое строка, и что такое число, но отслеживать количество бит в числе – это вне меня.

Таким образом, в приведенных выше ответах есть несколько хороших таблиц, но нет различия между 1 (как целое) и 1 (тонкий двойной) и 1,0 (очевидный двойной). Кроме того, совет, который вы всегда должны использовать === и никогда ==, невелик, потому что === будет иногда терпеть неудачу, если == работает правильно. Кроме того, JavaScript не эквивалентен в этом отношении, поскольку он имеет только один тип номера (внутри него могут быть разные побитовые представления, но это не вызывает проблем для ===).

Мой совет – не используйте ни того, ни другого. Вам нужно написать свою собственную функцию сравнения, чтобы действительно исправить этот беспорядок.