Laravel API: Attempt to assign property 'lastMessage' 报错解决
Laravel 接口响应结构实现报错排查
你触发的ErrorException: Attempt to assign property 'lastMessage' of non-object错误,本质是尝试给非对象类型的变量挂载对象属性,代码里共有4处核心问题:
- 基础查询写法错误:
chat::all()->where('userId', $id)会先查询全表所有数据加载到内存,再在PHP层面做集合过滤,性能极差,正确写法应该是直接在数据库查询阶段加过滤条件chat::where('userId', $id)->get() - 单条/多条结果API混用:给
$chats->chat、lastMessage赋值时你用了get(),该方法返回的是多条记录组成的集合(类似数组结构),但你预期这两个字段都是单个对象,应该用first()取单条结果 - 循环遍历目标错误:内层
foreach ($chats as $m)遍历的是外层循环的单条Chat模型对象本身,而不是你刚赋值的$chats->chat集合,循环内的$m根本不是预期的聊天对象,直接给它赋值属性就会触发非对象报错 - 查询逻辑缺失:查询
lastMessage时没有加会话ID匹配条件,且排序方向写反,用asc会拿到会话最早的一条消息,要拿最新的最后一条消息应该用desc倒序,同时加对应会话的过滤条件,否则所有会话都会拿到同一条全局消息。
修复后参考代码
你原来写了3次完全重复的全表查询,属于冗余逻辑,一次查询结合集合处理即可实现目标结构:
function listChats($id){ $chatsContacts = chat::where('userId', $id) ->get() ->map(function ($contact) { // 取单个关联聊天对象,不要用get()拿集合 $contact->chat = DB::table('chats') ->where('id', $contact->id) ->first(); // 先判断chat对象存在再挂载属性,从根源避免非对象报错 if ($contact->chat) { $contact->chat->lastMessage = DB::table('chats') ->select('message','time','senderId') ->where('chat_id', $contact->chat->id) // 匹配当前会话ID ->orderBy('time', 'desc') // 倒序取最新一条 ->first(); $contact->chat->unseenMsgs = 0; // 补全预期结构里的未读数字段 } return $contact; }); return [ 'chatsContacts' => $chatsContacts ]; }
优化提示:如果后续数据量增长,可以直接在Chat模型里定义
chat、lastMessage的关联关系,用with()预加载替代循环里查SQL的写法,彻底解决N+1查询问题,接口性能会提升明显。
内容的提问来源于stack exchange,提问作者stack user
相关产品推荐
相关产品推荐

