Windowsで作る - PHPプログラミングの開発環境
このページへのアクセス 今日: 0 / 昨日: 1 総計: 2977
文書の過去の版を表示しています。
TODO: 編集中
Version 3.3 (MIT License)
— y2sunlight 2020-04-18
定番ライブラリー に戻る
関連記事
リンク
テストプログラムの所在
{Project Folder}\test\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を選びました。
Auto Wiring
尚、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
{ "require": { "league/container": "^3.3" } }
パッケージのテストフォルダ(test\league-container\)に、以下のテスト用のコードを作成します。この例は League/Containerのマニュアル に記載されている Auto Wiringの例題 を簡素化したものです。
<?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 { // .. }
DIコンテナーを使わずに、サービスをコントローラに手動で注入している例です。尚、例題ではComposerによるAutoloadを使用していないので、spl_autoload_register()で代替しています。
<?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
League/Containerは Auto Wiring 機能をサポートします。これは、コンストラクター引数の型ヒントを調べることにより、オブジェクトとそのすべての依存関係を再帰的に自動的に解決する機能です。但し、注入できるのはオブジェクト型の変数だけです。
Auto Wiring はデフォルトで無効になっているので、有効にするにはコンテナデリゲートとして ReflectionContainer を登録しなけらばなりません。
ReflectionContainer
<?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
TODO:
<?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