Laravel 12 に新しく Bind Attribute が入りました。
これ、実際に触ってみると「なんで今までなかったの?」ってレベルで便利です。
Laravel v12.22.0(2025年7月9日リリース)で導入された機能であり、これ未満の場合はlaravelのバージョンを上げる必要があります。
今までのbindの書き方
今までだと、Interface と具象クラスのバインドをするために AppServiceProvider とか自作の ServiceProvider にこんな感じで書いてました
public function register(): void
{
    $this->app->bind(
        EventPusher::class,
        RedisEventPusher::class
    );
}
コンフリクトするしで、地味にめんどくさい。
特に Repository パターンっぽい設計をしていて、Interface が増えると ServiceProvider が膨らんでいきます。
Bind Attribute の登場
Laravel 12 からは、Interface 側に #[Bind] を書いておくだけで、自動的に依存解決が効くようになりました。
namespace App\Contracts;
use App\Services\FakeEventPusher;
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;
#[Bind(RedisEventPusher::class)]
#[Bind(FakeEventPusher::class, environments: ['local', 'testing'])]
interface EventPusher
{
    // ...
}
ポイントはこれ:
- どの実装をバインドするかを Attribute で宣言できる
- 環境ごとに切り替えも可能(local/test なら Fake、prod は Redis、みたいに)
もう ServiceProvider にいちいち書かなくていいんです。
しかも Interface 側に「デフォルト実装」が一目でわかる のがめちゃくちゃ良い。
Singleton / Scoped も Attribute で指定できる
さらに #[Singleton] や #[Scoped] も追加できるので、ライフサイクルの制御も Attribute で完結します。
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;
use Illuminate\Container\Attributes\Singleton;
#[Bind(RedisEventPusher::class)]
#[Singleton]
interface EventPusher
{
    // ...
}
これで「どの実装を使うか」「スコープはどうするか」まで Interface 側に完結。
ServiceProvider はよほど特殊なケースでしか出番がなくなりそうです。
結論:よほどのことがない限り ServiceProvider いらない
もちろん、少し複雑なケース(クロージャでコンテナに登録するとか)ではまだ ServiceProvider が必要になります。
でも大多数のケースでは、Interface に Attribute をつけるだけで十分です。
- コードの見通しが良くなる
- Provider に余計な記述が減る
- 実装の切り替えも Attribute で直感的に書ける
「ちょっとしたことでも ServiceProvider に書く」時代は終わりましたね。
まとめ
- 
#[Bind]で Interface に実装を紐付けられる
- 環境ごとの実装切り替えも Attribute で完結
- これからは ServiceProvider は特殊用途でしか使わなくてよい
Attribute導入された時は、あまり重要性を理解できてなかったですが、めちゃくちゃ便利ですね。
