Laravel循环内查询报错:尝试访问非对象属性
解决foreach循环中调用null对象属性的错误
嘿,我一眼就看出问题所在了——你这段代码里的$producto有时候会是null,这时候你直接去访问它的existencias属性当然会触发“非对象无法获取数据”的错误!
问题根源
当你执行$empresa->productos()->where('producto_nombre_id', 1)->first()时,如果当前企业没有匹配producto_nombre_id=1的产品,first()方法会返回null,而不是一个Producto对象。这时候你去调用$producto->existencias,就相当于在给null对象发消息,自然会报错。
几种解决方案
1. 先判断对象是否存在再操作(最直观的写法)
在累加之前先检查$producto是否有效,避免对null进行属性访问:
public function actualizar_costo_promedio() { $empresas = Empresa::all(); $anteriores_exist = 0; foreach ($empresas as $empresa) { $producto = $empresa->productos()->where('producto_nombre_id', 1)->first(); // 只有当产品存在时,才累加库存 if ($producto) { $anteriores_exist += $producto->existencias; } } }
2. 使用Laravel的optional辅助函数(简洁写法)
Laravel提供了optional函数来处理可能为null的对象,它会在对象为null时返回null,再配合??运算符设置默认值,一行代码就能解决问题:
public function actualizar_costo_promedio() { $empresas = Empresa::all(); $anteriores_exist = 0; foreach ($empresas as $empresa) { $producto = $empresa->productos()->where('producto_nombre_id', 1)->first(); // 产品不存在时自动取0,避免报错 $anteriores_exist += optional($producto)->existencias ?? 0; } }
3. 优化查询逻辑,提前过滤无效数据(性能更优)
上面两种写法都会触发N+1查询(每个企业都单独查一次产品),而且还要处理null的情况。你可以提前筛选出拥有指定产品的企业,同时预加载关联数据,既避免null问题,又提升性能:
public function actualizar_costo_promedio() { // 先筛选出拥有producto_nombre_id=1的企业,同时预加载对应产品 $empresas = Empresa::whereHas('productos', function ($query) { $query->where('producto_nombre_id', 1); })->with(['productos' => function ($query) { $query->where('producto_nombre_id', 1)->take(1); }])->get(); $anteriores_exist = 0; foreach ($empresas as $empresa) { // 这里的productos集合必然有数据,直接取第一个即可 $producto = $empresa->productos->first(); $anteriores_exist += $producto->existencias; } }
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

