cee/simple-di

该软件包最新版本(v1.0)没有可用的许可证信息。

简单的依赖注入容器

v1.0 2017-10-12 07:07 UTC

This package is not auto-updated.

Last update: 2024-09-19 19:12:37 UTC


README

简单的依赖注入容器

Build Status

适用于构建服务类依赖树的工具。服务类是一个在应用中只有一个实例的类。它可以用作Nette Di容器的简单替代品。所有DI容器的配置都是用PHP语言完成的。

基本用法

$container = new Cee\SimpleDi\Container();
$classInstance = $container->createServiceOnce('ClassName');

使用接口作为依赖的示例

interface Logger {
  public function log($message);
}
interface Mailer {
  public function send($message, $subject, $to);
}

提供某些功能并依赖于先前接口的Service类

class NotificationService {
  private $mailer;
  private $logger;

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

  public function notify($message, array $recipients) {
    $subject = 'Notification';
    foreach ($recipients as $recipient) {
      $this->mailer->send($message, $subject, $recipient);
    }
    $this->logger->log(...);
  }
}

接口的实现

class ErrorLogLogger extends Logger {
  public function log($message) {
    error_log('Error: ' . $message);
  }
}
class SendMailMailer extends Mailer {
  public function send($message, $subject, $to) {
    mail($to, $subject, $message);
  }
}

最后是配置Simple DI容器和创建的NotificationService实例

$container = new Cee\SimpleDi\Container();

$container->setInterfaceImplementation(Logger::class, ErrorLogLogger::class);
$container->setInterfaceImplementation(Mailer::class, SendMailMailer::class);

$notificationService = $container->createServiceOnce(NotificationService::class);

Simple Di容器通过类型提示(使用PHP反射)填充参数。这被称为自动装配。

在服务类构造函数中没有类型提示参数的示例

class NotificationService {
  private $mailer;
  private $logFileName;

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

  public function notify($message, array $recipients) {
    $subject = 'Notification';
    foreach ($recipients as $recipient) {
      $this->mailer->send($message, $subject, $recipient);
    }
    file_put_contents($logFileName, ...);
  }
}

作为Simple DI容器扩展类的容器配置

namespace App;

class Container extends \Cee\SimpleDi\Container {
  public function __construct($logFileName) {
    $notificationService = new \NotificationService(new SendMailMailer(), $logFileName);
    $this->addServiceInstance($notificationService);
  }
}

在应用程序中我们使用自己的容器

$logFileName = 'log.txt';
$container = new App\Container($logFileName);
$notificationService = $container->createServiceOnce(NotificationService::class);

这个示例的缺点是NotificationService是在应用程序启动时创建的,而不是按需创建,就像其他由Simple DI容器创建的服务类。这对于不需要重构代码的旧代码很有用。但重构的目标是在服务类的所有无类型提示参数上创建包装器。在这种情况下,第一步是

class NotificationService {
  private $mailer;
  private $logFileName;

  public function __construct(Mailer $mailer, LogFileName $logFileName) {
  ...

之后,您不需要自己创建NotificationService。下一步是创建服务类Logger,就像示例中使用接口那样。

使用已创建的类的示例

典型用例是具有单例的旧代码,或者如果您需要进行逐步重构。在您可以启动DI容器之前,您已经有服务类的实例。您需要使用该类的自动装配将其用于其他类。

class Repository {
  public function __construct(MySqlConnector $mySqlConnector) {
  ...
}
class Container extends \Cee\SimpleDi\Container {
  public function __construct(MySqlConnector $mySqlConnector) {
    $this->addServiceInstance($mySqlConnector);
  }
}

并且它工作正常

$mySqlConnector = MySqlConnector::instance();
$container = new App\Container($mySqlConnector);
$repository = $container->createServiceOnce(Repository::class);