PHPの依存性注入とは何ですか、そしてそれをどのように使用するか

ソフトウェア開発の一般的でよく知られている方法論の1つは、依存性注入と呼ばれます。これは、フローを容易にし、ソフトウェアが必要なツールに常にアクセスできるようにするのに役立ちます。多くの人がこの方法論を非常に複雑に聞こえるようにしようとしますが、実際にはそうではありません。

依存性注入とは何か、それがどのように機能するか、そしてそれがソフトウェアにどのように役立つかを詳しく見ていきましょう。

依存性注入とは何ですか?

依存性注入の優れた例えは、ソフトウェアが処理されているときにソフトウェアと一緒に移動し、すべてがスムーズに流れるようにするツールキットを持った作業者です。ツールキットには、変数、配列、オブジェクト、クロージャなど、手元のタスクを完了するために必要なあらゆるものを含めることができます。

ワーカーが新しいタスク(つまり、クラスまたはメソッド)を開始すると、必要な要件を確認し、考えずに、ジョブを完了するために必要なさまざまなツールを引き出します。これは一言で言えば依存性注入です。

ツールキットに必要なものを何でも入力できます。ソフトウェアのクラスとメソッド内で必要なツールを指定すると、それらが自動的に提供されます。

Apexコンテナをインストールする

さまざまな実装がありますが、すべて基本的に同じように機能します。シンプルでわかりやすいApexコンテナを使用します。すでにPHPがインストールされていることを前提としており、次のコマンドでComposerがインストールされているかどうかを確認できます。

 composer --version

「コマンドが見つかりません」というエラーが表示された場合は、次のコマンドを使用してComposerをインストールできます。

 sudo curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

次に、空のディレクトリを作成し、そのディレクトリ内で次のコマンドを実行します。

 composer require apex/container
composer require twig/twig

これにより、以下の例で使用されるApexコンテナと人気のあるTwigテンプレートエンジンの両方がダウンロードされます。どちらも/ vendor /サブディレクトリ内にあります。

ツールを注入する

次のコードを使用して、 Carというクイッククラスを作成しましょう。

 
<?php
use TwigLoaderArrayLoader;
class Car
{
public function __construct(
public string $model,
public string $color,
public ArrayLoader $db
) {
echo "I'm a $color $model and have a " . $db::class . "
";
}
}

これは、車のメーカーと色の2つのプロパティを持つ単純なクラスであり、Twigから「ArrayLoader」クラスをロードします。それをcar.phpとして保存し、依存性注入の魔法を使用する準備をします。別の空のファイルを開き、次のコードを追加します。

 
<?php
use ApexContainerContainer;
// Load Composer packages, and the car.php file
require_once(__DIR__ . '/vendor/autoload.php');
require_once(__DIR__ . '/car.php');
// Create container, and add a couple tools
$cntr = new Container(use_attributes: true);
$cntr->set('model', 'Jaguar');
$cntr->set('color', 'silver');
// Create our car object
$car = $cntr->make('Car');
$car2 = $cntr->make('car', ['color' => 'red']);

このコードをターミナルに保存して実行すると、結果は次のようになります。

 I'm a silver Jaguar and have a TwigLoaderArrayLoader
I'm a red Jaguar and have a TwigLoaderArrayLoader

上記のコードでは、コンテナ(つまり、ツールキット)をインスタンス化し、車の色とメーカーのツールをいくつか追加しました。通常の新しいCar()でcarオブジェクトを作成する代わりに 、コンテナのmake()メソッドを介して作成されました。これは、最初にクラスを通過して要件を確認し、次に利用可能なアイテム(つまりツール)を調べ、それらをクラスに注入してから返しました。

ファイルの先頭にあるArrayLoaderへのuse宣言に気付くでしょう。また、コンストラクターの3番目の引数もArrayLoaderを要求します。コンテナがクラスの要件を調べたとき、これらの両方の側面に気づき、 ArrayLoader `のインスタンスを自動的に作成し、それをコンストラクターに注入しました。これは自動配線と呼ばれます。

属性インジェクションによる拡張

さらに一歩進んで、コンストラクターに注入するだけでなく、属性を介してプロパティに直接注入することもできます。車のファイルを変更し、次のように変更します。

 
<?php
use TwigLoaderArrayLoader;
use ApexContainerContainer;
class Car
{
#[Inject(Container::class)]
public Container $cntr;
public function __construct(
public string $model,
public string $color,
public ArrayLoader $db
) {
echo "I'm a $color $model and have a " . $db::class . "
";
}
function getCost()
{
echo "Class is " . $this->cntr::class . "
";
}
}

唯一の変更は、新しいuse宣言が追加され、Containerクラスに属性を持つプロパティが追加され、新しいgetCost()関数が追加されたことです。以前に実行したテストコードの最後に、次の行を追加します。

 $car->getCost();

コードを再度実行すると、結果は次のようになります。

 I'm a silver Jaguar and have a TwigLoaderArrayLoader
I'm a red Jaguar and have a TwigLoaderArrayLoader
Class is ApexContainerContainer

car.phpクラスがロードされた今回は、また、そのプロパティを見コンテナは、コンテナクラスのために呼ばれることを注入する属性を気づいて、それのインスタンスを注入しました。この方法で属性を介して注入することは、物事をよりクリーンで読みやすく保つのに役立つため、時々好まれます。

独自のツールを入手する

常にアイテムを注入する代わりに、コンテナからアイテムを自分で取得したい場合はどうなりますか?これは、コンテナのget()メソッドを使用して簡単に実行できます。 car.phpファイル内で、以前に追加したgetCost()関数を次のように変更します。

 
function getCost()
{
$price = $this->cntr->get('car_price');
echo "The price is $price
";
}

これで、実行しているテストコード内で、 getCost()を呼び出す行の前に、次のような行を追加します。

 $cntr->set('car_price', 24995);

コードを実行すると、結果は次のようになります。

 I'm a silver Jaguar and have a TwigLoaderArrayLoader
I'm a red Jaguar and have a TwigLoaderArrayLoader
Price is 24999

必ずしもアイテムを挿入する必要はなく、上記のようにget()メソッドを使用して必要なものをいつでも簡単に取得できます。

依存性注入で前進する

これで、依存性注入とは何か、そしてそれがどのように機能するかについての概要がわかりました。繰り返しますが、上記は多くの実装の1つにすぎませんが、そこにあるすべての実装はget()/ set()/ make()メソッドで同じように機能します。

定義ファイルやメソッドの注入など、依存性の注入にはまだまだ多くのことがあります。興味がある場合は、 ApexContainerのマニュアルまたはその他の実装を確認してください。