4063 читателя, 405 постов
Администрация
Модераторы
Блог для обмена опытом
если $a == $b и $b == $c, то $a == $cПервое, что приходит в голову: "это ж очевидно, конечно обладает!"
'0' == false; // true
false == ''; // true
'0' == ''; // false :)))
Добро пожаловать в увлекательный мир PHP. Занавес...
P.S.: Вот тут (и ещё тут, спасибо
Kupyc
P.P.S.: Пост не для холивара, а к сведению и чтобы улыбнуться. Сам активно пишу на PHP.
комментарии (120)
Спасибо, сейчас добавлю...
вот оператор === как раз таки обладает таким нужным и полезным свойством :)
Если нужны строгие определения переменных, то вам в C++.
Конечно, к каждому большому удобству идёт в комплекте и своё маленькое неудобство. О нём достаточно просто не забывать.
Кстати, оператор "==" в Perl работает примерно аналогично.
1
Именно что "примерно" ;)
Эксперемент №1. Проверка оператора ===
time echo "<?php \$a='0'; \$b=1; for (\$i = 0; 10000000 > \$i; ++\$i) \$c = (\$a === \$b); ?>" | php
real 0m1.889s
user 0m1.864s
sys 0m0.012s
Эксперемент №2. Проверка оператора ==
time echo "<?php \$a='0'; \$b=1; for (\$i = 0; 10000000 > \$i; ++\$i) \$c = (\$a == \$b); ?>" | php
real 0m3.132s
user 0m3.120s
sys 0m0.008s
Очевидно, что оператор === почти в два раза быстрее чем ==. Для достоверности эксперемента, замеры произвёл несколько раз. Причина банальна: при операторе === интерпретатор не производит преобразование типов: если не совпали, то false.
time echo "<?php \$a='0'; \$b=1; for (\$i = 0; 10000000 > \$i; ++\$i) \$c = 0; ?>" | php
real 0m1.662s
user 0m1.652s
sys 0m0.004s
Операторы сравнения и тождественности, это разные операторы, каждый для своего случая.
Если бы один из них был определенно лучше другого во всех случаях, то он бы один в языке и остался.
Для более строгого сравнения есть ===.
перед сравнением пхп должен привести все к одному типу
'0' == false; // (bool)'0' вернет false
false == ''; // тут тоже самоме по сути
'0' == ''; // а тут уже сравнение строк
ml@pivo ~ $ echo "<? echo 0 == '' ?>" | php && echo
1
но это не значит что '0' == ''
Отсутствие транзитивности вполне можно получить и в других языках, где есть традиция определения операторов для сложных типов данных.
Так что ничего пародоксального в данном факте нет, я считаю. Оператор не обязан быть транзитивен при манипуляциях со столь далекими друг от друга типами.
А в том факте действительно ничего парадоксального нет, нужно просто понимать механизмы языка, с которым имеешь дело.
if(strlen($string))
и самому спокойней и каждому кто будет твой код ковырять сразу бедут понятно что $string это строка
Операция сравнения строк тоже тривиально, ага?
когда же человек уже навострился в программировании в C-подобных языках, это уже не нужно, и будет только мешать
А классическое образование приводит к забитой теорией голове и неспособности решать практические задачи.
У знакомых тут команда классиков пишет. По два высших у каждого. Умные алгоритмы знают, да. А вот о безопасности понятия ВООБЩЕ не имеют, SQL injection на каждом углу пролезает.
В противном случае это сродни магии. "Ух-ты как себя ведет программа!" на каждом шагу возникает.
Исправьте пожалуйста весь пост
Лучше распишите, что происходит, когда вы делаете ==, а не просто "первое, что приходит на ум". Так напишите, тем, кто не знает, почему ее тут нет.
А то пока от топика у новичков создается впчатление, что в пыхе опять что-то не так, хотя на самом деле это в знаниях "не так" ;)
А зачем расписывать то, что в прекрасной документации php и так написано чёрным по белому? Ссылки я дал.
А что новичков обманывать, в пыхпыхе действительно много что "не так", однако мне это не мешает его по своему "любить" и писать на нём много лет.
Мои знания тут не причём. Почему транзитивности нет в данном случае - совершенно понятно - и я уверен, что большинство программистов знает принципы сравнения, однако я так же уверен, что почти никто не обращал внимания на отсутствие транзитивности.
'0' — это строка
'' — это строка
false — это булево
(boolean) '0' — это булево
(boolean) '' — это булево
получается что: (boolean) '0' == (boolean) '' == false
Свойство транзитивности не может оставаться строгим когда идет преобразование типов из-за возможных потерь информации.
'0'== false // true
false == '' // true
'0' == '' // false Строка содержащая 1 символ, не равна пустой строке.
Но
0 == '' // true
Потому что:
$a='0';
$b=false;
$c='';
to STRING:
a=0
b=
c=
to BOOL:
a=
b=
c=
to INT:
a=0
b=0
c=0
Не надо. Ни одному человеку который учился не по книгам "PHP за 24 часа" даже в голову не прийдет такое сравнивать ибо результат вполне предсказуем.
$_GET['here_is_my_zero'] == '' будет работать как в примере...
про Java или C# такой спор в принципе не мог произойти, ибо сравнивать в них можно только одинаковые типы (даже при сравнении short и long IDE будет намекать на ошибку, а String'и в Java через "==" не сравнивают)...
а тут с одной стороны вроде как гибкий инструмент, а с другой "сдуру можно и хер сломать" :)
>даже в голову не прийдет такое сравнивать
прийдет или не прийдет дело десятое. это же иллюстрация :)
Это я к тому, что учить язык надо по вот таким источникам. Тогда и иллюстрировать ничего не прийдется. Те кто действительно знает PHP прекрасно понимают в чем фишка, и почему работает именно так. Те же кто знаком с ним по упомянутым мною выше "... за 24 часа" прочитают, забудут через 15 минут и уж тем более не извлекут никакого для себя урока.
'муха' == true
'слон' == true
'муха' == 'слон'
Ваш пример, в отличие от моего, можно размножить до бесконечности :)
Однако вероятность ошибки по неосторожности в случае с нулём и пустой строкой больше.
$x == false; // true
false == $y; // true
$x == $y //???
тогда лучше так
intval($x) == intval($y)
или так
strval($x) == strval($y)
в зависимости от контекста
Только зачем публично определять свою позу - все пхпшники в г-не, а я один в белом?
mysql> SELECT '0'=FALSE FROM DUAL;
+-----------+
| '0'=FALSE |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
mysql> SELECT FALSE='' FROM DUAL;
+----------+
| FALSE='' |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
mysql> SELECT '0'='' FROM DUAL;
+--------+
| '0'='' |
+--------+
| 0 |
+--------+
1 row in set (0.00 sec)
Фича известная.
И чего к PHP докопались? Тогда уж с Перла начните.
а сколько и какие именно средства дебага на PHP вы сможете сходу назвать?
> displays structured information about one or more expressions (php.net)
А это не одно ли и то же? Как пожно предположить, цитата относится далеко не к описанию echo.
> результат мне известен
так обычно пишут, когда знают(!) не только тип данных возвращаемых операцией сравнения, но и результат этого сравнения. О вот он, как мне показалось ( "Это обьяснить и понять уже сложнее" (с) ) для вас немного остался загадкой.
П.С.: прошу извинить, если мой тон показался вам излишне резким. Ни в коем случае не хотел на вас "наезжать" ибо и сам на абсолютное знание не претендую.
А явное преобразование boolean в integer у меня пока не вызывает сомнение. Поэтому я пишу echo.
Кроме того, автоматически приписать в начале строки echo проще нежели писать более сложную регулярку для окружения результата var_dump'ом. ;)
Я ведь, ествественно, не так смотрел всё это - это просто минималистический тестовый пример.
echo (int)("0xff"==0)."\n";
echo (int)((int)"0xff"==0)."\n";
echo (int)("0xff"==255)."\n";
Моя запись:
var_dump("0xff"==0, (int)"0xff"==0, "0xff"==255);
Какую-какую, простите, регулярку писать?
(int)("0xff"==0)
строка 0xff превосходно конвертируется в число в 16-ной форме. Далее приводится к десятичному 255. Это не равно нулю, а false при преобразовании в int становится нулем.
(int)((int)"0xff"==0)
Здесь интерпретатор не может преобразовать строку к 16-ричному виду, поскольку вы ему указываете на необходимость сразу преобразовать строку в интеджер. Используется явное преобразование, что дает нам 0, значит результат true, как следствие - 1
(int)("0xff"==255)
См. первое решение.
А приводит оно так, ибо сказано: the default is base 10
Соглашусь с тем, что это несколько странно. Но как уже здесь писали, хотя несколько по другому поводу - для хорошего(!) разработчика главное такие тонкости знать и уметь использовать себе во благо.
Кстати, одна из причин написать в блог развёрнуто и с примерами, была в том, что я хотел проиллюстрировать это поведение. Именно для того, о чём Вы написали выше (про разработчика). Собьсно тот пост вырос из развёрнутого обьяснения новенькому почему if ($rt=="0") {...} срабатывает, когда $rt==="all".
Так зачем вы вообще за PHP взялись, если он ненормальный?
Дело в том, что в PHP оператор == НЕ ЯВЛЯЕТСЯ оператором равенства. Он лишь означает equivalence операндов, что в переводе на русский означает "равнозначность", но отнюдь не "равенство". Вот так непонимание русского языка (не важно кем, переводчиком либо читателем) приводит к непониманию азбучных истин программирования.
Отношение == на множестве строк и булевых значений не определено, поэтому строка приводится к булевому значению и выполняется операция определенная на множестве булевых значений. Так же, как и в C++.
Остальное уже было сказано.
А лучше выучить какой-нибудь типизированный язык для разнообразия.
Вообще если человек начинает программировать с PHP (!) - велика вероятность не стать хорошим программистом.
Этот топик во мне вызвал чувство деградации... сам пишу на PHP, т.к. работа вынуждает. Грустно. Эх... пойду что-ли Страуструпа почитаю...
Сам, сильно увлёкшись пхп, и забыв о типах, потом довольно болезненно начинал сишарп.
Зато не нужно парится о типах в процессе кодинга. PHP позволяет мне излагать свои мысли прямо по ходу их поступления, не отвлекаясь на объявления переменных, размышления о том, какой тип рациональнее. Меня не ставят в строгие границы, как это, например, обожает делать C#.
В первой ситуации строку сравнивают с булевым типом. Пхп преобразует строку в bool и сравнивает 0 ? false. Конечно же, равны.
Кстати, это популярный источник ошибок. Ошибки, основанные на этом равенстве я находил даже в IPB. А именно, когда программист хочет проверить, указана ли строка: if ( $string ) { .. } Очевидно, что если юзер напишет строку "0", то условие не выполнится. Благодаря этому, в недавней версии ИПБ нельзя было поставить личный статус "0".
Вторая ситуация очевидна.
В третьей ситуации сравниваются две строки. Никакого преобразования не происходит. Две строки нифига не одинаковые, следовательно false;