简体   繁体   中英

Why does in_array() wrongly return true with these (large numeric) strings?

I am not getting what is wrong with this code. It's returning "Found", which it should not.

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

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

Note: this behavior was changed in PHP 5.4.

By default, in_array uses loose comparison ( == ), which means numeric strings are converted to numbers and compared as numbers. Before PHP 5.4, if you didn't have enough precision in your platform's floating-point type, the difference was lost and you got the wrong answer.

A solution is to turn on strict comparison ( === ) by passing an extra Boolean parameter to in_array :

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

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

Then the strings are compared as strings with no numeric coercion. However, this means you do lose the default equivalence of strings like "01234" and "1234".

This behavior was reported as a bug and fixed in PHP 5.4. Numeric strings are still converted to numbers when compared with == , but only if the value of the string fits in the platform's numeric type.

Note: This was a bug in PHP old versions and is corrected in PHP 5.4 and newer versions.

It is because of the limitations of the number storage in PHP

The real problem here is because of the PHP_INT_MAX - the value exceeded in our case.

Try to echo / print_r $lead and $diff without using the quotes. It will result

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

so, in this case, the in_array result is true!

so use strict comparison in in_array() by setting third argument in in_array() as true

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

Try this. It will work.

It's because of one defect in PHP. 418176000000069007 is modified to 2147483647 (integer limit of PHP). That is why you are getting Found .

try 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. 

The values exceed PHP_INT_MAX . Try doing if(in_array($lead,$diff,true)) instead.

in_array should be stricted.

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

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

This problem is due to your numbers are exceeded from the defined integer limit

Note: the maximum value depends on the system. 32 bit systems have a maximum signed integer range of -2147483648 to 2147483647 . So for example on such a system, intval('1000000000000') will return 2147483647 . The maximum signed integer value for 64 bit systems is 9223372036854775807 .

Try using brackets and use strict mode:

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

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

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, and because the limit is beyond the maximum integer value.

So 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. Check the PHP manuals.

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

From PHP Manual: String conversion to numbers :

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.

As some others mentioned, you should use strict for in_array :

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

Some mentioned PHP_INT_MAX . This would be 2147483647 on my system. I'm not quite sure if this is the problem as the manual states :

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.

But floating point precision should be high enough...

Whatever might be the "real" source of this problem, simply use strict for in_array to fix this problem.

If that is your problem and you really want to compare/find in array then there is a trick

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

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

ie somehow you have to prepend a perticular character to every number. They will behave as strings in comparison and hence give correct result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM