Изменение класса для инкапсуляции вместо наследования

Кодовая база, которую мне передали для работы с функциями класса databse, который наследует от MDB2. Это создает основу для используемой структуры MVC (пользовательская конструкция), а модели, в свою очередь, наследуют от db.

Как я уверен, некоторые из вас заметили, это приводит к довольно большой проблеме. Каждый раз, когда вы создаете экземпляр модели, результатом является создание новой базы данных. Это, очевидно, довольно расточительно. Это также означает, что я не могу использовать транзакции по назначению, потому что, если транзакция начинается в одном экземпляре модели, ее эффекты невидимы для других экземпляров, пока не произойдет фиксация.

Мой план состоит в том, чтобы изменить класс db, чтобы инкапсулировать MDB2 вместо наследования на него, а затем поддерживать один экземпляр MDB2 через его одноэлементные функции.

Тем не менее, MDB2 - это большая библиотека с множеством методов, и многое из того, что выше в базе кода, зависит от возможности доступа к методам MDB2.

Есть ли способ инкапсулировать класс MDB2 и передавать ему вызовы без изменения более высоких уровней и без необходимости писать метод-обертку для каждого метода в MDB2?

Ответ 1

Так как вы еще не указали какой-либо код, это нелогичное предложение о том, как вы можете удалить наследование с очень маленьким кодом и в то же время сохранить полную функциональность и убедиться, что класс 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. Это будет доступно для всех экземпляров БД, включая дочерние классы. Здесь нет оснований использовать Singleton.

Перехватчик __call гарантирует, что любые методы, которые вы вызывали в БД, вызывающие методы по методу MDB, будут пойманы и делегированы экземпляру MDB. Магические методы могут иметь серьезное влияние на производительность, поэтому, когда вы заметили какое-либо влияние на производительность, добавьте любые вызываемые методы в класс DB и делегируйте оттуда.

Излишне говорить, что это еще не лучшее решение, потому что ваш экземпляр БД по-прежнему тесно связан с вашими классами моделей. Если вы можете позволить себе больше рефакторинга, я бы предложил сделать все классы, которые в настоящее время наследуются от БД, инкапсулировать экземпляр БД вместо (если они не являются ActiveRecords). Затем используйте Dependency Injection, чтобы сделать экземпляр DB доступным.