2.2. Understanding dependency injection

未匹配的标注

理解依赖注入

依赖注入依赖注入容器 的区别:

  • 依赖注入是一种方法 用来编写更好的代码
  • 容器是一个工具 帮助注入依赖项

不需要 容器也可以进行依赖注入。 但是,容器可以帮助您更好的注入依赖。

PHP-DI 的使命: 让依赖注入更加实用

理论

经典PHP代码

这是 不使用 DI 的代码工作方式:

  • 应用需要 Foo (e.g. a controller), 所以:
  • 应用创建Foo
  • 应用调用Foo
    • Foo 需要 Bar (e.g. a service), 所以:
    • Foo 创建 Bar
    • Foo 调用 Bar
      • Bar 需要 Bim (a service, a repository, …), 所以:
      • Bar 创建 Bim
      • 执行 Bar 的代码

使用依赖注入

这是使用 DI 的代码工作方式:

  • 应用需要 Foo, Foo需要Bar、Bim, 所以:
  • 应用创建 Bim
  • 应用创建 Bar并将Bim给它
  • 应用创建 Foo并将Bar给它
  • 应用调用 Foo
    • Foo调用 Bar
      • 执行 Bar 的代码

这就是 控制反转模式。从被调用到调用间依赖关系的控制是 倒置的 。

优点:调用链最顶端的总是 。 您可以控制所有依赖关系,并且可以完全控制应用程序的工作方式。您可以随时用另一个依赖项(例如您创建的依赖项)替换当前依赖。

例如,如果库X使用记录器Y,而您想使其使用记录器Z,该怎么办?使用依赖注入,您不必更改库X的代码。

使用容器

使用PHP-DI的代码如何工作:

  • 应用需要Foo,所以:
  • 应用从容器中获取Foo,所以:
    • 容器创建BIm
    • 容器创建Bar给到Bim
    • 容器创建Foo给到Bar
  • 应用调用Foo
    • Foo调用Bar
      • Bar执行

简单来说, 容器帮你省去了所有创建和依赖注入项的工作.

举例说明

这是一个真实示例, 使用经典方式 (使用 new 或者 单例) VS 使用依赖注入

不使用依赖注释时

你拥有以下代码:

class GoogleMaps
{
    public function getCoordinatesFromAddress($address) {
        // calls Google Maps webservice
    }
}
class OpenStreetMap
{
    public function getCoordinatesFromAddress($address) {
        // calls OpenStreetMap webservice
    }
}

经典方式实现:

class StoreService
{
    public function getStoreCoordinates($store) {
        $geolocationService = new GoogleMaps();
        // or $geolocationService = GoogleMaps::getInstance() if you use singletons

        return $geolocationService->getCoordinatesFromAddress($store->getAddress());
    }
}

现在我们需要用 OpenStreetMap 代替 GoogleMaps, 该怎么做?
我们不得不更改 StoreService的代码, 跟所有其他使用了 GoogleMaps的类.

不使用依赖注入, 你的类会紧紧依赖着依赖项.

使用依赖注入

现在 StoreService使用依赖注入:

class StoreService {
    private $geolocationService;

    public function __construct(GeolocationService $geolocationService) {
        $this->geolocationService = $geolocationService;
    }

    public function getStoreCoordinates($store) {
        return $this->geolocationService->getCoordinatesFromAddress($store->getAddress());
    }
}

服务都使用接口定义:

interface GeolocationService {
    public function getCoordinatesFromAddress($address);
}

class GoogleMaps implements GeolocationService { ...

class OpenStreetMap implements GeolocationService { ...

现在, 由StoreService的用户决定要使用的实现. 它可以随时更改, 而不需要重写 StoreService.

StoreService不再与其依赖关系紧密耦合

使用PHP-DI

您可能会看到依赖项注入有一个缺点: 你必须处理注入依赖项.

这就是容器, 特别是PHP-DI可以为你提供帮助的地方.

常规写法:

$geolocationService = new GoogleMaps();
$storeService = new StoreService($geolocationService);

容器写法:

$storeService = $container->get('StoreService');

通过配置来设置PHP-DI自动将哪个GeolocationService注入到StoreService:

$container->set('GeolocationService', \DI\create('GoogleMaps'));

如果您改变主意,现在只需更改一行配置即可。

有兴趣吗?继续阅读 Getting started 指南!

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/php-di/6.0/unde...

译文地址:https://learnku.com/docs/php-di/6.0/unde...

上一篇 下一篇
贡献者:3
讨论数量: 0
发起讨论 查看所有版本


暂无话题~