こんにちは、ありちゃんです。

- Laravelのサービスコンテナって何?
- サービスコンテナについて調べたけどいまいち便利さがわからない
- 現場でどうサービスコンテナが使われるのか
このようなお悩みを解決するために、Laravelのサービスコンテナについてリフレクションやその必要性も含めて簡単に解説していきます。
この記事を書いた人

- もうすぐエンジニア3年目
- 主にLaravel, Vue.jsを使用
まずはこの一冊!一番わかりやすいLaravelの書籍

Laravelのサービスコンテナとは

Laravelのサービスコンテナは、依存関係を管理する仕組みです。
たとえば、あるクラスが別のクラスを使う場合、普通は「new クラス名()」でインスタンスを作成しますが、これだと管理が大変になります。
サービスコンテナを使えば、必要なクラスを自動で用意してくれるので、コードがスッキリし、テストもしやすくなります。
言葉だけの説明だとイマイチ想像できないと思うので、早速具体的な例を元に見ていきましょう。
サービスコンテナが必要な理由、サービスコンテナを使用するとどうなるのか

先ほどお話しした通り、クラスを使うときは new クラス名()
でインスタンスを作成しますが、この方法では依存関係が増えるほど管理が複雑になります。
例えば、以下のようなコードがあったとします。
class UserRepository {
public function getUser() {
return "User Data";
}
}
class UserService {
protected $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function getUserData() {
return $this->userRepository->getUser();
}
}
UserServiceクラスを利用するには、UserServiceクラスのインスタンスをnew クラス名で作成する前に、依存しているUserRepositoryクラスを作成する必要があるので以下のように書きます。
$userRepository = new UserRepository();
$userService = new UserService($userRepository);
echo $userService->getUserData();
ただ、サービスコンテナを利用すると以下のようにUserRepositoryのクラスを手動で作成することなくコードの記述量を減らして書くことができます。
$userService = app(UserService::class);
echo $userService->getUserData();

サービスコンテナを使ってもあまり違いがないんじゃない?
いまいち便利さがわからないなあ
サービスコンテナの便利さがいまいちわからない方は以下の状況を一緒に確認していきましょう。
UserServiceが依存しているクラスがUserRepositoryだけなら問題なさそうですが、UserServiceクラス内の処理でCommentRepositoryやArticleRepository、その他いくつかのクラスを利用する必要がある場合は下記のようにUserServiceのインスタンスを作成する前にいくつものクラスのインスタンスを書かなければいけません。
$userRepository = new UserRepository();
$commentRepository = new CommentRepository();
$articleRepository = new ArticleRepository();
$〇〇Repository = new 〇〇Repository();
$■■Repository = new ■■Repository();
$▶︎▶︎Repository = new ▶︎▶︎Repository();
$userService = new UserService($userRepository, $commentRepository, $articleRepository, $〇〇Repository, $■■Repository, $▶︎▶︎Repository);
echo $userService->getUserData();
このように依存しているクラスのインスタンスをいちいち作成するのは大変だし、ミスも生まれやすいと思いませんか?
サービスコンテナを利用すると上記のコードもコンパクトに実行することができます。
$userService = app(UserService::class);
echo $userService->getUserData();
実際はapp()をあまり使用しない?!

Laravelについて勉強してきた方はある疑問を持ったかもしれません。

あれ?Laravelで開発してるけどapp()もbind()も全然使ってない…
実はLaravelで主に使われる必要なクラスを用意する方法は他にもあります。
そして現場では、ほとんどの場合他の方法で必要なクラスを用意します。
現場で必ず使われる!コンストラクタインジェクションについて

先ほどお話しした現場で使われる必要なクラスの用意方法はコンストラクタインジェクションです。
Laravelのサービスコンテナは、基本的にクラスの型宣言(type-hint)に基づいて自動でインスタンスを解決してくれます。そのため、クラスそのものを使う場合は、明示的に app()->bind で登録しなくても下記のようにconstructに必要なクラスを記載するだけで使用できるようになります。
先ほどサービスコンテナの必要性について説明した例を見てみると以下のように書くだけでOKです。
class UserService {
public function __construct
(
protected UserRepository $userRepository,
protected CommentRepository $commentRepository,
protected ArticleRepository $articleRepository,
protected 〇〇Repository $〇〇Repository,
protected ■■Repository $■■Repository,
protected▶︎▶︎Repository $▶︎▶︎Repository
)
{
//下記のコードは記載しなくても$this->userRepository->メソッド名で利用できます。
$this->userRepository = $userRepository;
$this->commentRepository = $commentRepository;
$this->articleRepository = $articleRepository;
$this->〇〇Repository = $〇〇Repository;
$this->■■Repository = $■■Repository;
$this->▶︎▶︎Repository = $▶︎▶︎Repository;
}
public function getUserData() {
return $this->userRepository->getUser();
}
}
ただし、インターフェースとその実装クラスの関係のように、どの実装を使うか明示的に指定する必要がある場合は、app()->bind を使って登録する必要がありますが、単に具体的なクラスを使用する場合は自動解決が働くため、毎回バインディングを明示する必要はありません。
なので、app()とbind()を利用せずとも必要なクラスを用意することができるためapp(), bind()をあまり利用していないかたが多いのだと思います。
サービスコンテナが型ヒント(タイプヒント)をもとに依存関係を解決 しています。
つまり、「型ヒントを見て、どのクラスのインスタンスを注入すればいいかをサービスコンテナが判断する

