修改要封装的类而不是继承

时间:2010-11-22 10:29:00

标签: php singleton encapsulation mdb2

我已经交给代码库使用了一个继承自MDB2的数据库类的功能。这构成了正在使用的MVC框架(自定义构建的事务)的基础,而模型又从db继承。

我相信你们有些人已经注意到了,这导致了一个相当大的问题。每次实例化模型时,结果都是创建一个新的数据库连接。这显然非常浪费。这也意味着我无法按预期使用事务,因为如果事务在模型的一个实例中启动,则其效果对其他实例是不可见的,直到提交发生。

我的计划是将db类更改为封装MDB2而不是继承它,然后让它通过其单例功能维护单个MDB2实例。

然而,MDB2是一个拥有大量方法的大型库,代码库中更多的东西取决于能够访问MDB2方法。

有没有办法封装MDB2类并在不修改更高层的情况下将调用传递给它,而无需为MDB2中的每个方法编写包装器方法?

1 个答案:

答案 0 :(得分:3)

由于您还没有提供任何代码,这是一个盲目的建议,如何使用非常少的代码删除继承,同时保持完整的功能并确保MDB类仅实例化一次。

class Db
{
    protected static $_mdb;
    public function __construct()
    {
        if(self::_mdb === NULL) {
            self::_mdb = new MDB;
        }
    }
    public function __call($method, $args)
    {
        return call_user_func_array(array(self::_mdb, $method), $args);
    }
}

这基本上会使您的DB类成为MDB的装饰器。在第一次实例化时,DB类将创建并存储MDB的静态实例。这将在DB的任何实例之间共享,包括子类。没有理由在这里使用Singleton。

__call拦截器将确保您在DB中调用的任何调用MDB方法上的方法的方法都将被捕获并委派给MDB实例。 Magic方法可能会对性能产生严重影响,因此当您发现任何性能影响时,请将任何调用的方法添加到DB类并从那里委派。

毋庸置疑,这仍然不是最佳解决方案,因为您的数据库实例仍然与您的模型类紧密耦合。如果你能负担得起更多的重构,我建议让所有当前从DB继承的类封装数据库实例(除非它们是ActiveRecords)。然后使用Dependency Injection使数据库实例可用。