За последние 24 часа нас посетили 22375 программистов и 1637 роботов. Сейчас ищут 935 программистов ...

Методы объекта базы данных

Тема в разделе "Вопросы от блондинок", создана пользователем Kreker, 1 окт 2009.

  1. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    :blush:

    Представим класс:
    PHP:
    1.  
    2. <?php
    3. class Database {
    4. ...
    5.     public function query($query, $arguments) {
    6.         ....
    7.     }
    8.  
    9.     public function getArray($query, $arguments) {
    10.         $result = $this->query($query, $arguments);
    11.         while...
    12.         ....
    13.     }
    14. }
    Таким образом - сколько вариантов возвращения данных (методов для этого), столько раз нужно прописывать методы с аргументами (чтобы обращаться $db->getArray('SELECT ?s..', 'row'), в теле методов обращение к методу query.
    Получается много копипастного кода.

    В начале года я написал класс, где избежал дублирования:
    PHP:
    1.  
    2. <?php
    3. class Database {
    4. ...
    5.     public function query($method, $query, $arguments) {
    6.         ....
    7.         $this->resourse = mysql_query($sql);
    8.         $this->$method();
    9.     }
    10.  
    11.     public function getArray() {
    12.         while ($this->resourse)...
    13.         ....
    14.     }
    15. }
    Таким образом, я всегда обращаюсь к одному методу, а в качестве аргумента указываю метод, который будет возвращать необходимую структуру.

    Но сейчас мне такой вариант не нравится - нужно указывать на один аргумент больше. Хочется, чтобы вместо query указывалось имя необходимого метода (пример - $db->getArray).

    Как вариант - использовать перегрузку методов. Но здесь у меня сомнения:
    1) Верно ли это идеологически,
    2) верно ли это с точки зрения быстродействия,
    3) какой вариант реализации выбрать?

    По поводу реализации:
    1. Вариант:
    PHP:
    1.  
    2. <?php
    3. class Database {
    4. private $methods = Array ("getArray" => false);
    5. private $m_data = Array ("getArray" => "gA");
    6. ...
    7.     public function query($query, $arguments) {
    8.         ....
    9.         $this->resourse = mysql_query($sql);
    10.         $this->$method();
    11.     }
    12.    
    13.     function __call($method, $arguments) {
    14.    
    15.         if (isset($this->methods[$method])) {
    16.             $this->query($arguments[0], $arguments[1]);
    17.             return $this->m_data[$method]();
    18.         }
    19.         return false;
    20.    
    21.     }
    22.    
    23.     public function gA() {
    24.         while ($this->resourse)...
    25.         ....
    26.     }
    27. }
    28.  
    2. Вариант с помощью наследования:
    PHP:
    1.  
    2. <?php
    3. class Database extends mainDB{
    4. private $methods = Array ("getArray" => false);
    5. ...
    6.     public function query($query, $arguments) {
    7.         ....
    8.         $this->resourse = mysql_query($sql);
    9.         $this->$method();
    10.     }
    11.    
    12.     function __call($method, $arguments) {
    13.    
    14.         if (isset($this->methods[$method])) {
    15.             $this->query($arguments[0], $arguments[1]);
    16.             return parent::$method();
    17.         }
    18.         return false;
    19.    
    20.     }
    21. class mainDB {
    22.     public function getArray() {
    23.         while ($this->resourse)...
    24.         ....
    25.     }
    26. }
    27.  
    Склоняюсь к 1 варианту. Что скажете?
     
  2. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    вот те делать нечего =))
    хватит писать велосипеды, займись полезным делом, хотя бы С++ поизучай вместе с Mr.M.I.T., чем ваять over-ООП велосипедные классы [​IMG]
     
  3. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Сейчас для С++ нет времени. Нужно сделать лучше то, что есть. Да и на ООП нормально программить научитсяю
     
  4. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Какашка.
    Смысла в таком функционале 0.

    Ты всегда получаешь в запросе строки и столбцы.
    Поэтому можешь смело его парсить сразу в ArrayAssoc.
    А объект результата уже должен подерживать методы своей сериализации в разные виды.

    PHP:
    1.  
    2. <?php
    3. $db->query($queryString, $queryArguments);
    4. $result = $db->getLastResult();
    5.  
    6. $result->toArray();
    7. $result->toArrayAssoc();
    8. $result->toString();
    9. $result->toJSON();
    10. $result->toXML();
    11. ?>
    Все. Твоя задача вернуть объект класса QueryResult, который является наследником Result и имплементирует абстрактные (или не очень) методы toArray() и т.д.
    Можно еще добавить интерфейс ArrayAccess для доступа к данным напрямую, тогда убрать первые два конвертера из моего примера.
     
  5. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Можешь кстати, наследоваться от
    http://www.php.net/manual/en/class.splobjectstorage.php

    где-то я читал что он на 20% быстрее, чем работа с массивом объектов.
    хотя надо бы проверить, но лень.
     
  6. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Много строк...
     
  7. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Много строк чего? :)

    можешь писать так
    PHP:
    1. <?php
    2. $result = $db->query($queryString, $queryArguments)->getLastResult()->toArray();
    3. ?>
    Ты надеешься избежать лишних нажатий клавиш при наборе? :)
    Так я тебе скажу, тут их минимум втрое меньше, чем символов в строке, если ты конечно пользуешься нормальной IDE

    Зато когда мне понадобится добавить метод toJSON() я буду менять 1 класс Result в 1ном месте.
    А ты будешь менять код в 2х-3х местах, да еще, возможно, и в разных классах.

    Опять же, контроль параметров у тебя нулевой.

    PHP:
    1. <?php
    2. $db = new Database();
    3. $db->getArray("Ждал 2 аргумента? Получи фашист гранату");
    4. ?>
     
  8. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    чё за проблемы?
    1. Сделать много методов, (queryArray,queryResource ...)
    2. Возвращай в query $this потом $db->query()->getArray()

    советую 1й
    Simpliest
    по кой чёрт разбивать реализацию на такое кол-во объектов?
     
  9. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    На тот черт зачем вообще ООП :)

    1.Потому что первый способ ТС - это идиотизм.
    Вызов методов через _call() при их фактическом объявлении.
    Второй способ ничем не лучше.

    2. Хотим мы результаты БД сконвертировать в JSON и пишем метод getJSON? Да?
    А если мы хотим данные SOAP сконвертировать в JSON, ему тоже пишем getJSON?
    А если мы еще откуда-то получим данные, то мы еще один getJSON пишем?

    Множественного наследования в PHP нет, да и само оно (множественное наследование) не слишком удобно для многих вещей. Интерфейсы не поддерживают конкретную реализацию по определению.

    В моем примере выше мы отделили данные от способа их получения путем наследования от общего объекта Result (SplObjectStorage).

    Можно это было сделать через Dependency injection - создав класс(группу классов) конвертеров и подключая нужные к нашей модели
    PHP:
    1. <?php
    2. class DB {
    3.     public function __construct() {
    4.         foreach(func_get_args() as $arg) {
    5.             if ($arg instanceof Converter) {
    6.                 $this->converters[] = $arg;
    7.             } elseif ($arg instanceof Connection) {
    8.                 $this->connection = $arg;
    9.             }
    10.         }
    11.     }
    12. }
    13.  
    14. class Connection {
    15.     private $name = 'Default';
    16.     public function __construct($name) {
    17.         $this->name = $name;
    18.     }
    19.  
    20. }
    21. class Converter {
    22.     private $name = 'Default';
    23.     public function __construct($name) {
    24.         $this->name = $name;
    25.     }
    26.  
    27. }
    28.  
    29.  
    30. $db = new DB (new Connection('MySQL'), new Converter('JSON'), new Converter('XML'), new Converter('String'));
    31.  
    32. var_dump($db);
    33. ?>
     
  10. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Да, похоже на истину, спасибо.

    оО Похоже на оральный секс с фаллоимитатором?
     
  11. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Хм, никогда не пробовал :) есть опыт? :)
     
  12. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    В порнухе видел. Выглядело примерно так же ;)
     
  13. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    На самом деле пример был утрирован для демонстрации особенностей DI.

    Тебе достаточно было передать не десяток конвертеров, а один транспортный объект.
    Который уже в свою очередь может быть нашпигован конвертарами по DI или просто унаследован от абстрактного класса.
    При этом мы сохраняем и возможости typehinting в IDE и lowcoupling для кода.

    Вообще обычные массивы в php весьма удобны для передачи данных любого типа, но есть риск нарушения целостности структуры, проконтролировать которую у массива сложнее чем у класса

    P.S. Интересен Phemto, но все никак не было времени разобраться как он собирает классы. В частности автодополнение в IDE весьма проблематично, если он не компилирует в нативный PHP-код, а собирает их в runtime.
    А это только усложнит разработку :(
     
  14. Frozen

    Frozen Активный пользователь

    С нами с:
    20 окт 2008
    Сообщения:
    540
    Симпатии:
    0
    Адрес:
    Москва
    PHP:
    1.  
    2. <?php
    3. $conf = new Zend_Config_Ini(APPLICATION_PATH.'/configs/application.ini', APPLICATION_ENV);
    4. $db = Zend_Db::factory($conf->db->adapter, $conf->db->toArray());
    5. echo Zend_Json::encode($db->fetchAll('SELECT * from articles where id=?', $id));
     
  15. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    жошь, название топика прочти =)
     
  16. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    В том и вопрос. Если решать задачу "влоб", то получим десятки несвязанных классов со своими методами getJSON().

    Вдруг, внезапно, формат JSON забанили :)
    Переписывать все классы? Или может лучше 1?
     
  17. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    класс БД не должен решать эту задачу, в том формате в котором его попросили

    и что значит забанили "JSON" банить функция приложения а не фреймвока
     
  18. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Вот видишь :)
    А теперь почитай, что рекомендовали сделать :)

    :) Во всех маршрутизаторах всемирной сети данные в формате JSON режутся и фильтруются аппаратно :)
     
  19. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    боже, да я говорил про то что ты всё усложняешь
    вернуть объект, который наследник бла бла, потом бла бла будет там чёто с ним делать
    жопа всё это
     
  20. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Ты мне льстишь :) Я еще не боже :)

    А ООП оно вообще сложная штука.
     
  21. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    да ты омойгад просто =)

    ООП ради ООП != ЧеловекоПриятномуИэффективноРаботающему ООП а равно жопе
     
  22. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    o_0
    линк в студию!
     
  23. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    мне не верят? :)

    Легко
     
  24. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Simpliest
    "Вдруг" не заметил.
    Вообще, можно сделать класс с JSON и просто от него наследовать.
     
  25. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    У тебя следующие проблемы
    1. Дерево классов может иметь несколько предков и не пересекаться :)
    Соответствено реализаций классов с JSON должно быть много - что неудобно.
    2. Вытекает из п.1 - сделать общего предка у всех классов (какой нибудь - CommonObject). Можно, но тоже несколько неудобно. Мы будем тащить методы даже туда, где они не нужны...

    Поэтому на мой взгляд есть два разумных варианта.
    1. Классы утилит как показал Frozen (он вообще 1 на все дерево)
    2. Транспортный класс данных, датамапперы. Которые имеют общего предка и могут поддерживать конвертацию своего представления в JSON/XML/String etc. (таких классов будет 1-2)