でもどうしてbindで登録してないインスタンスを型ヒントだけで必要なものだけ用意できているの?
次の項目ではこのような疑問を解決するのに必要な知識であるリフレクションについて簡単にまとめていきます。
リフレクションとは?

リフレクション(Reflection)は、クラスやメソッドの情報を実行時に取得・操作できるPHPの機能です
Laravelのサービスコンテナは、リフレクションを使ってクラスの依存関係を解析し、必要なインスタンスを自動で作成します。
先ほどの例を使って具体的な流れを見ていきましょう。
class UserService {
public function __construct
(
protected UserRepository $userRepository,
protected CommentRepository $commentRepository,
protected ArticleRepository $articleRepository,
protected 〇〇Repository $〇〇Repository,
protected ■■Repository $■■Repository,
protected ▶︎▶︎Repository $▶︎▶︎Repository,
)
{
}
}
① リフレクションで UserService
の情報を取得
② コンストラクタの引数(UserRepository
, CommentRepositoryなど引数にあるクラス)を調べる
③ 依存クラス(コンストラクタの引数にあるクラス)のインスタンスを取得
④ リフレクションで UserService
のインスタンスを作成
⑤サービスコンテナはリフレクションが作成したクラスを受け取る
というような流れになります。
つまり、あくまでもサービスコンテナが依存クラスのインスタンスを作成するのではなく、必要なクラスを作成はリフレクションが行い、サービスコンテナは結果を受け取るだけということになります。
【Laravelを最短でマスター!】初中級者が確実に成長するおすすめ書籍3選

これを読めばLaravelで開発ができる!わかりやすく、実践的な学習書を厳選して紹介します!
Laravelの教科書 バージョン10対応
初めてLaravelに触れる、フレームワークに触れるという方は絶対にこの一冊!と言っても過言ではないほど初学者に寄り添った書籍になります。
MVCモデル?フレームワーク?という状態だった筆者がこれらの基本知識を理解し、アプリ開発できたのもこの書籍のおかげです。
難しいこと言葉には必ずわかりやすい説明がついていてこの書籍で学べば必ずLaravelの使い方を理解して何か開発することができるはず!
技術書って難しいしなあ、Laravelってどう使うんだろうという悩みや疑問を持っている方必読の一冊です。

Laravelリファレンス Web職人好みの新世代PHPフレームワーク
Laravelの深い理解を目指す開発者にとって必読の一冊です。
シンプルなコード例から実践的なテクニックまで幅広くカバーしているので、初心者はもちろん、中級者の方にも新たな発見がある内容になっています。
実務でLaravelを使いこなすためのベストプラクティスや、最新のフレームワーク動向を網羅しているため、初心者、中級者からさらにステップアップしたい方おすすめの一冊です。

PHPフレームワークLaravel Webアプリケーション開発 バージョン8.x対応
Laravelの基礎から実践的な開発手法までをわかりやすく解説した一冊です。
サンプルコードが豊富で、初心者の方でもスムーズに学習できるのが魅力だと思います。
実務で使える知識も多く、Laravelをしっかり習得したい方におすすめです。
今回のライフサイクルについても図解つきで説明してくれています。

Laravel サービスコンテナ・リフレクション まとめ

この記事ではLaravelのサービスコンテナについて、どうして必要なのか、何が便利なのか、実際の現場ではどのように利用されているのかについてお話ししました。
この記事が皆さんの役に少しでも立てたら嬉しいです。
最後まで読んでくださって本当にありがとうございました!
今後ともよろしくお願いします。
おすすめのLaravel記事
おすすめの技術系に関する記事
AWS SAA
ChatGPTを使いこなしたい方必見!
SNSはこちらから
twitter https://moile.twitter.com/QTzmttr1FeEYck
主に勉強記録を更新しています。
note https://note.com/arichan0/
参考記事・書籍
Laravelリファレンス Web職人好みの新世代PHPフレームワーク
Laravelリファレンス Web職人好みの新世代PHPフレームワーク

コメント