Laravel模型访问器调用关联对象属性报错问题咨询
哈哈,这个问题我之前也碰到过,本质是Laravel关联对象的加载逻辑和两种属性访问方式的差异在搞鬼,我给你拆解清楚:
为什么$this->supplier->name会报错?
你以为$this->supplier直接返回的是Supplier模型,但实际上有两种场景会导致报错:
- 关联未被加载时:如果你的Part查询没有用
with('supplier')预加载关联,且之前没触发过关联加载,$this->supplier返回的是Laravel的BelongsTo关联查询构建器对象——就是那个帮你准备SQL查询的工具类,它本身并没有name属性,直接访问->name自然会抛出“Trying to get property 'name' of non-object”的错误。 - 关联不存在时:如果这个Part对应的Supplier记录不存在(比如
supplier_id是无效值、null,或者Supplier记录被删除),$this->supplier会返回null,你去访问null的name属性也会触发同样的错误。
为什么$this->supplier['name']能正常运行?
这是因为Laravel给关联查询构建器和模型类都实现了ArrayAccess接口——简单说就是让这些对象可以像数组一样用下标访问。当你用['name']的方式时:
- 如果当前是关联查询构建器,它会自动触发关联查询,拿到Supplier模型实例后再返回
name属性; - 如果已经是Supplier模型实例,数组下标访问就等价于直接访问模型属性,和
->name效果一致。
相当于数组方式帮你做了一层“自动加载关联+取值”的封装,而直接用->name就没有这个额外处理。
怎么让$this->supplier->name正常工作?
给你几个实用的解决方案:
- 预加载关联:查询Part的时候加上
with('supplier'),这样$this->supplier始终会返回Supplier模型实例或null,不会再返回查询构建器。 - 使用可选链/辅助函数:PHP 7.4+可以用
$this->supplier?->name,如果supplier是null或未加载,会直接返回null而不报错;低版本PHP可以用Laravel的optional($this->supplier)->name,效果完全一致。 - 手动触发加载(不推荐):在访问器里先写
$this->load('supplier')再访问->name,但这种方式会额外执行SQL查询,性能不如预加载,尽量少用。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

