Патерн "Adaptor" из Книги. ООП + MySql

Духовность™

Продвинутый новичок
Патерн "Adaptor" из Книги. ООП + MySql

Привет.
Переписываю свой старый класс для работы с Mysql, в книге "Профессиональное программирование на PHP" есть раздел "типовые проекты", а в нем представлен паттерн"Adaptor", который служит для работы с СУБД. В снего сейчас и буру пример.

Вот код:

PHP:
class DB_MySQl
{
    // подключение к СУБД, etc 

    public function execute($sql_query)
    {
        // делаем mysql_query
        
        if (is_resourse($ret))  // $ret - результат работы mysql_query()
        {
            $stmt = new DB_MysqlStatement(....);
            $stmt->result = $ret;
            return $stmt;
        }
        else return $ret;
    }
}

class DB_MysqlStatement
{
    // ....

    public function fetch_assoc()
    {
        return mysql_fetch_assoc($this->result);
    }

    // и так далее - реализуем различные методы выборки
}
Мне вот одно не понятно - зачем было выносить в отдельный класс работу по выборке?

Если бы выборка была бы в основном классе, то можно было бы написать

PHP:
$database = new DB_MySQl();
$res = $database->query('SELECT 1');

while($row = mysql_fetch_assoc($res))
{
    print_r($row);
}
а теперь приходится класс DB_MysqlStatement дополнять методом getResult:

PHP:
$database = new DB_MySQl();
$res = $database->query('SELECT 1');

while($row = mysql_fetch_assoc($res->getResult()))
{
    print_r($row);
}
 

whirlwind

TDD infected, paranoid
что мешает сделать так ?
PHP:
$database = new DB_MySQl(); 
$res = $database->query('SELECT 1'); 

while($row = $res->fetch_assoc()) 
{ 
    print_r($row); 
}
 

Духовность™

Продвинутый новичок
Да ничего не мешает. Только что мешало реализовать подобное в главном классе?
 

Найч

Алгоритмик :-)
выборку и работу с ней вынесли потому, что это дает возможность последовательно выполнить несколько запросов из одного класса, а после обрабатывать их
 

whirlwind

TDD infected, paranoid
Автор оригинала: triumvirat
Да ничего не мешает. Только что мешало реализовать подобное в главном классе?
Ты можешь манипулировать набором записей, не задумываясь откуда они взялись. ООП - это не набор функций засунутых в класс. ООП позволяет концентрировать в контексте микрозадач только нужные сущности и методы их обработки. В контексте задач обработки набора однотипных записей не важно откуда и каким способом они были извлечены. Завтра ты изменишь способ извлечения/хранения этого набора записей, но тот код который использует Statement менять не придется.
 

Wicked

Новичок
Только что мешало реализовать подобное в главном классе?
как думаешь, почему mysql extension использует один ресурс для mysql линка, и совсем другой ресурс для результата mysql_query ? И в mysqli и pdo...

$database = new DB_MySQl();
$res = $database->query('SELECT 1');

while($row = mysql_fetch_assoc($res->getResult()))
{
print_r($row);
}
За что боролись, на то и напоролись :) Адаптеры для того и нужны, чтобы подогнать какой-нибудь к некоторому интерфейсу. И часто это делается для взаимозаменяемости. Ты бы в том варианте, который тебе больше нравится, смог бы заменить mysql на mysqli или pdo? :)
 

Духовность™

Продвинутый новичок
Хорошо, я понял, спасибо.

А теперь внимание - завязка.

Все знакомы с SQL_CALC_FOUND_ROWS/SELECT FOUND_ROWS()?

Если использовать адаптер, то у меня нет возможности получить FOUND_ROWS. Ибо при каждом запросе создается новый объект результата.

Как с этим быть - я не представляю.
 

zerkms

TDD infected
Команда форума
triumvirat
и что? в чём проблема использования?
 

Духовность™

Продвинутый новичок
zerkms
В том, что все SQL-запросы идут через метод базового класса execute, который и создаёт каждый раз, при каждом новом своём вызове, новый объект результата!
пример:
PHP:
$res = $database->query('SELECT SQL_CALC_FOUND_ROWS ... LIMIT 1, 3');

pr($res);

$rez = $database->query('SELECT FOUND_ROWS()');

pr($rez);
Это даст
Код:
DB_MysqlStatement Object
(
    ...
    [result:private] => Resource id #42
)

DB_MysqlStatement Object
(
    ...
    [result:private] => Resource id #43
)
 

zerkms

TDD infected
Команда форума
triumvirat
ну и что такого то???? ну и выполняй запросы из разных объектов
 

zerkms

TDD infected
Команда форума
ps: я конечно дико извиняюсь, но паттерн Adapter используется в качестве "переходника" (обёртки) для класса, чтобы использующие его объекты работали с тем интерфейсом, с которым они умеют работать
(обеспечивает совместную работу классов с несовместимыми интерфейсами (с) гоф)

в указанном в первом посте коде я этого не вижу
 

zerkms

TDD infected
Команда форума
triumvirat
потому что по определению паттерн адаптер должен делать работу по преобразованию одного интерфейса - в другой
просто переходник
у тебя в коде этого нет

пример:
был класс А:
class a
{
function b($a, $b)
{
...
}
function c($q)
{
...
}
}

потом в версии 2 этого класса произошли некоторые изменения, и он стал выглядеть так:
class a
{
function b($z)
{
// тут убрали 1 аргумент
...
}
function d($q)
{
// а тут метод переименовали
...
}
}

а у нас в наличии есть некоторый объём кода который с v.1 класса А работает хорошо, а с v.2 естественно работать не будет
вот тут то и выручает адаптер:

class adapter
{
private $a;
function __construct(a $a)
{
$this->a = $a;
}

function b($a, $b)
{
// некоторые действия над аргументами $a и $b, которые их приводят к требуемому аргументу $z
return $this->a->b($z);
}
function c($q)
{
return $this->a->d($q);
}

}

и всё - старый код сможет работать с новым классом А через адаптер

вот его сущность ;) этого даже приблизительно в коде - нет ;)
 

Духовность™

Продвинутый новичок
Понятно. Получается, адаптер заранее не пишут, а используют как некую заглушку в момент возникновения несостыковок в коде?

Тогда как охарактеризовать код в книжке?

и.. как тогда в твоём примере работает с адаптером?

PHP:
$oldA = new A();

$a = new adapter($oldA);

$a->b($a, $b); // т.е. работаем с $a->b($z) v.2
Так? :)
 

zerkms

TDD infected
Команда форума
triumvirat
да, с кодом работаем именно так
только вот нагляднее:
$a_v2 = new a();
$a_v1 = new adapter($a_v2);

по поводу книжки - приведи точное название и авторов

Понятно. Получается, адаптер заранее не пишут, а используют как некую заглушку в момент возникновения несостыковок в коде?
да, просто как "переходник"
 

whirlwind

TDD infected, paranoid
Автор оригинала: zerkms
ps: я конечно дико извиняюсь, но паттерн Adapter используется в качестве "переходника" (обёртки) для класса, чтобы использующие его объекты работали с тем интерфейсом, с которым они умеют работать
(обеспечивает совместную работу классов с несовместимыми интерфейсами (с) гоф)

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

PS. Разрабатывайте, опираясь на интерфейсы, а не на классы. Повторять перед сном по 10 раз всем желающим эффективно использовать ООП :)
 
Сверху