<?php
/*
* DIコンテナの構成
* 依存関係を集中管理し、呼び出し側の処理をすっきりさせる
*/
/**************************************************/
// メール送信インターフェイス
interface MailerInterface
{
public function send($body);
}
// ログ記録インターフェイス
interface LoggerInterface
{
public function record($body);
}
/**************************************************/
// Sendmailでメール送信
class SendmailMailer implements MailerInterface
{
public function send($body)
{
echo 'Sendmailで送信しました:' . $body . "\n";
}
}
// SMTPでメール送信
class SmtpMailer implements MailerInterface
{
public function send($body)
{
echo 'SMTPで送信しました:' . $body . "\n";
}
}
/**************************************************/
// ファイルでログ記録
class FileLogger implements LoggerInterface
{
public function record($body)
{
echo 'Fileで記録しました:' . $body . "\n";
}
}
// データベースでログ記録
class DatabaseLogger implements LoggerInterface
{
public function record($body)
{
echo 'Databaseで記録しました:' . $body . "\n";
}
}
/**************************************************/
// ニュースレター送信
class NewsletterTransfer
{
protected $mailer, $logger;
public function __construct(MailerInterface $mailer, LoggerInterface $logger)
{
$this->mailer = $mailer;
$this->logger = $logger;
}
public function send($message)
{
$this->mailer->send($message);
$this->logger->record(date('Y-m-d H:i:s') . ':送信完了');
}
}
/**************************************************/
// DIコンテナ
class Container
{
function createMailer()
{
return new SendmailMailer;
}
function createLogger()
{
return new FileLogger;
}
function createNewsletterTransfer()
{
return new NewsletterTransfer($this->createMailer(), $this->createLogger());
}
}
/**************************************************/
// 送信処理
$container = new Container;
$newsletterTransfer = $container->createNewsletterTransfer();
$newsletterTransfer->send('今月のピックアップニュース');
/**************************************************/
/*
■コンテナの命名規則(自分の理解での補足)
クラスを生成して返すのでメソッドに「create」と付けているが、
シングルトンにするなら「singleton」、インスタンスなら「instance」にすると良さそう
■Facadeとの比較(自分の理解での補足)
単純に以下のような共通メソッドを定義して、
Facadeとして集中管理するという手段もある
class SenderManager
{
public static sendNewsletter($message)
{
$newsletter = new NewsletterTransfer(new SendmailMailer(), new FileLogger());
$newsletter->send($message);
}
}
が、DIコンテナの方が「メールの送信はこのクラス」「ログの記録はこのクラス」の管理が明確になる
Containerに例えば以下のようなメソッドを追加した場合でも、
メールとログのクラスはコンテナで作成されており、差し替えがしやすい
function createOrderletterTransfer()
{
return new OrderletterTransfer($this->createMailer(), $this->createLogger());
}
■コンテナを多用しすぎる弊害(自分の理解での補足)
何でもかんでもコンテナで管理すると、コンテナの情報量が多くなりすぎてかえって収集がつかなくなる
また実装クラスが隠蔽されるため、「本来の処理はどこにあるの?」となって見通しが悪くなる
コンテナでの管理は疎結合が必要とされる処理に限定する。そのような処理はアプリケーション内でごく一部となるはず
疎結合が必要とされない箇所はFacadeで処理の窓口を作るくらいでいい
使用フレームワークの処理を参考にしてルールを決めるなどするといい
■参考ページ
DIとは?DIコンテナとは?試してみた(前編)[PHP][DI] - あざらし備忘録。
http://shiro-goma.hatenablog.com/entry/2014/06/22/102236
Dependency Injectionを特定のDIコンテナに頼らず実現する - Qiita
http://qiita.com/Hiraku/items/48fbdfca4b63c74494e9
DIコンテナの本当の使いどころ | 技術トピックス | ウルシステムズ株式会社
https://www.ulsystems.co.jp/topics/025
*/