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

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

  • Givi

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

    Spritz 10 февраля 2010 г. 21:32, спустя 1 час 45 минут 58 секунд


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

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

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

    Spritz 10 февраля 2010 г. 21:39, спустя 7 минут 5 секунд

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

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

    Spritz 10 февраля 2010 г. 21:53, спустя 13 минут 43 секунды

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

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

    Spritz 10 февраля 2010 г. 22:06, спустя 12 минут 39 секунд

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

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

    Spritz 10 февраля 2010 г. 22:19, спустя 13 минут 39 секунд

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

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

    Spritz 10 февраля 2010 г. 22:51, спустя 31 минуту 29 секунд


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

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

    Spritz 10 февраля 2010 г. 22:53, спустя 2 минуты 15 секунд

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

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

    Spritz 10 февраля 2010 г. 23: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, оформляй все это красивенько в статейку =)

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