Laravel Jobのコンストラクタ引数にクロージャを渡す方法
LaravelのJobを利用する際に、コンストラクタの引数としてクロージャを渡したいと思ったことはありませんか?通常の方法ではクロージャはシリアライズできないためエラーになりますが、シリアライズ可能なクロージャを使えば、この問題を解決できます。
本記事では、Job実行中にクロージャを活用する方法を解説します。
問題: クロージャをそのまま渡せない
LaravelのJobクラスでは、コンストラクタに渡されたデータはシリアライズされ、Queueに保存されます。しかし、PHPの標準クロージャはシリアライズできないため、エラーが発生します。
エラー例
class MyJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $closure;
public function __construct(\Closure $closure)
{
$this->closure = $closure;
}
public function handle(): void
{
($this->closure)();
}
}
// Dispatchする
MyJob::dispatch(function () {
echo 'This is a test.';
});
このコードを実行すると、次のようなエラーが発生します。
Serialization of 'Closure' is not allowed
解決策: クロージャのシリアライズ対応
opis/closure
パッケージを利用すると、シリアライズ可能なクロージャを作成できます。
必要なパッケージのインストール
まず、opis/closure
パッケージをインストールします。
composer require opis/closure
Jobクラスの修正
SerializesModels
トレイトとSerializableClosure
を活用して、Jobクラスを修正します。
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Opis\Closure\SerializableClosure;
class MyJob implements ShouldQueue
{
use Dispatchable, Queueable
public $closure;
public function __construct(\Closure $closure)
{
$this->closure = new SerializableClosure($closure);
}
public function handle(): void
{
// クロージャを実行
($this->closure)();
}
}
実行例
上記の修正後、次のようにクロージャを渡してJobをDispatchできます。
use App\Jobs\MyJob;
MyJob::dispatch(function () {
echo 'Job実行中にこのクロージャが実行されます!';
});
Queueが処理されると、以下の出力が得られます。
Job実行中にこのクロージャが実行されます!
注意点
- セキュリティ: クロージャをシリアライズしてQueueに保存するため、信頼できるコードのみを扱うようにしてください
- 依存関係: クロージャ内で外部変数やサービスコンテナへの依存がある場合などはどうなんでしょうね
まとめ
LaravelのJobでクロージャを扱うには、opis/closure
を利用してシリアライズ可能なクロージャを作成できます。皆様のエレガントな抽象化を祈念いたします。