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

Laravel 8队列处理通知时NumberFormatter不允许序列化错误如何解决?

问题根因分析

你遇到的报错核心是序列化时机和序列化对象的差异,和toArray()方法本身无关:

  • 你PaymentLog模型的total_amount_formatted访问器大概率返回的不是纯字符串,而是一个内置了NumberFormatter实例的货币格式化对象(比如常用的Money包返回的格式化对象、或者自定义的实现了__toString()的货币类),该对象只会在直接输出时自动转字符串,序列化时会保留内部所有属性,包括不可序列化的NumberFormatter实例。
  • 部分任务成功是因为对应订单没有关联paymentLog,optional()返回null,没有触发序列化问题。

为什么database通道正常、broadcast通道报错

两个通道的队列执行逻辑完全不同:

database通道执行流程

  1. 通知推队列时,仅序列化NewOrderNotification自身的两个属性:$orders(Laravel序列化模型时仅会保存主键,不会序列化模型属性)、$sendingToTeamMembers(布尔值),两个属性都不涉及NumberFormatter,所以推队列成功。
  2. 队列执行时反序列化通知,调用toArray()得到结果后直接写入数据库,写入时会自动把返回的货币对象转成字符串,全程不需要序列化toArray()的返回结果,所以不会触发报错。

broadcast通道执行流程

  1. 通知推队列时序列化逻辑和database通道一致,所以不会报错。
  2. 队列执行到broadcast通道时,会生成BroadcastNotification广播事件,这个事件本身默认会被推到广播队列二次序列化,此时toArray()的返回结果会作为事件payload的一部分被序列化,里面的货币对象携带的NumberFormatter实例就会触发序列化失败的报错。

修复方案

最简单的修复方式是强制把格式化结果转成纯字符串,避免任何对象被序列化:
修改getPaymentAmountSafely方法:

protected function getPaymentAmountSafely(Order $order)
{
    return (string) optional($order->paymentLog)->total_amount_formatted;
}

也可以直接修改PaymentLog的getTotalAmountFormattedAttribute访问器,直接返回字符串,避免后续其他地方再出现同类问题。


内容的提问来源于stack exchange,提问作者Louis L

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 07:06:02