Pull to refresh

Comments 81

«2.000000000000000123» == «2.000000000000000456»

Я этого не понял, должны ведь сравниваться как строки?
Всё, что похоже на число PHP преобразует тут в число. Довольно известное правило, где-то в документации есть.
ну да известно всем кроме интерпретатора:
var_dump(«2.000000000000000123» == «2.000000000000000456»); // false
Нулей просто мало. Вот:
 php -r 'var_dump("2.00000000000000000123" == "2.00000000000000000456");'
bool(true)
да жесть, в принципе кроме этого всё объяснимо… но зачем так-то?!!!
Потому что PHP традиционно мешает строки и числа в кучу, см., например, empty(«0»). Это из-за того, что снаружи ($_GET, $_POST и так далее) вообще всё приходит как строки, а создателям языка хотелось максимально упростить жизнь веб-мастеров в этом месте.
Ага. Упростили. Вместо объявления типа 1 раз — приведение, то там, то сям. И ===. Ну или ребусы как в сабже, а не код. Удобно, сил нет.
Ну и я бы не сказал, что «кроме этого всё объяснимо» :)) я таких примеров кучу знаю, например:
$ php -r '$a=null; var_dump(--$a); var_dump(++$a);'
NULL
int(1)

То есть уменьшение null даёт null, увеличение — единицу.
ну об этом в доке написано сразу: php.net/manual/en/language.operators.increment.php это можно объяснить, даже некую логику под это подвести (но я согласен, что это не ожидаемо)
но почему 2 строки сравниваются как числа нет
Ну так и об операции сравнения написано в доке:
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.
Более того!
These rules also apply to the switch statement.
То есть:
$ php -r 'switch("0x000000") { case "0e0": var_dump("Duh!"); }'
string(4) "Duh!"
про switch это боль да, там === не напишешь
На самом деле в доке есть почти всё (за очень редким исключением), но очень уж забавны некоторые вещи. Например:

$ php -r 'var_dump([] < new stdclass); var_dump([] > INF);'
bool(true) // пустой массив меньше пустого класса
bool(true) // пустой массив больше бесконечности
А пустой класс больше бесконечности?
"2.000000000000000123" == "2.000000000000000456"

у вас ошибка, это сравнение строк, а не float
Это от разрядности зависит, нужно просто ноликов побольше.
var_dump("2.00000000000000000000000000000000123" == "2.00000000000000000000000000000000456"); // bool(true)
3v4l.org/pCMMn
"2.33a" == "2.33b" // false - сравниваем строки, все логично
"1e2" == "100" // true - зачем он их преобразовывает в числа? Для кого тут кавычки стоят?!

Хоть убейте, не понимаю, какого черты PHP при сравнении двух строк вообще пытается преобразовывать их в числа. Тип же совпадает.
Это у автора ошибка. PHP так не делает
Прошу прощения. Проверил. Действительно делает.
Хорошо хоть рекомендуется везде использовать ===
Тоже два float в строках:
«2.000000000000000123» == «2.000000000000000456»

false, сравниваются строки, приведение не выполняется
Тут я просто нолик пропустил, попробуйте так
php >  echo "2.00000000000000000123" == "2.00000000000000000456" ? 'true' : 'false';
true
Не поверил, решил проверить:

<?php
$a1 = "1.000000000000000123";
$b1 = "1.000000000000000456";

$a2 = "2.000000000000000123";
$b2 = "2.000000000000000456";

if($a1 == $b1) echo $a1.' == '.$b1;
else echo $a1.' != '.$b1;
echo '<br>';
if($a2 == $b2) echo $a2.' == '.$b2;
else echo $a2.' != '.$b2;


В итоге:

1.000000000000000123 != 1.000000000000000456
2.000000000000000123 != 2.000000000000000456


PHP 5.4.35, Win 7x86, OpenServer
Да, ноль пропустил
php >  echo "2.00000000000000000123" == "2.00000000000000000456" ? 'true' : 'false';
true
Паскаль нас учил писать =
Си учил на писать ==
Пхп нас учит писать ===
10 GOTO 10

