社区内一哥们@smcboy 提出关于php中操做MongoDB存储整数问题,找到点资料花点时间翻译过来,是个很好的学习方式。@红薯 那篇讨论个人修改回复,仍然没有更新可恶啊~!!说实话我就是高一英语水平 为了这篇文章我算是绞尽脑汁,翻译了大半天,累死我了。科学精神难得、难得!! php
在我当前项目中大量是MongoDB,正在从传统RDBMS过分到key-value存储。Facebook中用户标识UserID使用64位Int数据类型存储,杯具的是 MongoDB的PHP驱动只支持32位整型数据,致使UserID被截断没法处理Facebook用户信息。 html
MongoDB数据采用BSON(Binary JSON)文档型存储,BSON有两种整型数据类型,一、32位有符号整型数据(INT); 二、64位有符号型整型数据(LONG)。因为PHP不支持大于8个字节整数,因此MongoDB PHP驱动只支持32位有符号整型数据存储。然而这样不是绝对的,在C类型 long 为64位平台上,PHP仍然能够正常支持64位整型数据; 除了在Windowns上,其余平台上C中long类型老是32位。
当PHP中整型存储到MongoDB中,PHP驱动会采用最低兼容原则用32位进行转换存储到MongoDB文档中。下面是测试案例(测试平台为 64位): git
$m = new Mongo(); $c = $m->selectCollection('test', 'inttest'); $c->remove(array()); //插入大于32位数据 $c->insert(array('number' => 1234567890123456)); $r = $c->findOne(); echo $r['number'], "\n";
输出: github
int(1015724736)二进制解析:
1234567890123456 = 100011000101101010100111100100010101011101011000000 1015724736 = 111100100010101011101011000000
代码:
mongodb
ini_set('mongo.native_long', 1); $c->insert(array('number' => 1234567890123456)); $r = $c->findOne(); var_dump($r['number']);输出:
int(1234567890123456)
在64位平台中,PHP程序中配置mongo.native_long 容许使用完整64位整型存储到MongoDB,本例中这种方式存储到MongoDB中类型为BSON LONG, 若是未开启此配置则类型为BSON INT类型。该配置对从MongoDB读取数据到PHP中一样有效。若是关闭该配置,当从MongoDB取出数据时PHP驱动会把 BSON LONG 类型转换为PHP的double类型,形成精度损失。下面看个例子: shell
ini_set('mongo.native_long', 1); //开启配置 $c->insert(array('number' => 12345678901234567)); ini_set('mongo.native_long', 0); //关闭配置 $r = $c->findOne(); var_dump($r['number']);输出:
float(1.2345678901235E+16)在32位平台中 mongo.native_log 参数配置不起任何做用,仍然会以BSON INT 类型存储。
$int32 = new MongoInt32("32091231"); $int64 = new MongoInt64("1234567980123456");使用该对象能够像正常使用插入、更新、查询等操做
$m = new Mongo(); $c = $m->selectCollection('test', 'inttest'); $c->remove(array()); $c->insert(array( 'int32' => new MongoInt32("1234567890"), 'int64' => new MongoInt64("12345678901234567"), )); $r = $c->findOne(); var_dump($r['int32']); var_dump($r['int64']);输出结果:
int(1234567890) float(1.2345678901235E+16)能够看到对返回结果没任何改变。BSON INT类型仍然是 int型,BSON LONG 类型变为 double类型。若是我启用 mongo.native_long 配置,经过MongoInt64类库转换,在64位平台上,PHP中获取 BSON LONG 会返回正确int型,在32位平台上MongoCursorException会抛出提示信息。
$m = new Mongo(); $c = $m->selectCollection('test', 'inttest'); $c->remove(array()); $c->insert(array( 'int64' => new MongoInt64("12345678901234567"), )); ini_set('mongo.long_as_object', 1); $r = $c->findOne(); var_dump($r['int64']); echo $r['int64'], "\n"; echo $r['int64']->value, "\n";输出:
object(MongoInt64)#7 (1) { ["value"]=> string(17) "12345678901234567" } 12345678901234567 12345678901234567MongoInt32和MongoInt64 类基于对象的__toString()实现,因此返回的value值能够直接进行 echo,你只能获取一个整型字符串,因此请意识到MongoDB是类型敏感的,不会用对待字符串的方式对待数字,数字就是数字。
ini_set('mongo.native_long', 1); $m = new Mongo(); $c = $m->selectCollection('test', 'inttest'); $c->remove(array()); $nr = "12345678901234567"; $c->insert(array('int64' => new MongoInt64($nr))); $r = $c->findOne(array('int64' => $nr)); // $nr is a string here var_dump($r['int64']); $r = $c->findOne(array('int64' => (int) $nr)); var_dump($r['int64']);输出:
NULL int(12345678901234567)
下面列出关于不一样的参数启用状态,整型转换状况: json
PHP to MongoDB (32位系统) From PHP 函数 |
Stored in Mongo 学习 |
|
native_long=0 测试 |
native_long=1 |
|
1234567 |
INT(1234567) |
INT(1234567) |
123456789012 |
FLOAT(123456789012) |
FLOAT(123456789012) |
MongoInt32("1234567") |
INT(1234567) |
INT(1234567) |
MongoInt64("123456789012") |
LONG(123456789012) |
LONG(123456789012) |
PHP to MongoDB (64位系统):
From PHP |
Stored in Mongo |
|
native_long=0 |
native_long=1 |
|
1234567 |
INT(1234567) |
LONG(1234567) |
123456789012 |
garbage |
LONG(123456789012) |
MongoInt32("1234567") |
INT(1234567) |
INT(1234567) |
MongoInt64("123456789012") |
LONG(123456789012) |
LONG(123456789012) |
Stored in Mongo |
Returned to PHP as |
||
long_as_object=0 |
long_as_object=1 |
||
native_long=0 |
native_long=1 |
||
INT(1234567) |
int(1234567) |
int(1234567) |
int(1234567) |
LONG(123456789012) |
float(123456789012) |
MongoCursorException |
MongoInt64("123456789012") |
Mongo to PHP (64位系统):
Stored in Mongo |
Returned to PHP as |
||
long_as_object=0 |
long_as_object=1 |
||
native_long=0 |
native_long=1 |
||
INT(1234567) |
int(1234567) |
int(1234567) |
int(1234567) |
LONG(123456789012) |
float(123456789012) |
int(123456789012) |
MongoInt64("123456789012") |
总结:
综上所述能够看到想得到64位的支持仍是很棘手的,若是你只须要在64为平台上运行代码,咱们推荐使用 mongo.native_long=1 配置参数。当整数存储到MongoDB,取出是仍然是整型数据,从而达到支持64位的目的。
若是你丫就是想要在32位平台(包含Windows 64位上的PHP),你没办法使用获得可靠的整型数据,必须使用MongoInt64 类来实现。这也会带来其余问题,如:你必须在初始化的时候处理字符串类型的数字。也要注意MongoDB Shell 将全部的数字做为float浮点型数据处理,这并不能表明64位整型数字,相反将做为浮点型数字。全部不要在shell模式下进行数据修改,这样会致使类型转换!!
案例:
$m = new Mongo(); $c = $m->selectCollection('test', 'inttest'); $c->remove(array()); $c->insert(array('int64' => new MongoInt64("123456789012345678")));MongoDB Shell模式下:
$ mongo MongoDB shell version: 1.4.4 url: test connecting to: test type "help" for help > use test switched to db test > db.inttest.find() { "_id" : ObjectId("4c5ea6d59a14ce1319000000"), "int64" : { "floatApprox" : 123456789012345680, "top" : 28744523, "bottom" : 2788225870 } }当咱们经过驱动获取支持64位数据,能够获得靠谱的结果:
ini_set('mongo.long_as_object', 1); $r = $c->findOne(); var_dump($r['int64']);输出:
object(MongoInt64)#7 (1) { ["value"]=> string(18) "123456789012345678" }
这个新函数方式将会在 mongo 1.0.9 release 版本中推出,能够经过PRCL pecl install mongo 获取。
剩下的就靠命运了,祝你好运。
翻译:OSC民工