
当 Laravel 通知类实现 ShouldQueue 并使用 Queueable trait 时,若未显式声明可序列化属性,队列反序列化后会丢失构造函数中赋值的成员变量,导致“Undefined property”错误。
当 laravel 通知类实现 `shouldqueue` 并使用 `queueable` trait 时,若未显式声明可序列化属性,队列反序列化后会丢失构造函数中赋值的成员变量,导致“undefined property”错误。
在 Laravel 中,通知(Notification)类若需通过队列异步发送,需同时满足两个条件:
- 使用 Illuminate\Bus\Queueable trait;
- 实现 Illuminate\Contracts\Queue\ShouldQueue 接口。
但关键在于:Queueable trait 依赖 PHP 的序列化机制传递通知实例到队列 worker。而 PHP 序列化仅会保存 已声明的公共(public)或受保护(protected)属性 —— 若属性未提前声明,即使在 __construct() 中动态赋值(如 $this->transaction_detail = $transaction_detail;),该属性在反序列化后将不存在,从而触发 Undefined property 错误。
✅ 正确做法是:在类中显式声明该属性,并在构造函数中初始化:
<?php namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class NewTransaction extends Notification implements ShouldQueue
{
use Queueable;
// ✅ 显式声明属性(public 或 protected 均可,推荐 protected)
protected $transaction_detail;
/**
* Create a new notification instance.
*/
public function __construct($transaction_detail)
{
// ⚠️ 注意:调用 parent::__construct() 是可选的(Notification 基类构造函数为空),
// 但显式调用更规范,尤其在后续升级或扩展基类逻辑时
parent::__construct();
$this->transaction_detail = $transaction_detail;
}
public function via($notifiable): array
{
return ['mail'];
}
public function toMail($notifiable): MailMessage
{
return (new MailMessage)
->subject('New Transaction Received')
->greeting('Hello ')
->line('Transaction ' . $this->transaction_detail->reference . ' has arrived.');
}
}
? 补充说明与注意事项:
- 不要使用 public $transaction_detail;(除非明确需要外部访问),推荐 protected 以保持封装性;
- Queueable trait 本身不自动处理属性声明,它仅提供队列相关的 dispatch()、onQueue() 等方法,并依赖标准序列化行为;
- 清除缓存(如 config:cache)或重启队列进程(queue:restart)无法解决此问题,因为根本原因是类结构定义缺失,而非缓存或进程状态;
- 若通知携带模型实例(如 Transaction),建议传递模型 ID 而非整个对象(避免序列化复杂关系),并在 toMail() 中按需查询:
protected $transaction_id;
public function __construct($transaction_id)
{
$this->transaction_id = $transaction_id;
}
public function toMail($notifiable): MailMessage
{
$transaction = Transaction::findOrFail($this->transaction_id);
return (new MailMessage)
->line('Transaction ' . $transaction->reference . ' has arrived.');
}
这是更健壮、内存友好且符合 Laravel 最佳实践的方式。
总结:队列化通知 ≠ 仅加 implements ShouldQueue 和 use Queueable;必须确保所有需跨进程传递的数据都作为显式声明的属性存在,才能被正确序列化与反序列化。











