【问题标题】:PHP Dependency injection when the arguments for the constructor are not available当构造函数的参数不可用时 PHP 依赖注入
【发布时间】:2023-03-27 17:10:01
【问题描述】:

我们刚刚开始齐心协力在我们的项目中统一使用依赖注入,我遇到了一个问题。

我正在编写一个类来处理我们的 MongoDB 查询。我将 MongoClient 作为对构造函数的依赖项传入,没有问题。但是当实例化对象所需的变量在实例化时不可用时,如何处理依赖关系?

特别是,我们有一个 MongoCollection 方法的包装器 findOne,如果您传入一个字符串,当前(在旧代码中)将该字符串转换为带有“new MongoId($_id)”的 MongoId,并且将其用于查找功能。

根据我对依赖注入的了解,使用“new MongoId”是个坏主意,而且我已经知道,为将字符串转换为 MongoId 的函数编写测试用例会变得更加困难。

但是当 MongoId 类在构造函数上获取 id 字符串时,我该如何处理注入呢?

我认为唯一可行的方法是在类构造函数上传递一个闭包,该闭包执行以下操作:

$getMongoId = function( $id ){
    return new MongoId( $id );
};

class MyMongo
{
   function __construct( MongoClient $client, Closure $mongoIdGetter){...}
}

[编辑以修复最后一部分]

但这是处理它的正确方法吗?当然,如果我们使用 DiC,我们可以做到,但是要求构造函数的闭包似乎有点多。我对注入我的依赖关系太教条了吗?我想我可以通过在新类中使用“new MongoId($_id)”轻松解决这个问题。

【问题讨论】:

    标签: php mongodb dependency-injection


    【解决方案1】:

    你可以使用工厂代替闭包:

    class MongoFactory
    {
        public function createMongoDb($id)
        {
            return new MongoId($id);
        }
    }
    

    在工厂中,拥有“新事物”硬编码依赖项被认为是可以的,因为创建对象是它们的唯一目的,您可以轻松地将它们替换为另一个工厂。

    您的消费者类 (MyMongo) 现在将依赖于 MongoFactory(或它的接口,如果您愿意的话),您可以轻松地“注入”它。

    【讨论】:

      【解决方案2】:

      但是当实例化对象所需的变量在实例化时不可用时,我该如何处理依赖关系?

      在您有机会自己处理之前,PHP 将出现致命错误。如果您使用类型参数和/或未将它们定义为,默认情况下,null PHP 将在该参数未传递给任何函数时出现致命错误。

      根据我对依赖注入的了解,使用“new MongoId”是个坏主意,而且我已经知道,为将字符串转换为 MongoId 的函数编写测试用例会变得更加困难。

      它会(在 PHPUnit 中)吗?

      $this->assertInstanceOf('\MongoId', $getMongoId($id_string));
      

      但是当 MongoId 类在构造函数上获取 id 字符串时,我该如何处理注入?

      不知道你的意思是什么,但你应该只测试MongoIds 处理的结果。

      你问题的最后一点让我有点松懈,我认为这是因为它不是真正的 PHP(即$__construct)。

      我不确定您为什么需要像这样将函数推入类中。我的意思是我最多的时候是:

      function findById($id){
          if(!$id instanceof \MongoId) $id = new MongoId($id);
          return $this->getCollection()->findOne($id);
      }
      

      除此之外,您不需要任何其他东西,也不需要测试 MongoId 的构造函数,因为它已经过单元测试,您应该改为对您的公共 API 进行单元测试,而不是其他人的。

      【讨论】:

      • 谢谢——$__construct 只是一个脑放屁,上面已经修复了。我认为您部分误解了我的问题,因为当我在上面说“处理”时,我指的不是错误处理,只是这个词的一般含义。
      • @Karptonite 哦,好吧,你能解释一下为什么要将 MongoId 设置器放入构造中,我理解依赖关系,但在你实际使用 find 函数之前不需要它。我的意思是,对于单元测试,你只需要检查你的公共函数的响应,它返回一个在为_id 输入字符串时应该存在的文档,你不应该将单元测试扩展到 MongoDB 驱动程序本身跨度>
      • 所以我是依赖注入的新手——但我的理解是,使用像你这样写的函数,在代码中带有“new MongoId”,通常是一个坏主意——例如,如果我在代码中使用了 MongoId 的任何方法,我无法模拟它以确保我的代码正确调用了这些方法。诚然,这不是我现在正在做的事情。
      • @Karptonite 不,这还不错,因为该函数应该允许将字符串转换为 MongoId 对象(在我看来),我的意思是这是它的核心目的。你对MongoClient 有正确的想法,但对MongoId 没有,如果函数的目的是专门将字符串转换为MongoId,那么这就是我一直学到的。
      猜你喜欢
      • 2016-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      • 1970-01-01
      相关资源
      最近更新 更多