Сравнение строки с целым числом дает странные результаты

#php #arrays

Вопрос:

Я действительно не понимаю, почему эта операция работает. Кто-нибудь может это объяснить?

 $test1 = "d85d1d81b25614a3504a3d5601a9cb2e";
$test2 = "3581169b064f71be1630b321d3ca318f";

if ($test1 == 0)
  echo "Test 1 is Equal!?";
if ($test2 == 0)
  echo "Test 2 is Equal!?";

// Returns: Test 1 is Equal!?
 

Для уточнения я пытаюсь сравнить строку "0" с $test переменными. Я уже знаю, что для исправления кода я могу просто вложить (как и следовало бы) 0 в "" s

Мне интересно, является ли это ошибкой PHP, ошибкой сервера или какой-то допустимой операцией. Согласно http://us3.php.net/types.comparisons это не должно было сработать.

Правка: Вычеркните это, по-видимому, в нем упоминается, что свободные сравнения между строкой и 0 верны. Но я все еще не знаю, почему.

Правка 2: Я пересмотрел свой вопрос, почему $test2 ценность "3581169b064f71be1630b321d3ca318f" не работает?

Комментарии:

1. какое значение $test не работает?

2. Если вы запустите код, он будет выводить только Test 1 is Equal!?

3. Редактировать 2 : потому что оператор сравнения автоматически приводит «3581169b064f71be1630b321d3ca318f» и, поскольку он начинается с чисел, он преобразуется в int и получает первую часть строки до буквы в качестве значения. и это сравнение (3581169 == 0) с ложным

4. FWIW, распечатка значений $test1 0 и $test2 0 дала бы ключ к пониманию того, что происходит. Или, альтернативно, значения $test1 и $test2 (с использованием оператора идентификации).

Ответ №1:

Из руководства по PHP:

Преобразование строк в числа

Когда строка оценивается в числовом контексте, результирующее значение и тип определяются следующим образом.

Строка будет оценена как плавающая, если она содержит какой-либо из символов».», » е » или «Е». В противном случае он будет оцениваться как целое число.

Значение задается начальной частью строки. Если строка начинается с допустимых числовых данных, это будет используемое значение. В противном случае значение будет равно 0 (нулю). Допустимые числовые данные-это необязательный знак, за которым следует одна или несколько цифр (необязательно содержащих десятичную точку), за которыми следует необязательный показатель степени. Показатель степени представляет собой букву » е » или «Е», за которой следует одна или несколько цифр.

Комментарии:

1. Все еще не думаю, что он должен преобразовываться в 0 или, по крайней мере, если он начинается с числа, не преобразовываться в десятичное число, если в строке есть ошибочные символы.

2. PHP не имеет типа «NaN», такого как Javascript (другой язык с произвольной типизацией), поэтому он в значительной степени должен быть преобразован в 0, так как другого способа не было бы (преобразование в NULL не сработало бы, потому что NULL также преобразуется в 0). Я думаю, что ответ заключается не в том, чтобы использовать свободное сравнение ( = = ) или сначала проверять строку.

3. В дополнение к этому ответу , при сравнении 2 элементов с == оператором , он преобразуется в общий тип. об этом говорится здесь. php.net/manual/en/language.operators.comparison.php

4. Лучший способ провести тест-использовать «пустой» метод: empty($test1)

5. @Pascal_dher — тьфу, нет. Причина: скажи, что ты имеешь в виду . Здесь цель состоит в том, чтобы задать вопрос «Равно ли это значение 0» . Выражение, похожее на намерение, очевидно , в то время как выражение, основанное на причудах языка, неочевидно . ИМХО. [Если бы единственным существующим компьютерным языком был PHP, то ваше предложение было бы разумным. Однако это все равно не сделало бы его лучшим способом; это просто сделало бы его эквивалентно хорошей альтернативой .]

Ответ №2:

Преобразование типов с помощью оператора ==

Оператор == представляет собой слабо типизированное сравнение. Он преобразует оба в общий тип и сравнивает их. Здесь объясняется, как строки преобразуются в целые числа.

Обратите внимание, что страница, на которую вы ссылаетесь, не противоречит этому. Проверьте вторую таблицу, где говорится, что сравнение целого 0 числа со строкой "php" с использованием == должно быть истинным.

Что происходит, так это то, что строка преобразуется в целое число, а нечисловые строки (строки, которые не содержат числа или начинаются с него) преобразуются в 0 .

Числовые и нечисловые строки

Строка, состоящая из числа или начинающаяся с числа, считается числовой строкой. Если в строке после этого числа есть другие символы, они игнорируются.

Если строка начинается с символа, который нельзя интерпретировать как часть числа, то она является нечисловой строкой и преобразуется в 0 . Это не означает, что числовая строка должна начинаться с цифры (0-9) — например "-1" , это числовая строка, потому что в этом случае знак минус является частью числа.

Так, например, ваша строка "d85d1d81b25614a3504a3d5601a9cb2e" не начинается с числа, поэтому она преобразуется в 0 . Но ваша вторая строка "3581169b064f71be1630b321d3ca318f" будет преобразована в целое 3581169 число . Так вот почему ваш второй тест работает по-другому.

Что вам следует делать

Вы, наверное, хотите:

 if ($test1 === "0")
 

Обратите внимание на использование тройных равных вместо двойных равных. Это гарантирует, что вы сравниваете строку, содержащую только нулевую цифру, и предотвращает любое преобразование типов.

Ответ №3:

После некоторого расследования выяснилось, что Эйдан из руководства по PHP упоминал, что любые строки, которые не начинаются с числа, будут преобразованы в 0 при приведении в виде целого числа.

Это означает, что:

 ("php" == 0) === true
("1php" == 0) === false
 

Очень раздражает и плохо документирован. Это было внизу комментариев на странице сравнения типов.

Комментарии:

1. Да, я так и понял, что это все. Действительно, плохая документация.

2. Я вовсе не думаю, что это плохая документация. Неявное преобразование типов является основой PHP, что очень хорошо объясняется в руководстве в разделе о типах, особенно в разделе «Манипулирование типами». == — это слабо типизированное сравнение; использование === вместо этого может помочь предотвратить запутанные ситуации.

3. См. Также «Преобразование строк в числа» по адресу us3.php.net/manual/en/…

Ответ №4:

 $test1 = "d85d1d81b25614a3504a3d5601a9cb2e";
 

эта строка начинается с «d», которое не является допустимым числом, значение var будет равно 0, и ваш тест № 1 пройдет.

 $test2 = "3581169b064f71be1630b321d3ca318f";
 

эта строка начинается с 3581169, что является допустимым числом, поэтому значение var будет равно тому значению, которое не равно 0.
Так что ваш тест № 2 не пройдет.

Ответ №5:

Я использовал некоторые преобразования и сравнения, чтобы проверить, является ли числовая строка числом:

 $test1="19de6a91d2ca9d91721d82f1bd8102b6";
   echo (float)$test1==$test1; //TRUE
   echo is_float($test1); //FALSE

   //Converting the string to float and then converting it to string and compare will do the trick 
   echo (string)((float)$test1)==(string)$test1; //FALSE


$test2="5.66";
   echo (float)$test2==$test2; //TRUE

   //Testing the numeric string using `is_float` wont give the expected result
   echo is_float($test2); //FALSE

   echo (string)((float)$test2)==(string)$test2; //TRUE