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つのケースすべてに当てはまりますが、最初のケースの本番サーバーでは誤った結果が得られ、残りの3つのケースでは真になります。

誰かが私が正確に何が起こっているのかを理解するのを手伝ってもらえますか?構成の観点から見逃していませんか?

4

4 に答える 4

9

とても簡単です....開発システムはWindowsで、本番サーバーはLinuxだと思いますか?

ほとんどの場合、WindowsバージョンのPHPは32ビットであり、Linuxは64ビットであるため、整数オーバーフローの問題が発生しています。

配列キー変換の条件を参照してください

  • 有効な整数を含む文字列は、整数型にキャストされます。たとえば、キー「8」は実際には8の下に格納されます。一方、「08」は有効な10進整数ではないため、キャストされません。
  • フロートも整数にキャストされます。これは、小数部分が切り捨てられることを意味します。たとえば、キー8.7は実際には8の下に保存されます。
  • Boolも整数にキャストされます。つまり、キー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_arrayarray_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(mixed $needle、array $ haystack [、bool $ strict = FALSE])

3番目のパラメーターstrictがTRUEに設定されている場合、in_array()関数は干し草の山にある針のタイプもチェックします。

このコードを実行すると

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

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

出力64ビット

string
string
integer
integer

出力32ビット

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ビットシステムではstringを返します。

解決策:すべてを文字列に変換array_keys($data)します。次にin_array("28000000000000003",array_keys($data),true);、3番目のパラメーターを使用します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が見つかりました

于 2013-02-11T12:16:28.563 に答える