【问题标题】:Injecting single-use object into class将一次性对象注入到类中
【发布时间】:2012-10-06 20:25:07
【问题描述】:

我有以下代码:

<?php

class X
{
    public function do($url)
    {
        $httpRequest = new \HttpRequest\Curl($url, $this->getOptions());
        $httpRequest->fire();
        // etc.
    }
    // ...
}

为了能够对这个类进行单元测试,我想注入一个模拟的 HttpRequest 类。一种方法如下:

<?php

class X
{
    private $httpRequestClass;

    public function __construct($httpRequestClass = '\HttpRequest\Curl')
    {
        $this->httpRequestClass = $httpRequestClass;
    }

    public function do($url)
    {
        $httpRequest = new $this->httpRequestClass($url, $this->getOptions());
        $httpRequest->fire();
        // etc.
    }
    // ...
}

但这似乎不对。还有其他想法吗?

【问题讨论】:

    标签: php dependency-injection


    【解决方案1】:
     public function __construct($url, $httpRequestClass = null)
        {
            $this->url = $url;
            if ($httpRequestClass == null) //> Default
               $this->httpRequestClass = new HttpRequest\Curl($this->url);
            else
               $this->httpRequestClass = $httpRequestClass;
        }
    

    所以当你通常使用这个类时,只需用一个参数调用它

    yourClass('your url');
    

    否则在第二个参数中传递 istance

    yourClass('url', new MockedObj);
    

    当然你应该总是注入你的依赖而不提供默认对象

    【讨论】:

    • +1 - 您应该始终注入您的依赖项而不证明默认对象
    • @AlexP:我总是告诉别人……但我自己总是不尊重这条规则:D
    【解决方案2】:

    该类需要生成 HttpRequest 类型的对象,但我们不一定希望它初始化一个对象:例如,我们可能希望它使用原型模式。因此,该类需要工厂模式。为简洁起见,我选择了工厂回调,而不是工厂类。

    <?php
    
    class X
    {
        private $factoryCallback;
    
        public function __construct($factoryCallback = null)
        {
            $this->factoryCallback = $factoryCallback;
        }
    
        public function do($url)
        {
            $httpRequest = $this->createHttpRequest($url);
            $httpRequest->fire();
            // etc.
        }
    
        private function createHttpRequest($url)
        {
            $callback = $this->factoryCallback;
            if (is_callable($callback)) {
                return $callback($url, $this->getOptions());
            }
            return new \HttpRequest\Curl($url, $this->getOptions());
        }
        // ...
    }
    

    帮助方法 createHttpRequest() 在本示例中有点多余,但将用于生产代码中的错误处理。

    【讨论】:

    • 你能解释一下你为什么选择这个选项,这比其他答案中给出的方法更好吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-28
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    相关资源
    最近更新 更多