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
发起讨论 只看当前版本


暂无话题~