CodeIgniter 4でコントローラにサービスを注入する方法!初心者でも依存関係管理がわかる
生徒
「CodeIgniterで、便利な道具(サービス)をコントローラで使うにはどうすればいいですか?」
先生
「CodeIgniter 4では『サービス(Services)』という仕組みがあって、それをコントローラに『注入』することで、いつでもどこでも同じ道具が使えるようになるんですよ。」
生徒
「注入……なんだか難しそうですね。具体的にどうやって書くんですか?」
先生
「実はとっても簡単です。コンストラクタという場所を使う方法が一般的ですね。詳しく解説していきましょう!」
1. サービスと依存関係管理(DI)とは?
プログラミングの世界には、「サービス(Services)」や「依存関係管理(Dependency Injection)」という言葉があります。初めて聞く人には呪文のように聞こえるかもしれませんが、実は身近な例えで考えると非常にシンプルです。
例えば、あなたが「料理(コントローラ)」を作るとしましょう。料理を作るには「包丁(サービス)」が必要です。このとき、料理を作るたびに自分で包丁を一から鉄を叩いて作る人はいないですよね。どこかにある道具箱(サービス・ロケータ)から、すでに使える状態の包丁を借りてくるはずです。
サービスとは、Webサイト制作でよく使う「データベースの操作」「メール送信」「検証(バリデーション)」などの便利な機能をまとめた道具のことです。そして、その道具を「外から渡してあげること」を依存関係の注入(DI)と呼びます。これによって、プログラムがスッキリと整理され、後で道具を交換したり修理したりするのがとても楽になります。
2. CodeIgniterのサービスロケータを使ってみよう
CodeIgniter 4には「Services」というクラスが用意されており、これが巨大な道具箱の役割を果たします。まずは一番簡単な、コントローラの中で直接サービスを呼び出す方法を見てみましょう。ここでは「タイマー」というサービスを使ってみます。
namespace App\Controllers;
use CodeIgniter\Config\Services;
class Home extends BaseController
{
public function index()
{
// 道具箱(Services)から「タイマー」という道具を取り出す
$timer = Services::timer();
$timer->start('test');
// 何かの処理
$timer->stop('test');
echo "処理にかかった時間: " . $timer->getElapsedTime('test');
}
}
このコードでは、Services::timer()と書くことで、CodeIgniterが裏側でタイマーの準備をしてくれます。自分で new Timer() と書かなくていいのがポイントです。このように、必要な時にだけ道具を呼び出す仕組みを理解することが、フレームワークを使いこなす第一歩です。
3. コンストラクタを使った「注入」の基本
先ほどの例では、メソッドの中で毎回 Services::... と書いていました。しかし、一つのコントローラで何度も同じ道具を使う場合、毎回書くのは面倒ですよね。そこで登場するのがコンストラクタ(Constructor)です。
コンストラクタとは、そのクラス(今回はコントローラ)が新しく作られた瞬間に、一番最初に自動で実行される魔法のメソッドのことです。ここで道具を受け取っておけば、他のどの場所でもその道具を使い回すことができます。
専門用語でこれをコンストラクタ・インジェクションと呼びます。難しく聞こえますが、「お店(コントローラ)を開店する前に、必要な備品(サービス)を棚に並べておく」というイメージでOKです。
4. バリデーションサービスを注入する実践コード
では、実際によく使う「バリデーション(入力チェック)」のサービスを、コンストラクタを使って注入してみましょう。バリデーションとは、ユーザーが入力したメールアドレスが正しい形式か、パスワードが短すぎないかなどを確認する機能です。
namespace App\Controllers;
use CodeIgniter\Validation\Validation;
use CodeIgniter\Config\Services;
class UserController extends BaseController
{
// 道具をしまっておくための「棚」を作る
protected $validation;
public function __construct()
{
// コントローラが動き出す時に、バリデーションツールを棚に入れる
$this->validation = Services::validation();
}
public function create()
{
// すでに棚にあるので、いつでも使える!
$data = ['username' => ''];
if (!$this->validation->run($data, 'signup')) {
echo "エラーが発生しました";
}
}
}
このように、$this->validation という変数(プロパティ)にサービスを代入しておくことで、コントローラ内のどのメソッドからでも $this->... という形で呼び出せるようになります。これが最も一般的で綺麗な書き方です。
5. BaseControllerを活用した共通サービスの管理
CodeIgniterには、すべてのコントローラの親玉である BaseController というファイルが存在します。もし、すべてのページで共通して使いたいサービス(例えばセッション管理やログインチェックなど)がある場合は、この BaseController で準備しておくと便利です。
子どものコントローラたちは、親が用意した道具をそのまま受け継ぐことができます。これにより、同じコードを何度も書く必要がなくなり、ミスが減ります。プログラミング未経験の方にとっては、親からお下がりの道具セットをもらうようなものだと考えると分かりやすいでしょう。
// BaseController.php の中でのイメージ
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
// 親クラスの初期化を忘れずに呼ぶ
parent::initController($request, $response, $logger);
// すべてのコントローラで「セッション」を使えるようにする
$this->session = \Config\Services::session();
}
これを設定しておけば、他のコントローラでわざわざ Services::session() と書かなくても、いきなり $this->session が使えるようになります。非常に効率的ですね。
6. 独自の自作サービスを注入する方法
CodeIgniterが用意してくれた道具だけでなく、自分で作ったオリジナルの道具をサービスとして登録することも可能です。例えば、「複雑な計算をするツール」や「外部のAPIと通信するツール」を自作した場合です。
自作したクラスを app/Config/Services.php という設定ファイルに登録することで、システム全体のどこからでも Services::myTool() のように呼び出せるようになります。これができるようになると、あなたはもう初心者を卒業して、立派なエンジニアの仲間入りです。
// app/Config/Services.php への追記例
public static function myCalculator($getShared = true)
{
if ($getShared) {
return static::getSharedInstance('myCalculator');
}
return new \App\Libraries\MyCalculator();
}
このように登録しておけば、コントローラ側で $this->calc = Services::myCalculator(); と書くだけで、自作の便利な計算機を呼び出すことができます。依存関係を管理することで、コードの見た目が美しくなり、中身が整理整頓されるのです。
7. サービスを使うメリットと注意点
なぜ直接 new してクラスを作らずに、サービスという仕組みを使うのでしょうか? その最大の理由は「テストのしやすさ」と「部品の交換」にあります。
例えば、本物のメールを送る機能の代わりに、テスト中だけは「メールを送ったふりをする機能」に差し替えたいことがあります。サービスとして注入していれば、設定一つで中身を入れ替えることができます。もしコードのあちこちに直接書き込んでいたら、全部書き直さなければなりません。
ただし、注意点もあります。何でもかんでもサービスにしすぎると、逆にどこで何が起きているか分かりにくくなることがあります。まずは「よく使う便利な道具」からサービス化していくのがおすすめです。パソコンを触ったことがない方でも、まずは「便利な引き出しから道具を取り出す」という感覚さえ掴めれば、モダンなPHP開発は怖くありません。