使用" new"构造函数中的关键字

时间:2013-01-08 16:48:12

标签: php oop

我最近读到在构造函数中使用关键字“new”非常不满意,但我不确定我理解为什么?例如,如何:

class A {
    public $foo;

    function __construct() {
        $this->foo = new Bar();
    }
}

与...不同:

class A {
    public function someMethod() {
        $foo = new Bar();
    }
}

???

3 个答案:

答案 0 :(得分:12)

这实际上是依赖注入背后的理论。

根据说,使用“新”并不是一个坏主意。相反,通过实例化类中的对象,您将创建硬依赖项,在不更改类本身的情况下,永远不会更改或切换它们。

它也违反了“编码接口而不是实现”的范例

示例:

class Phone {
    protected $network;

    public function __construct() {
        $this->network = new Verizon();
        $this->network->distinctiveRing();
    }
}

class Verizon {
    public function call($number) {
        ....
    }

    public function distinctiveRing() {

    }
}

现在,假设有一天你想创建一个ATT,TMobile和Sprint手机?当然,他们都可以打电话,只需要一个电话号码即可。此外,电话类不应该关心运营商是谁,因为它的工作是方便输入号码 - 而不是实际建立网络连接,对吗?

那就是说,我们不应该创建一个可以实例化另一个Sprint网络对象的新SprintPhone类,对吧?右。

那么更好的方法是什么?

class Phone {
    protected $network;

    public function __construct(NetworkInterface $network) {
        $this->network = $network;
    }
}

interface NetworkInterface {
    public function call($number);
}

class Verizon implements NetworkInterface {
    ...
}

class Sprint implements NetworkInterface {
    ...
}

现在,您可以说:$phone = new Phone(new Sprint())$phone = new Phone(new Verizon())

另请注意,我们对distinctiveRing的调用已消失。为什么?好吧,因为我们不知道实现NetworkInterface的任何对象都必然支持一个独特的环。 但这很好,因为现在我们的Phone可以支持 ANY Network而无需更改代码。

如果您需要支持特色铃声,您可以随时创建支持distinctiveRing方法的新界面。在Phone对象中,您可以检查Network 是否实现了 DistinctiveRingerInterface,如果是,请制作您的特色铃声。但是,您不再使用此方法与特定网络绑定。更好的是,你被迫这样做是因为你从一开始就采取了正确的方法。

并且,任何其他网络都可以在以后的路上创建。更重要的是,您的班级不再需要关心它所提供的网络对象类型。它知道(因为它收到了一个实现NetworkInterface的对象),Network对象能够使用call生成$number

这也可以带来更好的代码,更好地分离关注点。

最后:测试。

使用第一个示例,如果您尝试测试Phone对象,它将在Verizon网络上进行调用。因为你正在进行单元测试,所以整天都被叫到了,对吧?右。

好吧,只需创建一个实现NetworkInterface的TestNetwork类,并将其传递给您的手机对象。您的TestNetwork类可以在其call方法中执行任何操作 - 或者什么也不做。

此外,您可以使用PHPUnit创建模拟对象,并确保实际调用TestNetwork上的call方法。您之前无法执行此操作,因为Network已在Phone内实例化。

答案 1 :(得分:3)

您的问题和代码示例似乎没有太多分享?

您的第一个代码示例应该有效,因为您分配了一个类变量:

class A {
    public $foo;

    function __construct() {
        $this->foo = new Bar();
    }
}

您的第二个示例将其分配给__construct()方法的本地变量,因此您将无法在以后检索该值:

class A {
    public function someMethod() {
        $foo = new Bar();
    }
}

此外:使用new通常很好。但是,您可能已经阅读了关于控制或IOC的反转,这是一种避免依赖的技术,因此您将尝试避免直接在构造函数中创建类,例如参见http://ralphschindler.com/2011/05/18/learning-about-dependency-injection-and-php

答案 2 :(得分:1)

在第一个示例中,$ foo可用于此类中的任何方法,也可用于对象外部 所以你可以这样做:

$a = new A();
$a->foo->sth;

在第二个示例中,$ foo仅在someMethod中可用。