Eloquent与DB Facade中toArray()方法行为差异原因及解决办法
差异原因
核心是两种查询返回的集合元素类型不同:
- 第一段是Eloquent模型查询:
User::select()返回的Eloquent\Collection中,每个元素是User模型实例。模型类自带toArray()方法,调用集合的toArray()时,会自动把每个模型实例转换成关联数组,最终得到嵌套数组结构。 - 第二段是查询构建器查询:
DB::table()返回的Support\Collection中,每个元素是原生PHP的stdClass对象。stdClass没有toArray()方法,集合的toArray()仅会把外层集合转为数组,内部的对象会保留原样,所以结果是数组包裹对象。
解决方法
以下三种方法都能让第二段查询返回嵌套数组:
1. 用map()遍历转换每个对象为数组
在集合转数组前,先把每个stdClass对象强制转为数组:
$res2 = DB::connection($destinationDb.'__read') ->table("$destinationTable as d") ->leftJoin("$soruceDb.$soruceTable as s", "d.".strtolower($configRule['rule']['destination_lookup_key']), '=', "s.".strtolower($configRule['rule']['source_lookup_key'])) ->select(Db::raw(implode(',',$prefixedSourColumns))) ->limit(2) ->get() ->map(fn($item) => (array)$item) // 转换单个对象为数组 ->toArray();
2. 直接使用原生查询DB::select()
跳过查询构建器的集合包装,直接返回数组结构:
// 拼接SQL语句 $sql = sprintf( "SELECT %s FROM `%s` as d LEFT JOIN `%s`.`%s` as s ON d.%s = s.%s LIMIT 2", implode(',',$prefixedSourColumns), $destinationTable, $soruceDb, $soruceTable, strtolower($configRule['rule']['destination_lookup_key']), strtolower($configRule['rule']['source_lookup_key']) ); // 执行原生查询,直接得到嵌套数组 $res2 = DB::connection($destinationDb.'__read')->select($sql);
3. 用json_encode()+json_decode()强制转换
利用JSON序列化的特性,把对象集合强制转为数组:
$res2 = DB::connection($destinationDb.'__read') ->table("$destinationTable as d") ->leftJoin("$soruceDb.$soruceTable as s", "d.".strtolower($configRule['rule']['destination_lookup_key']), '=', "s.".strtolower($configRule['rule']['source_lookup_key'])) ->select(Db::raw(implode(',',$prefixedSourColumns))) ->limit(2) ->get() ->toArray(); // 强制转换为嵌套数组 $res2 = json_decode(json_encode($res2), true);
内容的提问来源于stack exchange,提问作者Archit Gupta
相关产品推荐
相关产品推荐

