サービス
はじめに
サービスとは?
CodeIgniter 4 の**サービス**は、新しいクラスインスタンスを作成して共有する機能を提供します。これは `Config\Services` クラスとして実装されています。
CodeIgniter 内のすべてのコアクラスは「サービス」として提供されます。これは、ロードするクラス名をハードコーディングする代わりに、呼び出すクラスが非常にシンプルな設定ファイル内で定義されていることを意味します。このファイルは、必要なクラスの新しいインスタンスを作成する一種のファクトリーとして機能します。
なぜサービスを使うのか?
簡単な例で分かりやすく説明します。タイマークラスのインスタンスを取得する必要があるとします。最も簡単な方法は、単にそのクラスの新しいインスタンスを作成することです。
<?php
$timer = new \CodeIgniter\Debug\Timer();
これはうまくいきます。ただし、別のタイマークラスを使用することにした場合を除きます。おそらく、このクラスにはデフォルトのタイマーにはない高度なレポート機能が備わっているでしょう。これを行うには、アプリケーション内でタイマークラスを使用したすべての場所を見つけなければなりません。アプリケーションのパフォーマンスログを常に実行し続けるために、そのままにしておくことがあるため、これは時間と労力がかかり、エラーが発生しやすい方法です。そこでサービスが役立ちます。
インスタンスを自分で作成する代わりに、中央のクラスにクラスのインスタンスを作成させます。このクラスは非常にシンプルに保たれています。サービスとして使用したい各クラスのメソッドが1つだけ含まれています。このメソッドは通常、そのクラスの**共有インスタンス**を返し、依存関係がある場合はそれを渡します。次に、タイマー作成コードを、この新しいクラスを呼び出すコードに置き換えます。
<?php
$timer = \Config\Services::timer();
使用する実装を変更する必要がある場合は、サービス設定ファイルを修正すれば、アプリケーション全体で自動的に変更が適用され、何もする必要がありません。新しい機能を活用するだけで済みます。非常にシンプルでエラーに強いです。
注記
サービスはコントローラー内でのみ作成することをお勧めします。モデルやライブラリなどの他のファイルは、コンストラクターまたはセッターメソッドを介して依存関係を渡す必要があります。
サービスを取得する方法
多くの CodeIgniter クラスはサービスとして提供されているため、次のように取得できます。
<?php
$typography = \Config\Services::typography();
`$typography` はタイポグラフィクラスのインスタンスであり、 `\Config\Services::typography()` を再度呼び出すと、まったく同じインスタンスが取得されます。
サービスは通常、クラスの**共有インスタンス**を返します。次のコードは、最初の呼び出しで `CURLRequest` インスタンスを作成します。2回目の呼び出しは、まったく同じインスタンスを返します。
<?php
$options1 = [
'baseURI' => 'http://example.com/api/v1/',
'timeout' => 3,
];
$client1 = \Config\Services::curlrequest($options1);
$options2 = [
'baseURI' => 'http://another.example.com/api/v2/',
'timeout' => 10,
];
$client2 = \Config\Services::curlrequest($options2);
// $options2 does not work.
// $client2 is the exactly same instance as $client1.
そのため、`$client2` のパラメーター `$options2` は機能しません。単に無視されます。
新しいインスタンスの取得
タイポグラフィクラスの新しいインスタンスを取得する場合は、引数 `$getShared` に `false` を渡す必要があります。
<?php
$typography = \Config\Services::typography(false);
便利な関数
サービスを取得するために、2つの関数が提供されています。これらの関数は常に使用可能です。
service()
1つ目は `service()` で、リクエストされたサービスの新しいインスタンスを返します。必要なパラメータはサービス名だけです。これは、Services ファイル内のメソッド名と同じで、常にクラスの共有インスタンスを返します。そのため、関数を複数回呼び出すと、常に同じインスタンスが返されます。
<?php
$logger = service('logger');
// The code above is the same as the code below.
$logger = \Config\Services::logger();
作成メソッドに追加のパラメーターが必要な場合は、サービス名の後に渡すことができます。
<?php
$renderer = service('renderer', APPPATH . 'views/');
// The code above is the same as the code below.
$renderer = \Config\Services::renderer(APPPATH . 'views/');
single_service()
2つ目の関数 `single_service()` は `service()` と同様に機能しますが、クラスの新しいインスタンスを返します。
<?php
$logger = single_service('logger');
// The code above is the same as the code below.
$logger = \Config\Services::logger(false);
サービスの定義
サービスをうまく機能させるには、各クラスに一定の API、つまりインターフェースがあることに頼ることができなければなりません。CodeIgniter のほぼすべてのクラスは、準拠するインターフェースを提供しています。コアクラスを拡張または置換する場合、インターフェースの要件を満たしていること、およびクラスに互換性があることを確認するだけで済みます。
たとえば、`RouteCollection` クラスは `RouteCollectionInterface` を実装しています。ルートを作成する別の方法を提供する代替を作成する場合は、 `RouteCollectionInterface` を実装する新しいクラスを作成するだけです。
<?php
namespace App\Router;
use CodeIgniter\Router\RouteCollectionInterface;
class MyRouteCollection implements RouteCollectionInterface
{
// Implement required methods here.
}
最後に、`CodeIgniter\Router\RouteCollection` の代わりに `MyRouteCollection` の新しいインスタンスを作成するために、**app/Config/Services.php** に `routes()` メソッドを追加します。
<?php
namespace Config;
use CodeIgniter\Config\BaseService;
class Services extends BaseService
{
// ...
public static function routes()
{
return new \App\Router\MyRouteCollection(static::locator(), config('Modules'));
}
}
パラメーターの許可
インスタンス化中にクラスに設定を渡すオプションが必要になる場合があります。サービスファイルは非常にシンプルなクラスであるため、これを簡単に実現できます。
良い例は `renderer` サービスです。デフォルトでは、このクラスが `APPPATH . 'views/'` でビューを見つけることができるようにします。ただし、必要に応じて開発者がそのパスを変更できるオプションを用意したいと考えています。そのため、クラスはコンストラクターパラメーターとして `$viewPath` を受け入れます。サービスメソッドは次のようになります。
<?php
namespace Config;
use CodeIgniter\Config\BaseService;
class Services extends BaseService
{
// ...
public static function renderer($viewPath = APPPATH . 'views/')
{
return new \CodeIgniter\View\View($viewPath);
}
}
これはコンストラクターメソッドでデフォルトパスを設定しますが、使用するパスを簡単に変更できるようにします。
<?php
$renderer = \Config\Services::renderer('/shared/views/');
サービスディスカバリ
CodeIgniterは、定義された名前空間内に作成されたConfig/Services.phpファイルを自動的に検出できます。これにより、モジュールサービスファイルを簡単に使用できます。カスタムサービスファイルを検出するには、次の要件を満たす必要があります。
名前空間は、app/Config/Autoload.phpで定義する必要があります。
名前空間内では、ファイルはConfig/Services.phpに配置する必要があります。
CodeIgniter\Config\BaseService
を拡張する必要があります。
簡単な例で説明します。
プロジェクトのルートディレクトリに新しいディレクトリBlogを作成したとします。これは、コントローラー、モデルなどを含むブログモジュールを保持し、いくつかのクラスをサービスとして利用できるようにしたいと考えています。最初のステップは、新しいファイル:Blog/Config/Services.phpを作成することです。ファイルのスケルトンは次のようになります。
<?php
namespace Blog\Config;
use CodeIgniter\Config\BaseService;
class Services extends BaseService
{
public static function postManager()
{
// ...
}
}
これで、上記のようにこのファイルを使用できます。任意のコントローラーから投稿サービスを取得する場合、フレームワークのConfig\Services
クラスを使用してサービスを取得するだけです。
<?php
$postManager = \Config\Services::postManager();
注記
複数のサービスファイルに同じメソッド名がある場合、最初に見つかったインスタンスが返されます。