• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

[PHP-DI]理解依赖注入

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

依赖注入依赖注入容器 是不同的:

  • 依赖注入 (Dependency injection) 是编写更好代码的一种方法
  • 容器 (Container) 是帮助注入依赖关系的工具

你不需要一个容器来执行依赖注入,但是一个容器可以帮助你。

PHP-DI就是这样做的:使依赖注入更加实用。

理论

经典的PHP代码

下面是使用DI的代码大致工作的方式:

  • 应用程序需要 Foo(例如一个控制器),所以:
  • 应用程序创建 Foo
  • 应用程序调用 Foo
    • Foo 需要 Bar(例如一个服务),所以:
    • Foo 创建 Bar
    • Foo 调用 Bar
      • Bar 需要 Bim(一个服务,一个仓库……),所以:
      • Bar 创建 Bim
      • Bar 做一些事情

使用依赖注入 (Dependency injection)

下面是使用DI的代码大致工作的方式:

  • 应用程序需要 Foo ,它需要 Bar,它需要Bim,所以:
  • 应用程序创建 Bim
  • 应用程序创建 Bar 并给它 Bim
  • 应用程序创建 Foo 并给它 Bar
  • 应用程序调用 Foo
    • Foo 调用 Bar
      • Bar 做一些事情

这是控制反转的模式,被调用者和调用者之间的依赖性控制是相反的

最主要的优点是:在调用链顶部的那个总是。你可以控制所有依赖项,并完全控制您的应用程序的工作方式,你可以用另一个(例如你创建的一个)来替换依赖项。

例如,如果库X使用 Logger Y,而你想让它使用 Logger Z 呢?有了依赖注入,你就不需要更改库X的代码了。

使用容器 (Container)

那么,使用PHP-DI的代码是如何工作的:

  • 应用程序需要 Foo,所以:
  • 应用程序从 Container 获取 Foo,所以:
    • Container 创建 Bim
    • Container 创建 Bar 并给它 Bim
    • Container 创建 Foo 并给它 Bar
  • 应用程序调用 Foo
    • Foo 调用 Bar
      • Bar 做一些事情

简而言之,容器包含了创建和注入依赖的所有工作

In short, the container takes away all the work of creating and injecting dependencies.

用一个例子来理解

这是一个真实的例子,比较了一个经典的实现(使用new或单例)和使用依赖注入。

没有依赖注入

假设你有:

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) 定义的:

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

class GoogleMaps implements GeolocationService { ...

class OpenStreetMap implements GeolocationService { ...

现在,StoreService的用户可以决定使用哪个实现。 它可以随时改变,不必重写StoreService

StoreService不再与它的依赖紧耦合。

The StoreService is no longer tightly coupled to its dependency.

使用 PHP-DI

你可能会发现依赖注入会带来一个缺点:你现在必须处理注入依赖关系。

这就是容器(Container),特别是PHP-DI可以帮助你的地方。

而不是写:

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

你可以写:

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

并配置哪个GeolocationService PHP-DI应该通过配置自动注入到StoreService中:

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

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

感兴趣吗? 继续阅读开始使用PHP-DI指南!

参考

p.s. 看到PHP-DI没有中文文档,第一次对着机翻瞎翻译,如有疏漏敬请指正。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
php创建文件并写入信息发布时间:2022-07-10
下一篇:
php获取今日、昨日、上周、本月的起始时间戳和结束时间发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap