A closure has no serialisable representation in PHP, so any object holding one — a validator with a custom rule, a collection with a lazy callback — cannot be queued or cached.
$job = new ProcessOrder($order);
$job->onSuccess = function () { /* ... */ };
dispatch($job);
// Exception: Serialization of 'Closure' is not allowed
// the fixes, in order of preference:
// an invokable class instead of a closure
// a string key into a registry
// __sleep()/__serialize() that drops it, and a rebuild on wake
An invokable class is the right answer nearly every time and it is also more testable, because a closure buried in a constructor cannot be asserted on. The __sleep route is what to reach for when the closure belongs to a dependency you do not own. The failure surfaces at dispatch rather than at construction, which is late enough that a rarely used code path can ship broken — a test that queues the job is the cheapest way to catch it.