laravel 队列任务中定义 `failed()` 方法时,若声明类型为 `exception $e` 但未加全局命名空间前缀 `\`,php 会尝试在当前命名空间 `app\jobs` 下查找 `exception` 类,导致类型约束失败;正确做法是使用 `\exception $e = null` 显式引用 php 内置异常类。
在 Laravel 中,当队列任务执行失败(如抛出异常、超时或手动调用 fail())时,框架会自动调用任务类的 failed() 方法,并传入一个 Exception 实例。然而,该异常参数可能为 null —— 例如任务被手动标记为失败($this->fail())、超时终止、或底层队列驱动无法提供具体异常信息时,Laravel 会传入 null 而非 Exception 对象。
此时,若你将 failed() 方法签名写为:
public function failed(Exception $e) // ❌ 错误:类型提示强制要求 Exception 实例
{
// ...
}PHP 将严格校验参数类型,而 null 不满足 \Exception 类型约束,从而触发致命错误:
Argument 1 passed to App\Jobs\SomeJob::failed() must be an instance of Exception, null given
根本原因在于:Exception 是 PHP 的内置类,位于全局命名空间,而你在 App\Jobs 命名空间下直接写 Exception,PHP 会解析为 App\Jobs\Exception(不存在),且即使存在同名类,类型提示也无法匹配 \Exception。
✅ 正确写法必须同时满足两点:
someVar = $someVar;
}
public function handle()
{
// 模拟可能失败的操作
throw new \RuntimeException('Something went wrong');
}
// ✅ 推荐:显式全局命名空间 + 可空参数
public function failed(\Exception $e = null)
{
if ($e) {
\Log:
:error('Job failed with exception: ' . $e->getMessage(), [
'exception' => $e,
'job_data' => $this->someVar,
]);
} else {
\Log::warning('Job failed without exception (e.g., timeout or manual fail())', [
'job_data' => $this->someVar,
]);
}
}
}⚠️ 注意事项:
总结:Laravel 队列 failed() 方法的参数签名必须为 \Exception $e = null,这是框架契约的一部分。坚持这一规范,既能避免类型错误,又能稳健处理所有失败场景。