Вопрос по arrays, php – Почему in_array () ошибочно возвращает true с этими (большими числовыми) строками?

43

Я не понимаю, что не так с этим кодом. Он возвращает "найдено", чего не должно быть.

<code>$lead = "418176000000069007";
$diff = array("418176000000069003","418176000000057001");

if (in_array($lead,$diff))
    echo "Found";
else
    echo "Not found";
</code>
Вот соответствующая запись об ошибке:bugs.php.net/bug.php?id=54547, Это довольно юмористическое чтение. Vinnyq12
@ThiefMaster Слишком легко взломать. Пожалуйста, предоставьте ответ вместо напыщенной речи в следующий раз :) Clement Herreman
Можете ли вы воспроизвести его с не номерами? Preet Sangha
Дело в том, чтоPHP is a broken language. ThiefMaster♦
@ClementHerreman: уже были хорошие ответы;) ThiefMaster♦

Ваш Ответ

9   ответов
139

Note: это поведение было изменено в PHP 5.4.

По умолчанию,in_array использует свободное сравнение (==), что означает, что числовые строки преобразуются в числа и сравниваются как числа. До PHP 5.4, если у вас не было достаточной точности в типе с плавающей точкой вашей платформы, разница была потеряна, и вы получили неправильный ответ.

Решение состоит в том, чтобы включитьstrict сравнение (===), передав дополнительнуюBoolean параметр дляin_array:

  $lead = "418176000000069007";
  $diff = array("418176000000069003", "418176000000057001");

  if ( in_array($lead, $diff, true) ) 
    echo "Found";
  else
    echo "Not found";

Затем строки сравниваются как строки без числового приведения. Однако это означает, что вы теряете эквивалентность строк по умолчанию, например & quot; 01234 & quot; и "1234".

Это поведениебыло сообщено как ошибка и исправлено в PHP 5.4. Числовые строки по-прежнему преобразуются в числа по сравнению с==, но только если значение строки соответствует числовому типу платформы.

так что, по вашему мнению, $ lead = & quot; 001 & quot ;; $ arr = array ("1", "01"); echo in_array ($ lead, $ arr); должен вернуть истину?
Это самый информативный ответ. +1
@gavriel: это, к сожалению, не соответствует действительности; если строка выглядит как число, она преобразуется в единицу. Добавьте несколько нулей, чтобы числовое сравнение теряло точность даже при вашей 64-разрядной установке, и это легко продемонстрировать:php -r 'echo("4181760000000000069003" == "4181760000000000057001"),"\n";' возвращает 1.
@tomerw: на вопрос дан ответ, поэтому мы не должны останавливаться на касательной в комментариях; не стесняйтесь начать чат, если хотите. Но я скажу, что (1) ваш код на самом деле возвращает 1 (= true) и (2) я давно разочаровался в поведении PHP, имеющем какое-либо сходство с моим мнением о том, что это такое; должен & Quot; делать. :)
Насколько я знаю, == не преобразует строки в числа. Он преобразует типы, если они разные, но сравнение двух строк IMHO не делает
16

418176000000069007 изменен на 2147483647 (целочисленный предел PHP). Вот почему вы получаетеFound.

пытатьсяin_array($lead, $diff, true)

If the third parameter strict is set to TRUE then the in_array() 
function will also check the types of the needle in the haystack. 
@Amit Set$strict вtrue: in_array($lead, $diff, true)
Вопрос в том, почему это приводит его кint совсем?
оооо ... боже ... я почти перепробовал каждую комбинацию ... в любом случае есть ли решение ?? www.amitpatil.me
Аххаааа .... @ deceze ... твое предложение сработало для меня ... большое спасибо. www.amitpatil.me
3

$lead = "418176000000069007";
$diff = array("418176000000069003","418176000000057001");

if(in_array($lead, $diff, true)) {
    echo "Found";
} else {
    echo "Not found";
}
2

и вы действительно хотите сравнить / найти в массиве, то есть хитрость

$lead = "a418176000000069007";
$diff = array("a418176000000069003","a418176000000057001");

if (in_array($lead,$diff))
    echo "Found";
else
    echo "Not found";

то есть каким-то образом вы должны добавлять символ perticular к каждому числу. Они будут вести себя как строки в сравнении и, следовательно, будут давать правильный результат.

2

in_array() Функция также проверит типы иголки в стоге сена, а также потому, что предел превышает максимальное целочисленное значение.

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

if (in_array($lead,$diff,true))
2

Руководство по PHP: преобразование строк в числа:

When a string is evaluated in a numeric context, the resulting value and type are determined as follows.

The string will be evaluated as a float if it contains any of the characters '.', 'e', or 'E'. Otherwise, it will be evaluated as an integer.

Как уже упоминалось, вы должны использовать строгийin_array:

bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ) Searches haystack for needle using loose comparison unless strict is set.

Некоторые упоминалиPHP_INT_MAX, Это было бы2147483647 в моей системе. Я не совсем уверен, что это проблема, посколькуручные состояния:

If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead.

Ноточность с плавающей точкой должно быть достаточно высоким ...

Что бы ни было «реальным» источник этой проблемы, просто используйте строгийin_array чтобы исправить эту проблему.

56

PHP,this was a bug and is rectified and solved in newer versions of PHP.

Значения превышаютPHP_INT_MAX.

Пробоватьecho/print_r $lead а также$diff без использования кавычек. Это приведет

$lead ---> 418176000000070000  
$diff ---> Array ( [0] => 418176000000070000 [1] => 418176000000060000 )

так что в этом случаеin_array результат верный!

так что пользуйтесьstrict сравнение вin_array() установив третий аргумент вin_array() какtrue

     if(in_array($lead,$diff,true)) //use type too
       echo "Found";
     else
       echo "Not found";
?>

Попробуй это. Это будет работать.

5

in_array должен быть строгим.

  $diff = array("418176000000069003","418176000000057001");

  if(in_array($lead,$diff,true)) 
    echo "Found";
  else
    echo "Not found";

Эта проблема связана сyour numbers are exceeded from the defined integer limit

Примечание: максимальное значение зависит от системы. 32-битные системы имеют максимальный целочисленный диапазон со знаком-2147483648 в2147483647, Так, например, в такой системе,intval('1000000000000') вернусь2147483647, Максимальное целочисленное значение со знаком для 64-битных систем9223372036854775807.

6

PHP_INT_MAX, Попробуй сделатьif(in_array($lead,$diff,true)) вместо.

Похожие вопросы