11

请查看以下代码,它在不同的机器上给出不同的结果:

$data = array(
    "28000000000000003" => 'ABC',
    "28000000000000001" => 'PQR'
);

echo "1.".in_array("28000000000000003",array_keys($data),true);

echo "2.".in_array("28000000000000003",array_keys($data));

echo "3.".in_array("28000000000000003",array("28000000000000003","28000000000000001"),true);

echo "4.".in_array("28000000000000003",array("28000000000000003","28000000000000001"));

正如预期的那样,我们本地服务器上所有 4 个案例的结果都是正确的,而在第一个案例的生产服务器上,它给出了错误的结果,而在其余三个案例中它给出了正确的结果

谁能帮我理解到底发生了什么?从配置的角度来看,我错过了吗?

4

4 回答 4

9

它很简单....让我猜你的开发系统是windows,你的生产服务器是linux?

您遇到整数溢出问题,因为您的 Windows 版本的 PHP 很可能是 32 位,而 linux 是 64 位

请参阅数组键转换的条件

  • 包含有效整数的字符串将被转换为整数类型。例如,键“8”实际上将存储在 8 下。另一方面,“08”不会被强制转换,因为它不是有效的十进制整数。
  • 浮点数也被转换为整数,这意味着小数部分将被截断。例如,密钥 8.7 实际上将存储在 8 之下。
  • 布尔值也被转换为整数,即键 true 将实际存储在 1 下,而键 false 将存储在 0 下。
  • Null 将被强制转换为空字符串,即键 null 将实际存储在 "" 下。数组和对象不能用作键。这样做会导致警告:非法偏移类型。

那么会发生什么:

所以密钥在系统上28000000000000003是有效integer的,64bitString32bits系统上是有效的

我能够复制您的问题

echo "<pre>";
$data = array("28000000000000003" => 'ABC',"28000000000000001" => 'PQR');
$keys = array("28000000000000003","28000000000000001");
$keysDerived = array_keys($data);

var_dump(in_array("28000000000000003", $keysDerived, true));
var_dump(in_array("28000000000000003", $keysDerived));
var_dump(in_array("28000000000000003", $keys, true));
var_dump(in_array("28000000000000003", $keys));

输出

bool(false)    <----------------------- false instead of true 
bool(true)
bool(true)
bool(true)

这个问题与示例无关,in_array而是array_keys示例

示例代码

echo "<pre>"; 
$data = array("28000000000000003" => 'ABC',"28000000000000001" => 'PQR');
$keys = array("28000000000000003","28000000000000001");
$keysDerived = array_keys($data);
var_dump($keys,$keysDerived);

输出

array(2) {
  [0]=>
  string(17) "28000000000000003"    <------- Keys are String
  [1]=>
  string(17) "28000000000000001"
}
array(2) {
  [0]=>
  int(28000000000000003)           <------- They are converted to int on 64bits
  [1]=>
  int(28000000000000001)
}

见在线演示

这意味着它们不是同一类型...

in_array bool in_array ( 混合 $needle , array $haystack [, bool $strict = FALSE ] )

如果第三个参数strict设置为TRUE,那么 in_array() 函数还将检查haystack 中的 needle 类型

如果您运行此代码

foreach ( $keys as $key ) {
    echo gettype($key) . "\n";
}

foreach ( $keysDerived as $key ) {
    echo gettype($key) . "\n";
}

输出64Bits

string
string
integer
integer

输出 32Bits

string
string
string
string

简单的解决方法

echo "<pre>";
$data = array("28000000000000003" => 'ABC',"28000000000000001" => 'PQR');
$keys = array("28000000000000003","28000000000000001");
$keysDerived = array_keys_string($data);
var_dump($keys,$keysDerived);

var_dump(in_array("28000000000000003", $keysDerived, true));
var_dump(in_array("28000000000000003", $keysDerived));
var_dump(in_array("28000000000000003", $keys, true));
var_dump(in_array("28000000000000003", $keys));

输出

array(2) {
  [0]=>
  string(17) "28000000000000003"
  [1]=>
  string(17) "28000000000000001"
}
array(2) {
  [0]=>
  string(17) "28000000000000003"
  [1]=>
  string(17) "28000000000000001"
}
bool(true)
bool(true)
bool(true)
bool(true)

查看原始代码 查看修改后的代码

使用的功能

function array_keys_string(array $input) {
    $list = array();
    foreach ( $input as $k => $v ) {
        $list[] = (string)$k;
    }
    return $list;
}
于 2013-02-11T14:16:27.090 回答
6

您的本地服务器是 32 位的,而生产服务器是 64 位的。

PHP 文档说,在定义数组字面量时,键将被强制转换:

包含有效整数的字符串将被转换为整数类型。例如,密钥“8”实际上将存储在 8 之下。

因此,如果您尝试以下代码:

var_export(array("5" => "test"));

您将看到结果是一个带有数字键的数组5,而不是字符串键"5"

在您的情况下,您有大数字字符串作为键。在 32 位机器上,数字28000000000000003超过了可能的最大整数值 ( PHP_INT_MAX),因此数组键将保持为字符串,这就是在本地服务器上发生的情况。另一方面,在 64 位机器上,最大整数要大得多,并且"28000000000000003"被强制转换为integer,这就是您的生产服务器上发生的情况。

因此,在 64 位生产服务器上运行时,array_keys($data)返回整数数组。当您在第一个测试用例中尝试使用严格比较在其中找到一个字符串时,您会得到FALSE.

于 2013-02-11T13:37:37.750 回答
2

您可以尝试使用array_key_exists(). 关联数组键的长度有一些限制。查看链接获取详细帮助PHP 关联数组的键(索引)限制?

您可以增加密钥内存限制。利用ini_set('memory_limit', '1024M');

于 2013-02-11T12:14:31.227 回答
2

问题:如果您有长整数键,例如“329462291595”,它们将在 64 位系统上被视为此类,但在 32 位系统上将是字符串类型。

因此该函数array_keys($data)将在 64 位系统中返回 int,在 32 位系统中返回字符串

解决方案:将所有转换array_keys($data)为字符串。然后in_array("28000000000000003",array_keys($data),true);使用第三个参数true(用于严格检查)

function array_keys_string($arr){
    $arr_keys      = array_keys($arr);
    $res_arry      = array();
    foreach($arr_keys as $val){
       $res_arry[] = (string)$val;
    }
    return $res_arry;
}


echo "1.".in_array("28000000000000003",array_keys_string($data),true);

这将在两台服务器上为您提供相同的结果。

请参阅以下链接

参考:http ://www.php.net/manual/en/function.array-keys.php#105578

来自php.net:http://www.php.net/manual/en/function.in-array.php

<?php
$a = array('1.10', 12.4, 1.13);

if (in_array('12.4', $a, true)) {
    echo "'12.4' found with strict check\n";
}

if (in_array(1.13, $a, true)) {
    echo "1.13 found with strict check\n";
}
?>

上面的例子会输出: 1.13 found with strict check

于 2013-02-11T12:16:28.563 回答