我要在这里做的基本上是从$stats
开始并获得一个包含四个数组的数组$counts
,其中每个数组都是一对: key是以毫秒为单位的时间戳< / strong>而值是计数。我在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']);
用虚拟值覆盖虚拟数组。
$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
答案 0 :(得分:7)
PHP将nummeric(so,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下。
答案 1 :(得分:1)
您是否在PHP文档中找到了表明数组键最大长度的内容?
PHP手册定义如下:“一个键可以是整数或字符串。”(Source)
每种数据类型,整数也是有限的。这在计算中很常见。根据软件或底层处理器处理整数的方式,它们可以翻转,放置或顶部。
在你的情况下,当越过边界时,它会转到最小的负数。我称 flip 其他人可能称之为溢出或环绕。
您可以使用PHP_INI_Min
和PHP_INI_MAX
了解边界。
注意字符串键,也有一个限制,它通常不能大于2GB。只是说。
答案 2 :(得分:0)
请阅读php文档中关于整数溢出的部分。 http://www.php.net/manual/en/language.types.integer.php#language.types.integer.overflow
“如果PHP遇到超出整数类型边界的数字,它将被解释为浮点数。而且,导致超出整数类型边界的数字的操作将返回浮点数。”< / p>
答案 3 :(得分:0)
好的,稍微研究表明浮点数,因为数组键被截断为整数。所以我的大浮点数被截断为整数会导致溢出。仍在寻找官方文档链接。
查看此(已关闭)错误Array keys converted from float to integer以及此article和此pull request。
编辑:在PHP documentation上找到:
密钥可以是整数或字符串。值可以是任何值 类型。
此外还会发生以下关键演员:
浮动也被投射到 整数,这意味着小数部分将被截断。例如。 密钥8.7实际上将存储在8下。