无法控制实例化和使用时的依赖注入

时间:2010-02-13 15:31:02

标签: php dependency-injection

怎么做?

我有一个Model类,它是许多子类的父类,而Model依赖于数据库连接和缓存机制。

现在,这就是它开始变得麻烦的地方:我无法控制每个对象如何被实例化或使用,但我可以控制子类使用的方法。

目前我已经使用静态方法和属性进行依赖注入:

class Model
{
    private static $database_adapter;
    private static $cache_adapter;
    public static function setDatabaseAdapter(IDatabaseAdapter $databaseAdapter)
    {
        self::$databaseAdapter = $databaseAdapter;
    }
    public static function setCacheAdapter(ICacheAdapter $cacheAdapter)
    {
        self::$cacheAdapter = $cacheAdapter;
    }
}

哪个效果很好,但感觉很脏(它为所有模型创建了一个全局状态)。

我已经考虑了工厂模式,但是从子类中删除了实例化的控制(如何在其构造函数中实例化具有可变数量参数的对象?)。

现在我不知所措。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

据我所知,这是一个完全可以接受的选择。 PHPUnit的创建者Sebastian Bergmann建议的另一种可能性是使用$测试静态属性。你可以阅读他最近关于Testing of Singletons的文章。听起来你有类似的问题。

答案 1 :(得分:0)

您的解决方案可以设置默认适配器,但我会为各个型号添加一种方法来使用不同的适配器。考虑一下:

abstract class Model {
    protected $_database_adapter;
    protected $_default_database_adapter;

    public function getDatabaseAdapter() {
        if(!$this->_database_adapter) {
            if(self::$_default_database_adapter) {
                $this->_database_adapter = self::$_default_database_adapter;
            } else {
                throw new Exception("No adapter set yet");
            }
        }
        return $this->_database_adapter;
    }

    public function setDatabaseAdapter(IDatabaseAdapter $databaseAdapter) {
        $this->_database_adapter = $databaseAdapter;
    }

    public static function setDefaultDatabaseAdapter(IDatabaseAdapter $databaseAdapter) {
        self::$_default_database_adapter = $databaseAdapter;
    }
}

当然,您可以将所有静态方法/属性提取到RegistryContainer或其他任何内容中。

例如,您可能不希望在整个应用程序中从同一数据库主机收集数据。然后您的原始脚本将如下所示:

Model::setDatabaseAdapter($default);
$my_model->query('....');
Model::setDatabaseAdapter($another_adapter);
$my_other_model->query('....');
Model::setDatabaseAdapter($default);

非常相似:

mysql_select_db('default_db');
mysql_query('...');
mysql_select_db('other_db');
mysql_query('...');
mysql_select_db('default_db');