Lumen分页结果追加关联字段时报Creating default object错误如何解决
错误原因
- 核心问题是**
$product对象未提前初始化genres属性**:你尝试直接给$product->genres->$propName赋值时,$product->genres本身是未定义的空值,PHP无法直接对空值挂载子属性,因此抛出Creating default object from empty value错误。 - 附加问题:
where('ggc.EAN', '=', DB::raw("'".$product->EAN."'"))写法多余且有SQL注入风险,不需要用DB::raw包裹参数,直接传值即可。
修正方案
1. 快速修复当前代码
先给每个产品对象初始化genres属性再赋值,示例代码如下:
foreach($products as $product) { // 先初始化genres为stdClass对象 $product->genres = new \stdClass(); $genres = DB::table('sCategoryConnector as ggc') ->join('sCatGenre as gg','gg.ID','=','ggc.ID_sCatGenre') // 简化where写法,避免SQL注入风险 ->where('ggc.EAN', $product->EAN) ->select('gg.tag') ->orderBy('gg.ID', 'asc') ->get(); if ($genres->isNotEmpty()) { foreach($genres as $i => $genre) { $propName = 'genre'.$i; $product->genres->$propName = $genre->tag; } } } return response()->json($products);
如果需要genres是数组格式,初始化和赋值改成如下即可:
// 初始化genres为数组 $product->genres = []; // 赋值时直接push $product->genres[] = $genre->tag;
2. 性能优化建议
当前写法存在N+1查询问题:分页100条的场景下,会额外发起100次分类查询,性能很差。建议先批量查询所有产品的对应分类再匹配赋值,总查询次数可降到3次:
// 第一步:查询分页产品 $products = DB::table('storeItems as i') ->where('i.B2BAvailable', '=', '1') ->select('i.title','i.EAN','i.vendor','i.productType','i.ID as productID','i.releaseDate',DB::raw('(CASE WHEN (i.releaseDate > NOW()) THEN 1 ELSE 0 END) AS announced')) ->orderBy('i.releaseDate', 'desc') ->paginate(100); // 第二步:提取所有产品的EAN,批量查询对应分类 $eanList = $products->pluck('EAN')->toArray(); $allGenres = DB::table('sCategoryConnector as ggc') ->join('sCatGenre as gg','gg.ID','=','ggc.ID_sCatGenre') ->whereIn('ggc.EAN', $eanList) ->select('gg.tag', 'ggc.EAN') ->orderBy('gg.ID', 'asc') ->get() // 按EAN分组,方便后续匹配 ->groupBy('EAN'); // 第三步:遍历产品匹配分类,避免循环查库 foreach($products as $product) { $product->genres = new \stdClass(); if (isset($allGenres[$product->EAN])) { foreach($allGenres[$product->EAN] as $i => $genre) { $propName = 'genre'.$i; $product->genres->$propName = $genre->tag; } } } return response()->json($products);
内容的提问来源于stack exchange,提问作者Bostjan
相关产品推荐
相关产品推荐

