PHP入門:PHP-DIを導入して実行するまでの方法

スポンサーリンク
PHP入門:PHP-DIを導入して実行するまでの方法 環境構築
PHP入門:PHP-DIを導入して実行するまでの方法
この記事は約8分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

今日は、PHP-DIを導入して実行するまでの方法についてご紹介します。

スポンサーリンク

背景

PHP-DIに触れる機会がありましたので、PHP-DIを導入して実行するまでの方法を備忘として残しました。

作業ディレクトリの作成

下記のコマンドを実施します。

mkdir 22_learn-php-di
cd 22_learn-php-di

PHPのバージョンを指定

下記のコマンドを実施します。

asdf local php 8.2.7

asdfコマンドによるPHPの導入方法は、下記の記事をご覧ください。

composerコマンドの用意

下記のコマンドを実施します。

touch compose.yml

compose.ymlに下記の内容を保存します。

version: '3.8'

services:

  composer-cmd:
    image: composer
    container_name: composer-cmd
    volumes:
        - .:/app

下記のコマンドを実施します。

docker compose run -it --rm composer-cmd composer --version

下記のような結果になっていれば成功です。

% docker compose run -it --rm composer-cmd composer --version
Composer version 2.5.8 2023-06-09 17:13:21

PHP-DIのインストール

下記のコマンドを実行します。

docker compose run -it --rm composer-cmd composer require php-di/php-di

実行ファイルの準備

下記のファイルを用意します。ファイルの内容は下記のセクションで記載しています。

        new file:   Mailer.php
        new file:   UserManager.php
        new file:   Sample01.php
        new file:   Sample02.php

Mailer.php

下記の内容でファイルを新規作成します。

<?php

class Mailer
{
    public function mail($recipient, $content)
    {
        echo sprintf('%s : %s', $recipient, $content);
    }
}

UserManager.php

下記の内容でファイルを新規作成します。

<?php

class UserManager
{
    private $mailer;

    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    public function register($email, $password)
    {
        // The user just registered, we create his account
        // ...

        // We send him an email to say hello!
        $this->mailer->mail($email, 'Hello and welcome!');
    }
}

Sample01.php

下記の内容でファイルを新規作成します。

<?php

require_once "vendor/autoload.php";

$mailer = new Mailer();
$userManager = new UserManager($mailer);

$userManager->register('dummy@mail.com', 'password');

Sample02.php

下記の内容でファイルを新規作成します。

<?php

require_once "vendor/autoload.php";

$container = new DI\Container();
$userManager = $container->get('UserManager');

$userManager->register('dummy@mail.com', 'password');

composer.json

下記の緑色の箇所を追記します。

{
    "autoload": {
        "files": ["./Mailer.php", "./UserManager.php"]
    },
    "require": {
        "php-di/php-di": "^7.0"
    }
}

動作確認

PHP-DI がなければ、Sample01.phpのように依存関係を手動で「接続」しなければなりません。

実行結果は下記のとおりです。

% php Sample01.php 
dummy@mail.com : Hello and welcome!

それに対して、PHP-DIを使用すると、Sample02.phpのように依存関係をPHP-DIに解決させることができます。

実行結果は下記のとおりです。

% php Sample02.php 
dummy@mail.com : Hello and welcome!

それでは、どのようにして何を注入するか、どうやって知っているのでしょうか?

このコンテナは、自動接続(autowiring)と呼ばれる技術を使用しています。これはPHP-DIに特有のものではありませんが、それでも非常に優れています。コードをスキャンして、コンストラクタで必要なパラメーターを調べます。

この例では、UserManagerのコンストラクタはMailerオブジェクトを受け取ります。PHP-DIはこれを作成する必要があると知っています。非常に基本的な手法ですが、非常に効率的です。

でも、PHPコードをそのようにスキャンするのは奇妙でリスキーではないでしょうか?

心配しないでください、PHP-DIはPHPのReflectionクラスを使用しており、これはかなり標準的な方法です。LaravelやZend Frameworkなど、多くの他のコンテナも同じ方法を採用しています。パフォーマンス的には、そのような情報は一度読み取られてからキャッシュされるため、影響はありません。

依存関係の定義について

私たちは自動接続(autowiring)を見てきました。これは、PHP-DIがクラスが必要とする依存関係を自動的に解決する方法です。しかし、クラスに何をinjectionするかを定義する方法は3つあります。

  1. 自動接続を使用する方法
  2. 属性を使用する方法
  3. PHP定義を使用する方法

これらの方法はそれぞれ異なり、任意の選択肢です。以下は、PHP定義を使用する例です。ファイル内に以下のような内容が記述されています。

return [
    'api.url'    => 'http://api.example.com',
    'Webservice' => function (Container $c) {
        return new Webservice($c->get('api.url'));
    },
    'Controller' => DI\create()
        ->constructor(DI\get('Webservice')),
];

この定義方法については、後日ご紹介したいと思います。

フレームワークでの使用について

先ほどの例でわかるように、コンテナを使用してオブジェクトを取得できます。

$userManager = $container->get('UserManager');

ただし、アプリケーション内の至る所でコンテナを呼び出すのは避けたいです。なぜなら、それはコードをコンテナに依存させてしまうからです。これはサービスロケーターアンチパターンとして知られており、依存関係を取得する代わりにinjectionにするべきです。

Symfonyのドキュメントを引用すると:

「ある時点でコンテナから[オブジェクト]を取得する必要がありますが、これはアプリケーションのエントリーポイントでできるだけ少ない回数にすべきです。」

このため、PHP-DIはいくつかのフレームワークと統合しており、(コントローラーに依存関係が注入されるため)コンテナを呼び出す必要はありません:

  • Symfony
  • Slim
  • Silex
  • Zend Framework 2
  • Zend Expressive
  • Silly

別のフレームワークや独自のコードでPHP-DIを使用する場合は、ルートアプリケーションクラスまたはフロントコントローラー内で$container->get()を使用することをおすすめします。このデモアプリケーションを見ると、PHP-DIを中心に構築された実践的な例が確認できます。

おわりに

今日は、PHP-DIを導入して実行するまでの方法についてご紹介しました。

本記事でご紹介したソースは、下記のリポジトリにあります。

https://github.com/Gate-Yossi/Musica/releases/tag/v2023.09.04

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました