可以进行依赖项注入回退吗


Is it okay to have a dependency injection fallback?

我已经编写了一个使用DI的开源PHP库。

该库有一个供想要使用它的人使用的入口点,即Client类,它有一个构造函数,看起来像这样(简化):

class Client {
    protected $depOne;
    protected $depTwo;
    public function __construct(DependencyOne $depOne, DependencyTwo, $depTwo)
    {
        $this->depOne = $depOne;
        $this->depTwo = $depTwo;
    }
}

DependencyOne和DependencyTwo也有各自的依赖关系。这意味着任何想要使用我的库的人,没有使用DI,都需要这样做:

$dependencyThree = new DependencyThree();
$dependencyFour = new DependencyFour();
$dependencyFive = new DependencyFive();
$dependencyOne = new DependencyOne($dependencyThree, $dependencyFour);
$dependencyTwo = new DependencyTwo($dependencyFive);
$client = new Client($dependencyOne, $dependencyTwo);
$someStuff = $client->doTheThing();

的依赖项注入仅设为该类的可选项会不会很糟糕?例如

class Client {
    protected $depOne;
    protected $depTwo;
    public function __construct(DependencyOne $depOne = null, DependencyTwo, $depTwo = null)
    {
        if (!isset($depOne)) {
            $depThree = new DependencyThree();
            $depFour = new DependencyFour();
            $depOne = new DependencyOne($depThree, $depFour);
        }
        if (!isset($depTwo)) {
            $depFive = new DependencyFive();
            $depTwo = new DependencyTwo($depFive);
        }
        $this->depOne = $depOne;
        $this->depTwo = $depTwo;
    }
}

这意味着不使用DI的人可以这样做:

$client = new Client();
$someStuff = $client->doTheThing();

那些想要使用DI或用于单元测试的人,依赖关系仍然可以传递

这是个坏主意吗?如果是,为什么?

这正是我在开源项目中所做的,我认为这是一个非常好的解决方案。

它为用户提供了一种不用付出任何努力就可以开始使用库的方式,同时也让他们可以覆盖任何内容。

我有时选择的另一个解决方案是有一个构建器类或工厂,例如,这个构造函数有强制参数,但ContainerBuilder隐藏了这种复杂性。

构建器的优点是它将配置部分从类中移除。如果配置部分开始增长(关注点分离),这将非常有用。

我同意@Unex的观点。让DI成为可选的并不是坏事,但我会在我的库中提供一个工厂,而不是在构造函数中进行硬编译。通过这种方式,您可以保持与DI相同的松散耦合,并使Client类具有单一的责任。为什么客户端类知道如何构造其他类?类构造函数是关于自我认识的,仅此而已。请记住,构建整个依赖链可能又大又复杂,甚至可能需要在引导程序中读取配置文件、访问其他php模块中定义的常量、调用实用程序函数等;您不希望在构造函数中包含所有这些代码。