☁ == ☀

Как знают программисты на ПХП, у этого языка есть одна неприятная особенность: при сравнении с приведением типов („==“) ПХП всё, что по его мнению похоже на число, преобразует в число:

If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically.

Причём, «похоже на число» — это не обязательно нечто десятичное:

var_dump("0x01" == "1"); // true
// но при этом
var_dump("0b01" == "1"); // false
var_dump("014" == "12") // false

Эта проблема косвенно проявляется при поиске в массиве. Казалось бы, строкового значения «1.5» в массиве нет:

var_dump(in_array("1.5", ["01.5000"])); // true
// правда есть специальный флаг для строгого стравнения, о котором почему-то мало кто знает:
var_dump(in_array("1.5", ["01.5000"], true)); // false

Но настоящая проблема вот в чём. ПХП, конечно, смотрит, похожа ли строка на то, что он считает числом, но никак не проверяет сможет ли он «съесть то, что укусил»:

var_dump("10000000000000000000000000000000" == "10000000000000000099999999999999"); // true

Сюрприз?

Почему так происходит. Всё очень просто. ПХП решает: внутри строки одни цифры, нужно преобразовать в число, в целый это не помещается, поэтому преобразую в число с плавающей точкой. Но число с плавающей точкой хранится с некой точностью, такова плата за его быструю обработку машиной.

В итоге при конвертации происходит потеря точности, левая и правая часть конвертируются в 1e31 (единица с с 31 нулём), которые равны между собой. Это может произойти, например, тогда, когда мы сравниваем «двумя равно» пару хешей, которые содержат только цифры.

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

Есть конструкция, которой мы управлять не можем:

switch ("1.5") {
    case "0001.500": echo "пичалька"; // ещё какая!
}

Конструкция «switch» всегда использует нестрогое сравнение, об этом нужно помнить.

Поделиться
Отправить
3 комментария
Segr

Превратим число в строку:
$a = «1.5»;
switch («`{$a}`») {
   case «`0001.500`»: echo «кто здесь?»;
}

Азат Разетдинов (razetdinov.ya.ru)

Хорошо, что в яваскрипте этот тупняк на == и заканчивается. И switch, и indexOf используют ===.

Евгений Степанищев (bolknote.ru)

Комментарий для razetdinov.ya.ru:

В ПХП есть один тупняк есть (это как минимум): строка «0» считается false при всяких сравнениях:

var_dump(array_filter( [ 0, null, false, «0», «123», «000» ]));
array(2) {
[4]=>
string(3) «123»
[5]=>
string(3) «000»
}

или:

$a = «0»; $b = «000»;
var_dump(empty($a), empty($b));
bool(true)
bool(false)

Популярное