там вообще таких фокусов не было. LET A$ = KEYBOARD$ и все.
… как и во многих языках с неявным приведением типов. но топик-то про пхп?
12 == «0xC»
Конечно, true.
Спасибо. Хорошая шпаргалка.
Почитал, поужасался. К концу остался вопрос: а что, вот так действительно кто-то пишет?
Я к тому, что если идёт более-менее осмысленное написание кода то вот такого понаписать сложно (чтобы (string) «false» сравнивать с (boolean) true, 12 == «0xC» и тому подобное).
Вот честное слово, с подобными проблемами сравнения последний раз сталкивался может быть лет пять назад.
Явное приведение типов, фильтрация входящих данных и принцип «никогда не доверяй тому, что пришло от пользователя» — избавляют от подобных проблем. Разве нет?
Ну вот сравнение «100» == «1e2» может в какой-то задаче попасться. Скажем, 2 пользователя с такими никами — и вроде все нормально, правильные данные от пользователя, сравниваем строки со строками… А нет, PHP за нас что-то додумывает!
Бывают не очевидные случаи. Приходит вам с клиента $POST, а там строки, а вы вполне можете думать, что там целые числа и сравниваете эти строки с числами через ==. Как вариант.
Нормальные люди конечно так никогда не пишут. Это статья больше для развлечения, чем для использования всего этого на практике. Маленькие перлы языка =)
double(0.9)
string(3) «0.9»
double(0.9)

А что должно было быть?
Похоже, вы пренебрегли первой командой
Да нет, скопировал целиком, правда если включить e_depricated, то можно увидеть:
Deprecated: setlocale(): Passing locale category name as string is deprecated. Use the LC_* -constants instead in test.php on line 2

Замена 'LC_ALL' на LC_ALL убирает предупреждение, вывод не меняется. php 5.4.12, если это важно.
Локаль «ru_RU.UTF-8», видимо, в системе отсутствует. Смысл в том, чтобы установить такую локаль, где десятичный разделитель — запятая.

Если у вас unix-система, посмотрите список локалей с помощью команды locale -a. Если Windows — не знаю :-)
Ага, просто кто-то забыл проверить результат выполнения функции setlocale
if(setlocale(LC_ALL, 'ru_RU.UTF-8') !== false){
	echo "Мое любимое:\n";
	$f = 0.9;
	$s = (string)$f;
	$f2 = (float)$s;
	var_dump($f, $s, $f2);
} else {
	echo "В системе отсуствует локаль 'ru_RU.UTF-8'\n";
}
Мне вот не понятно, как после такого люди добровольно выбирают похапе в проекты?
Это же пограничные случаи, а не правило, при этом никто ж не запрещает использовать ===
Думаю пасхалки есть в любом языке, просто в PHP их немного больше :)
Соглашусь, если объясните для чего использовать ==, вместо ===?
Ну если вы точно уверены в типах переменных в каком то месте то думаю вполне допустимо ==
Ну так каждая пасхалочка у тебя отнимает (условно) час времени. Поэтому и не ясно, зачем брать инструмент с пасхалками, когда есть такой же без. А час времени лучше потратить на себя/жену/детей.
Скажем так, у меня опыта в пыхе не мало, но проблемы подобного плана возникали лет эдак 5-6 назад. Если ты думаешь не только о себе, а и о других сотрудниках — то подобный ф-ционал ты просто не используешь.
В любом языке можно найти что-то такое, после чего скажешь: да зачем Вы взяли этот язык???
Ага, из всех зол выбираем не меньшее, а наиболее кривое. Такая то аргументация…
Каждый человек сам отвечает за свой выбор, поступки и действия.
Половина кода из статьи будет работать в JS. как? как люди выпирают писать на js?
Можно подумать есть выбор.
Выбора очень много, на каждый популярный язык по компилятору в JS.
Вот так, например, в typescript выглядит сравнение разных типов:
есть === и для PHP, и для js
У js альтернативы как таковой нет. У похапе же навалом. Да и уровень идиотии у js не такой зашкаливающий.
Да и уровень идиотии у js не такой зашкаливающий.

