单例(以及为什么要使用依赖注入)

单例类是只能实例化一次的类。实际上,在一个应用程序中,每个单例类只能有一个对象。如果你以前从未听说过 Singletons,你可能会跃跃欲试,心想:"太好了!我有一百万个这样的用例!" 请不要这样想。Singletons 非常糟糕,可以有效避免。

因此,PHP 中的 Singleton 类看起来是这样的:

<?php

class Singleton
{
    private static $instance;

    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    protected function __construct()
    {
    }

    private function __clone()
    {
    }

    private function __wakeup()
    {
    }
}

以下是应避免使用的原因:

  • 它们本质上是紧密耦合的,这意味着很难对其进行测试,例如使用单元测试。它们甚至会在应用程序的整个生命周期中保持自己的状态。

  • 它们控制着自己的创建和生命周期,违反了单一责任原则。

  • 从根本上说,它导致您将应用程序的依赖关系隐藏在全局实例中。您再也无法在代码中有效地跟踪依赖关系,因为您无法跟踪它们作为函数参数注入的位置。如果需要对依赖关系链进行分析,也无法找到依赖关系链。

尽管如此,有些人认为它们可以有效地解决资源争用问题(在这种情况下,您只需要一个资源实例,并且需要管理该单一资源)。

依赖注入

依赖注入是单例的解药。因此,假设您有一个名为 Transaction 的类。作为该类的构造函数,它接受名为 $creditCardNumber$clientID 的参数,因此我们可以如下构造该对象:

$order = new Transaction('1234 5678 9012 3456', 26);

在使用依赖注入时,我们将传递 $creditCard$client 的对象,它们将是信用卡和客户端类的实例。如果使用的是 ORM,则可以是数据库模型类:

$order = new Transaction($clientCreditCard, $client);