You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 22:09:39