如何为Lithium数据库查询结果添加处理器?兼MongoInt64兼容问题
解决Lithium 1.1.1 + MongoDB 3.6 + PHP 5.6 下NumberLong转MongoInt64的兼容问题
我刚好碰到过一模一样的场景——PHP 5.6搭Lithium 1.1.1,把MongoDB从3.4升到3.6后,为了让旧驱动的aggregateCursor()正常跑,必须开mongo.long_as_object=true,结果Lithium处理NumberLong时全变成了MongoInt64对象,不管是序列化还是直接取值都出问题。下面给你几个实用的解决办法:
方案1:修改Lithium的MongoDB数据源类(最彻底)
找到Lithium框架里的lithium\data\source\MongoDb.php,在处理查询返回结果的方法里(比如_item或者_read),加一段对MongoInt64的转换逻辑:
// 假设在处理单个数据项的方法中,遍历字段时添加判断 foreach ($data as $key => &$value) { if ($value instanceof \MongoInt64) { // 这里推荐转成字符串,避免PHP整数溢出(尤其是32位系统) $value = (string) $value; // 如果确定数值在PHP整数范围内,也可以用 (int) $value } } unset($value);
这样所有从MongoDB读取的数据都会自动把MongoInt64转成原生类型,不用在业务代码里重复处理。
方案2:全局注册转换函数(灵活且无侵入)
如果不想改框架源码,可以在项目入口文件(比如index.php)里写一个递归转换函数,然后在获取数据后统一处理:
function convertMongoInt64($data) { if (is_array($data)) { foreach ($data as &$item) { $item = convertMongoInt64($item); } unset($item); } elseif (is_object($data)) { if ($data instanceof \MongoInt64) { return (string) $data; } // 处理Lithium的Entity对象 if (method_exists($data, 'data')) { $rawData = $data->data(); $converted = convertMongoInt64($rawData); $data->set($converted); } } return $data; } // 示例:在模型查询后调用 $records = Posts::find('all'); $records = convertMongoInt64($records);
这个方法不用动框架代码,适合临时应急或者不想修改框架的场景。
方案3:单个字段手动转换(应急用)
如果只是个别字段出问题,也可以在业务代码里手动转换:
$post = Posts::first(['conditions' => ['_id' => $id]]); // 把MongoInt64转成字符串 $post->viewCount = (string) $post->viewCount;
不过这种方法重复代码多,不适合批量处理。
注意事项
- 一定要注意PHP 5.6的整数范围:32位系统下整数最大是2147483647,64位是9223372036854775807,如果MongoDB里的NumberLong超过这个值,转成整数会溢出,所以优先转成字符串更安全。
- Lithium 1.1.1确实不支持新版MongoDB扩展,如果项目长期维护,建议考虑升级Lithium到支持
mongodb扩展的版本,或者逐步迁移到官方的mongodb/mongodbComposer包。
内容的提问来源于stack exchange,提问作者Benjamin Gearig
相关产品推荐
相关产品推荐

