Ground Sunlight

Windowsで作る - PHPプログラミングの開発環境

ユーザ用ツール

サイト用ツール


basic-library:league-container:3.3

文書の過去の版を表示しています。


TODO: 編集中

DIコンテナー - League/Container

Version 3.3 (MIT License)

— y2sunlight 2020-04-18

定番ライブラリー に戻る

関連記事

リンク

テストプログラムの所在

{Project Folder}\test\league-container\

League/Containerについて

DIコンテナの主な目的はコントローラへの依存性の注入(DI)にあると思います。それはビジネスロジックであるサービスとコントローラやビューとの結合性を如何に疎にするかによって開発効率、保守性やテスト容易性が決まるからに他なりません。しかし「ちょっとした機能のプログラムをPHPでサクサクと実装したい」のが目的のApricotにDIコンテナが果たして必要なのでしょうか。迷いましたが結果的には、ORMやリクエストルーターと同じくシンプルで軽量なものを選定して追加することにしました。現在ではDIコンテナはもはやソフトウェア開発にとって当たり前の部品なのかもしれません。

DIコンテナにはいくつかの候補があがりました。シンプルで軽量という時点で多機能で秀作なDIコンテナであるPHP-DIは除外されましたが、場合によっては選択してもよかったと思っています。そして次の2つが候補に残りました:

PimpleはSlimでも採用されいる軽量DIコンテナです。どちらにするか迷いましたが、最終的には、PHP-DIにも搭載されている Auto Wiring をサポートしているContainerの方を採用することにしました。Auto Wiring とはコンストラクター引数の型ヒントを調べることにより、オブジェクトとそのすべての依存関係を再帰的に自動的に解決する機能の事です。Auto Wiring については手動での簡易実装を考えていたので、その手間のかからないContainerを選びました。

尚、Containerについては、(Containerではあまりに一般的な呼称なので)誤解のないように、プロバイダ名を冠して「League/Container」と呼ぶ事にします。League(リーグ)の正式名称は The League of Extraordinary Packages で、この組織は最新のコーディング標準を使用して、しっかりとテストされたPHPパッケージを構築するために結束した開発者のグループのことです。

インストール

composer require league/container
Using version ^3.3 for league/container
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Installing psr/container (1.0.0): Loading from cache
  - Installing league/container (3.3.0): Loading from cache
Writing lock file
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
Note:
Eclipse起動中にパッケージを取得した場合は、プロジェクト・エクスプローラー内の[プロジェクト(apricote)]を右クリックして[リフレッシュ]を選択して下さい。また、新しく取得したパッケージのインテリセンスが有効にならない場合は、プロジェクトのビルトまたはクリーン&ビルドを行ってビルドリストの更新を行って下さい。

パッケージの取得が終わると composer.json の require に以下が追加されます。

composer.json
{
    "require": {
        "league/container": "^3.3"
    }
}


テストプログラム

パッケージのテストフォルダ(test\league-container\)に、以下のテスト用のコードを作成します。この例は League/Containerのマニュアル に記載されている Auto Wiringの例題 を簡素化したものです。

  • Foo.php — 2つのサービス(BarとBza)を持つFooコントローラ
  • index1.php — 手動によるコンストラクター・インジェクションの例
  • index2.php — DIコンテナ― によるコンストラクター・インジェクションの例
  • index3.php — Auto Wiring によるコンストラクター・インジェクションの例
  • index4.php — Auto Wiring だがDIコンテナーをキャッシュしている例
Foo.php
<?php declare(strict_types=1);
 
namespace Acme;
 
class Foo
{
    /**
     * @var \Acme\Bar
     */
    public $bar;
 
    /**
     * @var \Acme\Baz
     */
    public $baz;
 
    /**
     * Construct.
     *
     * @param \Acme\Bar $bar
     * @param \Acme\Baz $baz
     */
    public function __construct(Bar $bar, Baz $baz)
    {
        $this->bar = $bar;
        $this->baz = $baz;
    }
}
 
class Bar
{
    // ..
}
 
class Baz
{
    // ..
}


【テスト1】手動によるコンストラクター・インジェクション

サービス及びコントローラをDIコンテナーを使わずに手動で注入している例です。尚、例題ではComposerによるAutoloadを使用していないので、spl_autoload_register()で代替しています。

index1.php
<?php declare(strict_types=1);
require __DIR__.'/../../vendor/autoload.php';
 
// ComposerのAutoloadの代替
spl_autoload_register(function ($class)
{
    require __DIR__.'/Foo.php';
});
 
//-------------------------------------
// 手動によるコンストラクター・インジェクション
//-------------------------------------
$baz = new Acme\Baz;
$bar = new Acme\Bar;
$foo = new Acme\Foo($bar, $baz);
 
var_dump($foo instanceof Acme\Foo);           // true
var_dump($foo->bar instanceof Acme\Bar);      // true
var_dump($foo->baz instanceof Acme\Baz);      // true

結果

D:\usr\ws2019\apricot\test\league-container\index1.php:17:boolean true
D:\usr\ws2019\apricot\test\league-container\index1.php:18:boolean true
D:\usr\ws2019\apricot\test\league-container\index1.php:19:boolean true


テスト3

TODO:
index3.php
<?php declare(strict_types=1);
require __DIR__.'/../../vendor/autoload.php';
 
// ComposerのAutoloadの代替
spl_autoload_register(function ($class)
{
    require __DIR__.'/Foo.php';
});
 
//-------------------------------------
// Auto Wiring による
//-------------------------------------
$container = new League\Container\Container;
 
// リフレクションコンテナーをデリゲートとして登録してAuto Wiringを有効にする
// (注)既定では、リフレクションコンテナーは、要求するたびに要求を解決します。
$container->delegate(
    new League\Container\ReflectionContainer
);
 
$foo = $container->get(Acme\Foo::class);
 
var_dump($foo instanceof Acme\Foo);           // true
var_dump($foo->bar instanceof Acme\Bar);      // true
var_dump($foo->baz instanceof Acme\Baz);      // true

結果

D:\usr\ws2019\apricot\test\league-container\index3.php:23:boolean true
D:\usr\ws2019\apricot\test\league-container\index3.php:24:boolean true
D:\usr\ws2019\apricot\test\league-container\index3.php:25:boolean true


テスト4

TODO:
index4.php
<?php declare(strict_types=1);
require __DIR__.'/../../vendor/autoload.php';
 
// ComposerのAutoloadの代替
spl_autoload_register(function ($class)
{
    require __DIR__.'/Foo.php';
});
 
//-------------------------------------
// Auto Wiring による
//-------------------------------------
$container = new League\Container\Container;
 
// リフレクションコンテナーのキャッシュを有効にするに、以下のようにします
$container->delegate(
    (new League\Container\ReflectionContainer)->cacheResolutions()
    );
 
$fooOne = $container->get(Acme\Foo::class);
$fooTwo = $container->get(Acme\Foo::class);
 
var_dump($fooOne === $fooTwo); // true

結果

D:\usr\ws2019\apricot\test\league-container\index4.php:23:boolean true


basic-library/league-container/3.3.1587265087.txt.gz · 最終更新: by y2sunlight