Если и не такой зашкаливающий, то только потому, что в PHP встроенного функционала на два порядка больше, там было место, где развернуться. В процентном соотношении они идут плечо к плечу.
У js альтернативы как таковой нет.

TypeScript ;-)
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.

Так то я лучше PureScript возьму. :)
А еще лучше не привязываться к какому-то языку в браузере, но на сегодняшний день это фантастика.
Напомнило :)

(Только это JavaScript)
Прочитал заголовок как «PHP — баллада о двух стульях» (ну вы поняли). Закрыл вкладку, т.к. всё уже было сказано несколько лет назад: habrahabr.ru/post/142140
Да, та статья шикарная
Сравнивать float'ы нужно всегда с учетом погрешности в любом языке, а не только в PHP.
Решение задачки: $x == 1 && $x == 2

x=...
при $x = true;

Это первый же комментарий к топику.
ИМХО, резюме должно быть такое: юзайте ===
Кому нужна транзитивность в PHP, те используют === тождественное сравнение активных типов (без преобразований). Но статья классная, хороший справочник)
В большинстве случаев большинство, к счастью, эти примеры так и остаются просто любопытными случаями, но есть то на чем наверное рано или поздно спотыкается любой пхпшник, при том иногда довольно больно спотыкается — это empty('0')==true, возможно стоило упомянуть в статье и об этом, оно в принципе о том же.
На работе php-шники делают нам REST-API. Когда десериализуем Json происходит сущий ад. Числа в одном и том же запросе то в string, то во float, а если число 1, то приходит int. Писали, ругались. Проблемы они не видят, видимо слово «типы» им вообще не знакомо. Не хочу обижать всех, кто пишет на php, но сам язык предрасположен к написанию говнокода. В новых версиях намечается прогресс, хоть это радует.
На работе сишники присылают нам в php xml, валидацию не проходит, даже кавычки расставлены неверно. Не хочу обижать никого, но c++ предрасположен к генерации невалидного xml. Проблемы они не видят, их собственноручная библиотека проходит все тесты. Надеюсь в версии c++ 15 эту проблему решат, а пока хотим перейти на nodejs.
Если в c++ вы указали тип поля int, то string вы туда никак не засунете. Чего не скажешь о php. Я вам реальный случай из жизни привожу, а вы передёргиваете.
Вы рассказали реальный случай из жизни неквалифицированных работников (и видимо такого же отдела кадров и руководителя тех. отдела). Не понятно, причем тут PHP абсолютно, именно поэтому я привела пример с кавычками, а не типами.
И если вы не можете выставить элементарные требования к формату, то хоть кто вам будет слать JSON, и хоть с какими типами. А если формат есть, а работа выполняется некачественно, то можно обвинять язык, ОС, железо, ну вы поняли.
В языке со статической типизацией даже совсем зелёный новичок не совершил бы таких ошибок.
Подразумевал сильную типизацию, не статическую.
Совершил бы другие, и? Вы обвиняете язык в его возможностях?
А зачем ругаться? Есть такая штука json-schema. И тут как бы одно из двух либо результат ей соответсвует и тогда никаких претензий друг к другу. Либо нет, тогда значит апи не соответствует спеке.
Json это лишь пример. Я говорю о том, что люди понятия не имеют, чем отличается «1», 1.0 и 1. Хотя пишут на php не первый год.
Всё это говорит о том, что программисту надо воздерживаться от неоднозначностей, предпочитать ===, а не ==, и вообще, писать ясный и читаемый код. При желании в любом языке можно найти разные «пасхалки», глюки и неоднозначности, — только зачем их все пихать в код? Опять же, юнит-тесты на что?
Sign up to leave a comment.

Articles