ФорумПрограммированиеPHP для идиотовPHP и ООП → непонятки с ООП

непонятки с ООП

  • Givi

    Сообщения: 2284 Репутация: N Группа: Адекваты

    Spritz Фев. 10, 2010, 9:32 п.п., спустя 1 час 45 минут 58 секунд


    коннект к базе делай в конструкторе
    если вынесешь сам коннект в отдельный метод а его вызовешь в конструкторе то ниче страшного

    Помоему второй вариант удобен если нужно конектится к двум разным базам. Или я ошибаюсь? Просто мне таки тоже интересно в каком направлении двигатся при написании класса если нужно будет предусмотреть возможность юзать две базы.
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz Фев. 10, 2010, 9:39 п.п., спустя 7 минут 5 секунд

    Givi, я конекчусь к двум разным базам в разных объектах. Поэтому это не важно. НРГ умное слово сказал - инкапсуляция. По-моему конструкт не должен знать как подключается база. Он просто организует то, что должно происходить при подключении класса.
  • Givi

    Сообщения: 2284 Репутация: N Группа: Адекваты

    Spritz Фев. 10, 2010, 9:53 п.п., спустя 13 минут 43 секунды

    SpartakuS, да пофигу будет он знать или нет - это просто метод, запускающийся автоматом при создании объекта. По сути он ничем не отличается от обычного метода.
    А вот относительно двух объектов, то тут уже хз правильно или нет, так как, если я правильно понимаю, тебе будет тяжело связать две базы в одном запросе. Но это я так… просто "теоретничаю" :)
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz Фев. 10, 2010, 10:06 п.п., спустя 12 минут 39 секунд

    Givi, я бы даже сказал нереально связать две базы в одном запросе в моем случае. Но мне и не нужно.
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz Фев. 10, 2010, 10:19 п.п., спустя 13 минут 39 секунд

    А делать класс с одним методом это нормально?
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Фев. 10, 2010, 10:51 п.п., спустя 31 минуту 29 секунд


    А делать класс с одним методом это нормально?
    нормально даже без методов.
    Сапожник без сапог
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz Фев. 10, 2010, 10:53 п.п., спустя 2 минуты 15 секунд

    phpdude,
    это ты серьезно? Для конфига например?
    PS Тот что с одним методом сделал как extends
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Фев. 10, 2010, 11:29 п.п., спустя 36 минут 17 секунд


    phpdude,
    это ты серьезно? Для конфига например?
    PS Тот что с одним методом сделал как extends
    почему сразу для конфига :)

    например как базу для instanceof ;)
    Сапожник без сапог
  • Nyaah

    Сообщения: 574 Репутация: N Группа: Джедаи

    Spritz Фев. 11, 2010, 9:52 д.п., спустя 10 часов 22 минуты 50 секунд

    SpartakuS, будет многа букв наверно, все что ниже мой личное мнение =)

    Что главное при создании библиотеки, не только бд, а любой:
    1. удобство (прежде всего для себя самого)
    2. лёгкая расширяемость
    3. возможность быстро дёрнуть код и использовать в другом проекте
    4. отсутствие повторяющегося кода

    у тебя пока из 4 пунктов есть только четвёртый, и то с натяжкой…

    будем плясать с самого начала, нет методов для получения кол-ва затронутых запросом строк, последнего автоинкримент ключа, дисконнекта плюс сама реализация порочна, так как ты не чистишь за собой память (нет ни одного mysql_close/mysql_free_result)

    по коду:
        // Уничтожаем объект в духе ООП :)
        // сам метод неправильно назван? должен быть __destruct()
        public function destroy() 
        {
            // неверно, нужно mysql_close($this->_dbHandle)
            // так как unset($this) сборщик мусора сам вызовет после того
            // как у тебя не останется ни одного линка на объект
            unset($this);
        }

    теперь если сделаешь как в коде выше, что произойдёт, если сделать так:
    $db1 = new DB('dle');
    $db2 = new DB('dle');
    unset($db1);
    $db2->query($sql);

    - словишь ошибку в 4 строке, так как деструктор убъёт подключение к бд, это есть плохо, соответственно нужно делать реестр подключений примерно так:
    class nyaaDatabase
    {
        // список подключений к бд
        protected static $_instances = array();
    
        /**
         * Возвращает инстанс подключения к определённой базе данных
         *
         * @param string $name имя подключения
         * @return nyaaDatabaseDriver
         */
        public static function getInstance($name = 'dle')
        {
             if (!array_key_exists($name, self::$_instances))
             {
                  // если объект ещё не создан, то создаём его
    
                  // загружаем конфиг подключения (сама реализация конфига может быть любой, сыть не меняется)
                  $config = nyaaConfig::get('database.' . $name);
                  if (is_null($config))
                  {
                       // если в конфиге не обнаружены параметры подключения данной бд, то генерируем исключение
                       throw new nyaaExceptionDatabaseNotConfigure($name);
                  }
                  // загружаем драйвер бд
                  self::$_instances[$name] = self::_loadDriver($name, $config);
             }
             return self::$_instance[$name];
        }
    
        // это статичный класс, запрещаем интснцирование
        final private function __construct()
        {}
        // … дальше реализация метода загрузки драйвера бд
    }
    
    // в итоге можно будет сделать так
    $db1 = nyaaDatabase::getInstance('dle');
    $db2 = nyaaDatabase::getInstance('dle');
    unset($db1);
    $db2->query($sql); // тут никакой ошибки не возникнет, так как линк на объект не единственный и дектруктор при ансете не вызовется
    
    Что такое nyaaDatabaseDriver? - Подумай, вдруг тебе понадобится реализовать класс работы не с MySQL а постгресс например, тебе придётся либо писать новую библиотеку работы с бд, либо переписывать старую, называть её по другому (если опять же нужно работать одновременно с разными бд) Возможно у этих библиотек ещё будут разные интерфейсы работы, короче минусов куча
    Поэтому лучше использовать драйвер, примерно как у меня выше в коде (nyaaDatabaseDriver):
    abstract class nyaaDatabaseDriver
    {
        protected $_config;
        protected $_dbHandle = NULL;
        protected $_lastQuery = '';
        protected $_lastErrorMessage = '';
    
        abstract public function __construct($config);
        abstract public function __destruct();
        abstract public function connect();
        abstract public function query();
        abstract public function getAffectedRows();
        abstract public function getInsertId();
        // и т.д.
    }
    Потом просто создаёшь драйвер и реализуешь все методы драйвера для примера:
    class nyaaDatabaseDriverMysql extends nyaaDatabaseDriver
    {
        public function __construct($config)
        {
             $this->_config = $config;
        }
    
        public function __destruct()
        {
             if (!is_null($this->_dbHandle))
             {
                  mysql_close($this->_dbHandle);
             }
        }
        // etc.
    }

    Почему именно класс nyaaDatabaseDriver, а не интерфейс: стандартные операции можно реализовать прямо в базовом классе драйвера, вот сейчас сразу видно - конструктор только копирует конфиг и все, деструктор рвет соединение с бд, можно сделать так:
    abstract class nyaaDatabaseDriver
    {
        protected $_config;
        protected $_dbHandle = NULL;
        protected $_lastQuery = '';
        protected $_lastErrorMessage = '';
    
        public function __construct($config)
        {
             $this->_config = $config;
        }
        public function __destruct()
        {
             $this->_disconnect();
        }
        abstract public function connect();
        abstract protected function _disconnect();
        // и т.д.
    }
    
    class nyaaDatabaseDriverMysql extends nyaaDatabaseDriver
    {
        // реализаия конструктора и деструктора уже ненужна
        protected function _disconnect()
        {
             if (!is_null($this->_dbHandle))
             {
                  mysql_close($this->_dbHandle);
             }
        }
        // и т.д.
    }
    
    Почему нет коннекта в конструкторе драйвера? Потому что лучше в query в начале проверять есть ли соединение, и если нет, то делать коннект, так как в дальнейшем возможно сделать кеширование результатов, и коннект вообще не понадобиться, тоесть бд вроде и будет инстанцирована, но соединение не будет сделано, сэкономим пару милисекунд =)

    Потом, реализовывать метод fetch прямо в драйвере крайне непредусмотрительно, а если понадобится в процессе работы с одной выборкой сделать ещё один запрос, косяк:
    $db = new DB('dle');
    if ($db->query($sql))
    {
        while ($db->fetch('row'))
        {
             $sql = 'UPDATE чтонибуть';
             $db->query($sql);
             // и тут наступает писец =)
        }
    }
    // плюс тебе самому нужно вызывать унылую функцию mysql_free_result
    
    Поэтому лучше реализовать ещё один класс - nyaaDatabaseDriverResult или что-то типо того, опять же абстрактный базовый класс, и наследуемые классы для каждого типа подключения
    class nyaaDatabaseDriverMysqlResult extends nyaaDatabaseDriverResult
    {
         public function __construct($result)
         {
              $this->_result = $result;
              $this->_rowNumber = 0;
              $this->_rowsCount = mysql_num_rows($result);
         }
    
         public function __destruct()
         {
               if (is_object($this->_result))
               {
                    mysql_free_result($this->_result);
               }
         }
    
         public function next()
         {
              $this->_rowNumber += 1;
              return mysql_fetch_row($this->_result);
         }
         // и тд
    }
    
    И пусть у тебя метод query бд возвращает нужный nyaaDatabaseDriverResult либо true|false для запросв типа инсерта/апдейта и т.п.
    чтото задолбался писать…

    а ещё, самое главное =) накогда так не делай:
        public function __construct()
        {
            try {
                $this->_linkIdentifier = @mysql_connect($this->_host . ':' . $this->_port, $this->_user, $this->_pswd);
                if (!$this->_linkIdentifier){
                    throw new Exception('Can\'t connect to host: ' . $this->_host);
                }
                if (!mysql_select_db($this->_database, $this->_linkIdentifier)) {
                    throw new Exception('Can\'t use database: ' . $this->_database);
                }
            } catch (Exception $e) {
                echo '<b>Caught exception:</b> ' . $e->getMessage();
            }
        }
    Исключение отлавливать нужно снаружи, а если реализовать так как тут, то ты просто никогда не узнаешь создано ли было соединение, в итоге трудноуловимые ошибки.
    Work, buy, consume, die
  • Nyaah

    Сообщения: 574 Репутация: N Группа: Джедаи

    Spritz Фев. 11, 2010, 8:48 д.п., спустя 22 часа 56 минут 8 секунд

    блин, как же так, почему нельзя редактировать свои сообщения, накосячил с тэгами :/
    Work, buy, consume, die
  • adw0rd

    Сообщения: 22959 Репутация: N Группа: в ухо

    Spritz Фев. 11, 2010, 9:28 д.п., спустя 39 минут 45 секунд

    Naaayh, SpartakuS, теперь вы можете редактировать мессаги свои
    https://smappi.org/ - платформа по созданию API на все случаи жизни
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz Фев. 11, 2010, 10:56 д.п., спустя 1 час 27 минут 57 секунд

    adw0rd, Спасибо :)
    Naaayh, Сейчас почитаю. Может даже постараюсь оспорить что =) Спасибо. Ты крут)
  • VaseninM

    Сообщения: 2416 Репутация: N Группа: Адекваты

    Spritz Фев. 11, 2010, 11:35 д.п., спустя 38 минут 50 секунд

    Naaayh, в общем не много пояснений и моего мнения.
    1. удобство (прежде всего для себя самого) - ну если учитывать пояснение в скобках, то мне то вроде удобно. Пока удобно.
    2. лёгкая расширяемость -Старался делать все для нее.
    3. возможность быстро дёрнуть код и использовать в другом проекте - тут согласен. Не получится.
    4. отсутствие повторяющегося кода
    Но по каждому из пунктов в любом случае есть над чем поработать.
    Далее беглое утреннее чтение :)

    будем плясать с самого начала, нет методов для получения кол-ва затронутых запросом строк, последнего автоинкримент ключа, дисконнекта плюс сама реализация порочна, так как ты не чистишь за собой память (нет ни одного mysql_close/mysql_free_result)

    Я написал, что в данном проекте мне не нужен даже фетч ибо будут одни инсерты => Зачем мне нужен последний ключ, количество строк….
    Дисконнект есть.
    Про освобождение памяти - влияние отсутствия работы с высоко нагруженными проектами. Не чистил никогда.
    В следующем коде твои комменты //, мои #
     // Уничтожаем объект в духе ООП :)
        // сам метод неправильно назван? должен быть __destruct()
        #Правильно. Этот метод нужен для того чтобы уничтожать объект не так unset($db), а так $db->destroy()
        public function destroy()
        {
            // неверно, нужно mysql_close($this->_dbHandle)
            // так как unset($this) сборщик мусора сам вызовет после того
            // как у тебя не останется ни одного линка на объект
            # Нет. После вызова метода он сработает как  unset($db) в коде, этим вызовет деструктор, который в свою очередь вызовет закрытие соединения с базой.
            unset($this);
        }

    А тут деструктор убъет только то подключение, что нужно ибо использую индификаор соединения.
    $db1 = new DB('dle');
    $db2 = new DB('dle');
    unset($db1);
    $db2->query($sql);

    Далее нужно читать более подробно, а там заказчик начинает пинать… Вникну и отвечу вечерком =)
    Еще раз спасибо.
  • Trej Gun

    Сообщения: 5305 Репутация: N Группа: в ухо

    Spritz Фев. 11, 2010, 12:39 п.п., спустя 1 час 4 минуты 7 секунд

    Naaayh, стока много букав просто не могут быть неубедительным аргументом. но это шутки молодец что не заломался это писать.

    ЗЫ это навернео в статью стоит оформить?
  • NRG

    Сообщения: 4761 Репутация: N Группа: в ухо

    Spritz Фев. 11, 2010, 12:41 п.п., спустя 2 минуты 35 секунд

    ЗЫ это навернео в статью стоит оформить?

    непомешало бы =)
    "ООП для маленьких (на примере мускл адаптера)"
    Спустя 50 сек.
    Naaayh, оформляй все это красивенько в статейку =)

Пожалуйста, авторизуйтесь, чтобы написать комментарий!