25
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Dependency Injectionを特定のDIコンテナに頼らず実現する

Last updated at Posted at 2014-02-26

Pimple風の名前ベースでインジェクション設定を書いていくやり方なら、ただのファクトリで再現できそうに思った。

Pimpleのコア機能はPimpleがなくても実現できる仮説

DIのサンプルはPHPメンターズのものを流用させていただく。
PHPメンターズ -> Pimpleでシンプルに正しくDIを理解する

Pimpleの場合。

di.php
<?php
$container = new \Pimple();

// オブジェクトコンストラクションのコンフィギュレーション
$container['infrastructure.mailer'] = function($container) {
    $mailer = new \SendmailMailer();

    return $mailer;
};
$container['domain.transfer.newsletter'] = function($container) {
    $newsletterTransfer = new \NewsletterTransfer($container['infrastructure.mailer']);

    return $newsletterTransfer;
};

return $container;

素のクラスにしてみる。

FactoryDefault.php
<?php
class FactoryDefault
{
  function createInfrastructureMailer()
  {
    return new SendmailMailer;
  }

  function createDomainTransferNewsletter()
  {
    return new NewsletterTransfer($this->createInfrastructureMailer());
  }
}
example.php
<?php
$container = new FactoryDefault;
// オブジェクトの利用
$newsletterTransfer = $container->createDomainTransferNewsletter();
$newsletterTransfer->send('ニュースレター本文');

メソッド名をラベルとして使うスタイルです。実現できてますね!

ファクトリによるDI設定のテクニック

オブジェクトの生成を使いまわす(疑似シングルトン)

static変数でキャッシュすればおk。
たとえばさっきの例でInfrastructureMailerは毎回作らなくても、同じオブジェクトを使いまわせばいいのなら、こんな感じか?

  function createInfrastructureMailer()
  {
    static $mailer;
    return $mailer ?: ($mailer = new SendmailMailer);
  }

設定を上書きする

DIコンテナなんていらない - usagidropの日記
このページだと、ファクトリをグローバル関数で書いてしまっている。PHPの関数は一度定義すると上書きできないので、拡張性を担保するならばクラスで書いてメソッドにした方がよいだろう。
ファクトリによるDIコンテナなら上書きが可能である。

たとえばさっきの例で、テストをしたいからInfrastructureMailerはモックに差し替えたい、という場合。

FactoryTest.php
<?php
class FactoryTest extends FactoryDefault
{
  function createInfrastructureMailer()
  {
    return new SendmailMailerMock;
  }
}
test.php
<?php
$container = new FactoryTest; //こっちに差し替える
//...

Mockに差し替えられた。

設定を継承して追加する

もちろんクラスの継承なので、parent::も使える。
たとえばさっきの例で、InfrastructureMailerに何か設定を追加したい場合。こんな感じでいける。

//...
  function createInfrastructureMailer()
  {
    $mailer = parent::createInfrastructureMailer();
    $mailer->setOption('hogehoge');
    return $mailer;
  }
//...

素のFactoryをDIコンテナとして利用するメリット

  • 特定のDIコンテナライブラリが不要
  • たぶん速い
  • コア機能は割となんとかなりそうな気がする
  • IDEで入力補完がきく

素のFactoryをDIコンテナとして利用するデメリット

  • PHP<5.4だと設定ファイルの分割ができない。traitが必要
  • 複数の設定ファイルをマージできない。traitが必要
  • 所詮は名前ベースのインジェクタなので、大規模になると名前管理で破綻する
  • AOPなどの豪華機能はない
25
23
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?