5

ここで私がやろうとしているのは、基本的には、4 つ$statsの配列を含む配列を取得することです。ここ$countsで、各配列はペアです。キーはミリ秒単位のタイムスタンプで、値はカウントです。Windows 7 x64 で PHP バージョン 5.3.14 を使用しています。

質問: なぜ負の配列キーの値を取得しているのか、どうすればこれを回避できるのでしょうか? var_dump()以下を参照してください。

$stats = array();
$stats[] = array(
    'subtype' => 'small_text_message_user',
    'count'   => '6',
    'date'    => '2012-06-03'
);

$stats[] = array(
    'subtype' => 'small_text_message_auto',
    'count'   => '3',
    'date'    => '2012-07-03',
);

$stats = array(
    'subtype' => 'newsletter_auto',
    'count' => '11',
    'date' => '2012-07-16',
);

$counts = array();
$counts['small_text_message_user'] = array();
$counts['small_text_message_auto'] = array();
$counts['newsletter_user']         = array();
$counts['newsletter_auto']         = array();

foreach($data as $stat) :
    $millisecs = 1000 * strtotime($stat['date']);
    $count     = intval($stat['count']);
    $counts[$stat['subtype']][$millisecs] = $count;
    var_dump($millisecs, $count);
endforeach;

var_dump($counts);

そして結果は間違っています:

float 1338674400000

int 6

float 1341266400000

int 3

float 1342389600000

int 11

array (size=4)
  'small_text_message_user' => 
    array (size=1)
      -1355396352 => int 6
  'small_text_message_auto' => 
    array (size=1)
      1236603648 => int 3
  'newsletter_user' => 
    array (size=0)
      empty
  'newsletter_auto' => 
    array (size=1)
      -1935163648 => int 11

例 (実際に動作します) は、「ダミー」配列を生成する短いコードです。

public function createTimestampRangeFromDates(\DateTime $from,
    \DateTime $to = null)
{
    $start = strtotime($from->format('Y-m-d 00:00:00'));
    $limit = strtotime(sprintf('%s 00:00:00', $to ? $to->format('Y-m-d')
        : date('Y-m-d') . ' 00:00:00'));

    return range($start, $limit, 86400);
}

// Test
$start = new \DateTime('2012-06-27');
$end   = new \DateTime('2012-07-07'); // 10 days

$timestamps = createTimestampRangeFromDates($start, $end);
$millisecs  = array_combine($timestamps, array_fill(0, count($timestamps), 0));

var_dump($millisecs);

これは正常に機能し、大きな整数をキーとして取得します:

array (size=11)
  '1340748000000' => int 0
  '1340834400000' => int 0
  '1340920800000' => int 0
  '1341007200000' => int 0
  '1341093600000' => int 0
  '1341180000000' => int 0
  '1341266400000' => int 0
  '1341352800000' => int 0
  '1341439200000' => int 0
  '1341525600000' => int 0
  '1341612000000' => int 0

ああ、これが問題なら、このコードの目的は次のようなことです:

$values = array_merge($millisecs, $counts['newsletter_auto']);

つまり、ダミー配列を実際の値でオーバーライドしています。

@hakre の提案に従って小さなテスト ケースを更新する

$result1 = array();
$result2 = array();
$test    = array('2012-06-03', '2012-07-03', '2012-07-16');

foreach($test as $date) :
    $result1[1000 * strtotime($date)] = 0;
    $result2[] = 1000 * strtotime($date);
endforeach;

var_dump($result1); // Not working
var_dump($result2); // Works

結果は の負のキーを示しています$result1。問題はキーのみであり、値ではありません (値が に変換されるためfloat):

array (size=3)
  -1355396352 => int 0
  1236603648 => int 0
  -1935163648 => int 0

array (size=3)
  0 => float 1338674400000
  1 => float 1341266400000
  2 => float 1342389600000
4

4 に答える 4

7

PHP は、数値 (つまり、float または integer) の配列インデックスを整数に変換します。

ckruse@lin ~ $ php -r 'var_dump(array(1.2 => "a"));'
array(1) {
  [1]=>
  string(1) "a"
}

そのため、配列インデックスが非常に大きい場合、PHP によって計算時に float に変換され、インデックスとして使用されると整数に戻されます。これは、大きなインデックスに対して整数オーバーフローが発生することを意味します。

解決策は、文字列インデックスを使用することです。

ckruse@lin ~ $ php -r 'var_dump(array(((string)1.2) => "a"));'
array(1) {
  ["1.2"]=>
  string(1) "a"
}

編集: http://php.net/manual/en/language.types.array.phpのマニュアルは次のように述べています。

浮動小数点も整数にキャストされます。これは、小数部分が切り捨てられることを意味します。たとえば、キー 8.7 は実際には 8 の下に格納されます。

于 2012-07-08T12:15:27.037 に答える
1

配列キーの最大長を示す PHP ドキュメントを見つけましたか?

PHP マニュアルでは、次のように定義されています。「キーは整数または文字列のいずれかです。」ソース

すべてのデータ型と同様に、整数も制限されています。それはコンピューティングでは一般的です。ソフトウェアまたは基盤となるプロセッサによる整数の処理方法に応じて、反転、フロア、またはトップのいずれかになります。

あなたの場合、境界を越えると最小の負の数になります。私はそれをフリップと呼び、他の人はそれをオーバーフロー またはラップアラウンドと呼ぶかもしれません。

PHP_INI_Minとで境界を調べることができますPHP_INI_MAX

文字列キーにも注意してください。制限もあり、通常は 2GB を超えることはできません。ただ言って。

于 2012-07-08T12:24:08.403 に答える
0

PHPドキュメントの整数オーバーフローに関する部分をお読みください。http://www.php.net/manual/en/language.types.integer.php#language.types.integer.overflow

「PHPが整数型の境界を超える数値を検出した場合、代わりにfloatとして解釈されます。また、整数型の境界を超える数値を生成する操作は、代わりにfloatを返します。」

于 2012-07-08T12:09:05.920 に答える
0

OK、少し調査したところ、配列キーとしての float は integer に切り捨てられることがわかりました。そのため、整数に切り捨てられた大きな浮動小数点数がオーバーフローします。まだ公式ドキュメントのリンクを探しています。

この (クローズド) バグArray keys Converted from float to integerと、この記事およびこのプル リクエストを参照してください。

編集: PHPのドキュメントで見つかりました:

キーは整数または文字列のいずれかです。値は任意の型にすることができます。

さらに、次のキー キャストが発生します。

浮動小数点も整数にキャストされます。これは、小数部分が切り捨てられることを意味します。たとえば、キー 8.7 は実際には 8 の下に格納されます。

于 2012-07-08T12:14:16.023 に答える