Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > global в методах класса


Автор: bars80080 24.9.2009, 15:13
новый мутный вопрос...

вот есть к примеру у меня класс $db = new db(); для работы с базой данных, подключается всегда, так как и нужен всегда
далее, в модуле имеется другой класс, который совершает запросы к БД, естественно он использует уже налаженное соединение и функционалом класса db.
в методе пишу:

Код

function metod() {
    global $db;
    ....
}


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


вот скажите, как вы делаете? или мне опять не беспокоиться?

Автор: Simpliest 24.9.2009, 15:27
Синглтон для работы с БД. Коннект - статик свойство.

Все кому нужно работать с БД, работают с этим синглтоном

Автор: bars80080 24.9.2009, 15:45
Цитата(Simpliest @  24.9.2009,  15:27 Найти цитируемый пост)
Синглтон для работы с БД. Коннект - статик свойство.

а мне нужно более одного экземпляра. как раз касаемо работы с БД

Автор: youri 24.9.2009, 15:56
Цитата(Simpliest @  24.9.2009,  15:27 Найти цитируемый пост)
Все кому нужно работать с БД, работают с этим синглтоном

не все http://wiki.agiledev.ru/doku.php?id=ooad:manage_dependencies_in_php_code

Цитата(bars80080 @  24.9.2009,  15:13 Найти цитируемый пост)
получается, что метод стороннего класса зависит от имени переменной, что мне не очень нравится. как-то у меня сформировалось мнение, что функции и классы должны быть вещью в себе. то есть передаёшь им какие-то параметры, они их и используют. от изменения в другом месте кода должны быть независимы.

независимость это, конечно, хорошо. Но я считаю, что чтобы усложнять должны быть причины. Пока что похоже причина одна. Если измениться название переменной, то надо будет поменять ряд мест в коде. Допустим будет Синглтон. С тем же успехом можно предположить, что название класса может измениться. В статье, кстати, сказано, что привязка к именам классов хуже, чем к именам переменных

Цитата(bars80080 @  24.9.2009,  15:45 Найти цитируемый пост)
а мне нужно более одного экземпляра. как раз касаемо работы с БД

а зачем?

Автор: sTa1kEr 24.9.2009, 15:56
Тогда логично было бы использовать какой-либо реестр коннектов к БД. Добавлять получать их через статические методы класса.

Автор: NewDima 24.9.2009, 16:05
bars80080, более одного коннекта одновременно тебе нужно? Зачем такая роскошь?

Автор: sTa1kEr 24.9.2009, 16:08
Цитата(NewDima @  24.9.2009,  17:05 Найти цитируемый пост)
bars80080, более одного коннекта одновременно тебе нужно? Зачем такая роскошь? 

Я полагаю bars80080 имел ввиду несколько коннектов к разным серверам.

Автор: NewDima 24.9.2009, 16:14
В таком случае нахождение в коде нескольких переменных для обертки соединений, которые отвечают за коннект (каждая за свой) вижу бессмысленным методом.
ИМХО, должен быть какой-то объект, управляющий коннектами, а ну да, об это и сказал sTa1kEr

Автор: bars80080 24.9.2009, 16:15
Цитата(sTa1kEr @  24.9.2009,  16:08 Найти цитируемый пост)
имел ввиду несколько коннектов к разным серверам. 

нет, до разных серверов ещё не развился

Цитата(youri @  24.9.2009,  15:56 Найти цитируемый пост)
а зачем? 

ну, есть у меня интерфейс работы с БД. одно подключение со своей базой использует сам сайт, другое интерфейс. чтобы не заморачиваться на переходе и выставлении установок туда-сюда для интерфейса мы определяем своё подключение, и там уже выставляем нужную ему БД



Цитата(sTa1kEr @  24.9.2009,  15:56 Найти цитируемый пост)
Тогда логично было бы использовать какой-либо реестр коннектов к БД. Добавлять получать их через статические методы класса. 

вообще, задача общая. помимо db есть ещё два класса используемых постоянно. правда, они используются одиножды. есть ещё один класс, который теоритечески может использоваться несколько раз, хотя я пока не реализовал эту задачу, но уже сейчас могу придумать обоснование нужды.
и есть частные классы, к примеру, по работе с файлами, по работе с БД, по работе со структурой сайта, дампер, и прочие. они используют вышеупомянутые классы, и везде где нужно приходится писать в методах global $db, $main;

уже само по себе неудобно

Автор: NewDima 24.9.2009, 16:29
Цитата(bars80080 @ 24.9.2009,  23:15)
ну, есть у меня интерфейс работы с БД. одно подключение со своей базой использует сам сайт, другое интерфейс. чтобы не заморачиваться на переходе и выставлении установок туда-сюда для интерфейса мы определяем своё подключение, и там уже выставляем нужную ему БД

Это точно оправдано? Что-то кажется, что никак. У тебя для одного сайта использется более одной базы данных?

Автор: sTa1kEr 24.9.2009, 16:30
Цитата(bars80080 @  24.9.2009,  17:15 Найти цитируемый пост)
ну, есть у меня интерфейс работы с БД. одно подключение со своей базой использует сам сайт, другое интерфейс. чтобы не заморачиваться на переходе и выставлении установок туда-сюда для интерфейса мы определяем своё подключение, и там уже выставляем нужную ему БД

А если будет 10 баз, то будете делать 10 коннектов? smile  Почему просто в запросах не использовать полные имена таблиц? Т.е. Db1.Table1, Db2.Table2, etc.

Цитата(bars80080 @  24.9.2009,  17:15 Найти цитируемый пост)
вообще, задача общая. помимо db есть ещё два класса используемых постоянно. правда, они используются одиножды. есть ещё один класс, который теоритечески может использоваться несколько раз, хотя я пока не реализовал эту задачу, но уже сейчас могу придумать обоснование нужды.
и есть частные классы, к примеру, по работе с файлами, по работе с БД, по работе со структурой сайта, дампер, и прочие. они используют вышеупомянутые классы, и везде где нужно приходится писать в методах global $db, $main;

Самый простой способ использовать некий контейнер, реестр этих объектов, в качестве примера реализации можно привести ZF http://framework.zend.com/manual/en/zend.registry.html Ну и, как уже сказал, Simpliest можно использовать шаблон Singleton.

Автор: bars80080 24.9.2009, 16:31
Цитата(NewDima @  24.9.2009,  16:29 Найти цитируемый пост)
У тебя для одного сайта использется более одной базы данных?

у меня для одного сайта используется одна база. но хостинг сразу на несколько сайтов и на несколько баз. из интерфейса одного сайта я имею возможность работать со всеми базами. для чего собственно всё и делалось

Добавлено через 1 минуту и 5 секунд
Цитата(sTa1kEr @  24.9.2009,  16:30 Найти цитируемый пост)
А если будет 10 баз, то будете делать 10 коннектов?

нет, одна для сайта и одна для интерфейса работы


Цитата(sTa1kEr @  24.9.2009,  16:30 Найти цитируемый пост)
Ну и, как уже сказал, Simpliest можно использовать шаблон Singleton

мне нужно несколько экземпляров

Автор: icewind 24.9.2009, 16:32
Я в таких случаях использую фабрику. Мне удобнее всего писать так
Код

$db =& Factory::getDB('first_connection');
$db2 =& Factory::getDB('second_connection');

если уж принципиально использование нескольких коннектов

Автор: NewDima 24.9.2009, 16:35
icewind, и каждый раз будет создаваться новый объект с новым внутренним состоянием...

Автор: icewind 24.9.2009, 16:37
NewDima, и почему это?

Автор: Simpliest 24.9.2009, 16:38
Цитата(bars80080 @  24.9.2009,  15:45 Найти цитируемый пост)
а мне нужно более одного экземпляра. как раз касаемо работы с БД 

Все равно делай один общий пусть даже с пулом БД или коннектов.

Хотя если общего кроме хостинга ничего нет smile тогда - да. Каждому приложению своя прослойка.

Добавлено через 46 секунд
Цитата(bars80080 @  24.9.2009,  16:31 Найти цитируемый пост)
мне нужно несколько экземпляров 

Тебе уже указали. Registry заменяет собой пачку синглтонов.

Автор: NewDima 24.9.2009, 16:42
icewind, извини, не вник, оплошал =)
Посчитал, что ты у фабрики запрашиваешь каждый раз новый объект

Автор: Simpliest 24.9.2009, 16:44
Цитата(youri @  24.9.2009,  15:56 Найти цитируемый пост)
не все 

Конкретно для БД - все вменяемые. Такое уточнение подойдет?

Чем меньше точек входа для базовых операций - тем лучше.

Цитата(youri @  24.9.2009,  15:56 Найти цитируемый пост)
В статье, кстати, сказано, что привязка к именам классов хуже, чем к именам переменных

Глупость кстати. Никаких разумных доводов этому нет.

И статью следует читать аккуратно. Писали ее не гуру. Но даже гуру ошибаются smile

Автор: icewind 24.9.2009, 16:45
NewDima, да не за что извиняться. С кем не бывает  smile 

Автор: bars80080 24.9.2009, 16:46
Цитата(Simpliest @  24.9.2009,  16:38 Найти цитируемый пост)
Registry заменяет собой пачку синглтонов. 

разобраться б что там написано

Автор: icewind 24.9.2009, 16:51
Один объект, который представляет собой реестр, хранящий список инициализированных объектов, и обладает геттерами, возвращающими эти объекты (ссылки)

Автор: NewDima 24.9.2009, 16:51
bars80080, а в чем конкретно?
Как использовать зендовский реестр? так просто, по строковым ключам, которые в твоем случае могут быть для тебя в виде 'interface' и 'site'. Разве не удобно?

Автор: bars80080 24.9.2009, 16:51
Цитата(icewind @  24.9.2009,  16:51 Найти цитируемый пост)
реестр, хранящий список инициализированных объектов

объектов разных классов?

Автор: NewDima 24.9.2009, 16:52
да хоть чего вообще, это же альтернатива глобальному массиву

Автор: icewind 24.9.2009, 16:56
Реестр может хранить все что угодно, но для данного примера можно и классы для работы с базой. 
Код

$db = new PDO('mysql:host=localhost;dbname=demo', '[user]', '[password]');
$registry->set ('db', $db);

$db2 = new PDO('mysql:host=localhost;dbname=demo', '[user]', '[password]');
$registry->set ('db2', $db2);

потом
Код

$db = $registry->get('db2');


а лучше
Код

$db =& Registry::get('db2');


Хотя мне кажется обычная фабрика здесь подойдет отлично. Пример я приводил

Автор: bars80080 24.9.2009, 17:01
Цитата(NewDima @  24.9.2009,  16:52 Найти цитируемый пост)
да хоть чего вообще, это же альтернатива глобальному массиву 

наверное, самый важный момент, на него мне ещё не ответили

вот есть:

Код

function metod() {
    global $db;
    ....
}
в ряде методов некоего третьего класса. нужно ли отходить от этой схемы?

я лично испытываю раздражение от этих global (а я имею право испытывать раздражение), но я всё-таки вменяемый человек и готов мириться с тем что лучше

Автор: icewind 24.9.2009, 17:05
На мой взгляд да. Нужно отходить и использовать factory для получения коннекта к базе.
Код

function metod() {
    $db =& Factory::getDB('connection');
    ....
}

Автор: sTa1kEr 24.9.2009, 17:08
Цитата(bars80080 @  24.9.2009,  17:31 Найти цитируемый пост)
нет, одна для сайта и одна для интерфейса работы

Тогда я не совсем понимаю, что значит "для интерфейса работы". Но в любом случае, раз на сервере используются несколько баз, то вполне оправданно было бы использовать полные имена и отказаться от select_db.

Цитата(icewind @  24.9.2009,  17:56 Найти цитируемый пост)
Хотя мне кажется обычная фабрика здесь подойдет отлично. Пример я приводил 

Да, фабрика хорошо бы подошла если бы были коннекты к разным серверам. А так, конечно, от нее не очень много проку в фабрике одного объекта smile Хотя, с другой стороны универсальность и задел на будущее...

Автор: NewDima 24.9.2009, 17:10
или
Код

function metod() {
    $db = Zend_Registry::get('database interface');
    ....
}
function metod1() {
    $db = Zend_Registry::get('database site');
    ....
}

 smile 

Автор: sTa1kEr 24.9.2009, 17:12
Цитата(bars80080 @  24.9.2009,  18:01 Найти цитируемый пост)
наверное, самый важный момент, на него мне ещё не ответили

Имхо, да, любые переменные должны быть инкапсулированны настолько, насколько это возможно.

Добавлено через 1 минуту и 46 секунд
Цитата(NewDima @ 24.9.2009,  18:10)
или
Код

function metod() {
    $db = Zend_Registry::get('database interface');
    ....
}
function metod1() {
    $db = Zend_Registry::get('database site');
    ....
}

 smile

Я имел ввиду
Код

function metod() {
    $db = Zend_Registry::get('database');
}

А все запросы переписать так, что бы они не завесили от того site это или interface  smile 

Автор: NewDima 24.9.2009, 17:19
sTa1kEr, сначала нужно, чтобы bars80080 решил, что соединение должно быть одно. А потом многое отпадет smile 

Автор: youri 24.9.2009, 17:23
Цитата(bars80080 @  24.9.2009,  16:15 Найти цитируемый пост)
ну, есть у меня интерфейс работы с БД. одно подключение со своей базой использует сам сайт, другое интерфейс. чтобы не заморачиваться на переходе и выставлении установок туда-сюда для интерфейса мы определяем своё подключение, и там уже выставляем нужную ему БД

кстати, вот вторая причина: чтобы не писать постоянно global. Самое простое решение использовать функцию, которая возвращает нужный коннект (и создает, если нужно)
Код

db('connect_name')->query(...)


Цитата(bars80080 @  24.9.2009,  16:31 Найти цитируемый пост)
Ну и, как уже сказал, Simpliest можно использовать шаблон Singleton

мне нужно несколько экземпляров

Singleton допускает больше одного объекта: "Permits a variable number of instances. The pattern makes it easy to change your mind and allow more than one instance of the Singleton class. Moreover, you can use the same approach to control the number of instances that the application uses. Only the operation that grants access to the Singleton instance needs to change." (книжка банды четырех)

Цитата(Simpliest @  24.9.2009,  16:44 Найти цитируемый пост)
Конкретно для БД - все вменяемые. Такое уточнение подойдет?Чем меньше точек входа для базовых операций - тем лучше.

не подойдет. TDD-шники не любят Singleton

Цитата(Simpliest @  24.9.2009,  16:44 Найти цитируемый пост)
В статье, кстати, сказано, что привязка к именам классов хуже, чем к именам переменных

Глупость кстати. Никаких разумных доводов этому нет.

есть разумные доводы. Ты б статью почитал прежде чем говорить ;) : "Характер зависимости может быть Динамическим – когда мы легко можем подменить один объект другим, и клиент об этом не узнает, если интерфейсы все также поддерживаются." Динамическую зависимость можно подменить, в отличие от статической. Важно как минимум для TDD. А статья - хорошая

Цитата(sTa1kEr @  24.9.2009,  17:12 Найти цитируемый пост)
Имхо, да, любые переменные должны быть инкапсулированны настолько, насколько это возможно.

я бы сказал "в разумных пределах"

Автор: bars80080 24.9.2009, 17:36
Цитата(sTa1kEr @  24.9.2009,  17:08 Найти цитируемый пост)
то вполне оправданно было бы использовать полные имена и отказаться от select_db.

что сие значит?


Цитата(sTa1kEr @  24.9.2009,  17:08 Найти цитируемый пост)
Тогда я не совсем понимаю, что значит "для интерфейса работы"

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

Добавлено через 24 секунды
Цитата(NewDima @  24.9.2009,  17:19 Найти цитируемый пост)
что соединение должно быть одно

почему?

Автор: Simpliest 24.9.2009, 17:41
Цитата(youri @  24.9.2009,  17:23 Найти цитируемый пост)
не подойдет. TDD-шники не любят Singleton

Это личные тараканы вас неопытных TDD-шников. Я говорил про вменяемых программистов, которые исповедуют KISS & DRY.

Цитата(youri @  24.9.2009,  17:23 Найти цитируемый пост)
Ты б статью почитал прежде чем говорить 

Нет там разумных доводов, там есть искусственно созданные проблемы самому себе. 

Вы бы, прежде чем давать глупые советы, приняли за факт, что эту статью я читал больше года назад (а появилась в сети она еще раньше). И я уже цитировал ее же на этом форуме.

Одна эта фраза
"В тестах иногда нужно иметь возможность изменить поведение этих методов" начисто убивает.  
И такого там достаточно много. Статья написана с претензией, но не более того. Относится к ней следует достаточно критически, особенно некорепшим умам.

Добавлено через 8 минут и 36 секунд
Цитата(bars80080 @  24.9.2009,  17:36 Найти цитируемый пост)
дабы не мешать всё в кучу, для этих операций создаётся отдельный коннект

Брр, прошу прощения, но меня это запутало еще больше.

Что ты пытаешься не мешать в кучу?
Точнее, что от чего ты хочешь отделить?

Вот смотри, есть у нас некоторый слой абстракции работы с БД. 
  •  мы ему можем передать запрос
  • можем использовать какой-либо из реализованных примитивов

Допустим, нам нужно чтобы работа некоторых модулей с БД логировалась отдельно. Тогда нам нужно предусмотреть это в асбтракции.

Например -
Декларация выглядит примерно так

Код

public function query ($query, array $params, LogObject $log = 'default log') {};


Все, когда нам надо, мы передаем другой объект ведения лога
Код

$log =  new LogObject('individual.log');
DB->query($query, $params, $log);



Автор: sTa1kEr 24.9.2009, 17:58
Цитата(bars80080 @  24.9.2009,  18:36 Найти цитируемый пост)
одна страница/скрипт реализует интерфейс работы с базой данных. разные операции: создать базу, редактировать, создать таблицу, редактировать таблицу, её значения, слить дамп базы, загрузить дамп, закачать дамп на сервер, просто осуществить прямой запрос. дабы не мешать всё в кучу, для этих операций создаётся отдельный коннект

Все равно не понимаю. Имеем один, сервер, один коннект к нему и два разных интерфейса взаимодействия. Первый интерфейс реализует операции " создать базу, редактировать, создать таблицу...", второй то, что необходимо сайту. Все. Зачем тут два коннекта?

Цитата(bars80080 @  24.9.2009,  18:36 Найти цитируемый пост)
что сие значит?

Это значит
Цитата(bars80080 @  24.9.2009,  18:36 Найти цитируемый пост)
чтобы не приходилось впоследствии переключаться на прежнюю базу

Точнее вообще отказаться от переключения баз.

Добавлено через 1 минуту и 7 секунд
Цитата(youri @  24.9.2009,  18:23 Найти цитируемый пост)
я бы сказал "в разумных пределах"

Это само собой, разумеется.

Автор: nerezus 24.9.2009, 18:27
Цитата

Синглтон для работы с БД.
 Я юзаю Registry-паттерн.

Цитата

Коннект - статик свойство.
 Зачем? о_О

Автор: bars80080 24.9.2009, 19:27
Господи, какие же вы демагоги. ни одну проблему не можете решить в рамках поставленных условий. Саймон говорит прыгать на одной ноге, училка по рисованию - не использовать чёрную краску, родители - не лижи качельку на морозе. какая разница почему?

отлипли от БД.
есть класс подключения страницы, один объект, одна страница, ряд операций с ней. надеюсь, религия вам не мешает загонять три контента в один вывод?

теперь задаю вопрос: внимание!
может теперь увидите

Код

function metod() {
    global $content;
    ....
}

в ряде методов некоего третьего класса. нужно ли отходить от этой схемы?


-------------------------------------------------------------------------------------------------------------
вопрос был выше



как я понял, нужно. но судя по всему вы не можете определиться как. или я что-то упустил. можете конкретезировать?

/ни о какой БД мы здесь не говорим/

Автор: Simpliest 24.9.2009, 19:50
Тебе уже давно ответили. Только ты ответа не захотел увидеть.

Отходить нужно.

Как именно отходить - тебе дали "надцать" вариантов ответов.

Singletone, Registry, через одно место можно Factory.

Автор: bars80080 24.9.2009, 20:15
вот, registry. значит, завтра (может быть) будем разбираться, что это за зверь такой

Цитата(Simpliest @  24.9.2009,  19:50 Найти цитируемый пост)
тебе дали "надцать" вариантов ответов.

в слове три, формы "надцать" нет smile 

Автор: youri 24.9.2009, 21:31
Цитата(Simpliest @  24.9.2009,  17:41 Найти цитируемый пост)
Я говорил про вменяемых программистов, которые исповедуют KISS & DRY.

палишься ;)

Цитата(Simpliest @  24.9.2009,  17:41 Найти цитируемый пост)
Нет там разумных доводов, там есть искусственно созданные проблемы самому себе. 

если человек не хочет слушать...

Цитата(bars80080 @  24.9.2009,  19:27 Найти цитируемый пост)
теперь задаю вопрос: внимание!
может теперь увидите
в ряде методов некоего третьего класса. нужно ли отходить от этой схемы?

ответили почему: чтобы постоянно не писать и не забыть написать global
ответили как... чем отличаются варианты можно почитать в статье (кстати, писали разработчики limb). Фактически, если не практикуешь TDD, можно остановиться на Singleton, остальные варианты скорее для TDD (если неправ, объясните почему). Причем не обязательно создавать класс Singleton, можно обойтись функцией (см. выше)

Автор: Simpliest 24.9.2009, 21:51
Цитата(youri @  24.9.2009,  21:31 Найти цитируемый пост)

Цитата(Simpliest @  24.9.2009,  17:41 Найти цитируемый пост)
Я говорил про вменяемых программистов, которые исповедуют KISS & DRY.

палишься ;)

??? вменяемость как-то противоречит KISS & DRY?

Цитата(youri @  24.9.2009,  21:31 Найти цитируемый пост)
если человек не хочет слушать...

Тут не о чем говорить. Тесты не должны менять поведение тестируемого класса. Нигде и никогда.
Иначе я вам рефлексией такого наменяю, что из детской коляски у меня получится АК-47, как в пресловутом анекдоте.

Если вы и автор той статьи допускаете такое поведение - значит грошь цена вам, как профессионалам.

Автор: youri 24.9.2009, 22:18
Цитата(Simpliest @  24.9.2009,  21:51 Найти цитируемый пост)
Тесты не должны менять поведение тестируемого класса.

а кто сказал менять. Неужели моки уже considered harmful?

Автор: Simpliest 24.9.2009, 22:21
Мда, и как я такое пропустил

Цитата(youri @  24.9.2009,  21:31 Найти цитируемый пост)
ответили почему: чтобы постоянно не писать и не забыть написать global

К сведению. Отказаться от этого нужно не по причине забывчивости.

А по причине безопасности. Переменные в global scope могут быть изменены любым! случайным модулем. Этого быть не должно.

Цитата(youri @  24.9.2009,  21:31 Найти цитируемый пост)
Фактически, если не практикуешь TDD, можно остановиться на Singleton

Никакой прямой связи между Singleton и TDD нет. Проблема в узком мышлении и попытке покрыть непокрываемое, впихнуть невпихуемое.

Singleton это объект, который должен существовать в одном (ограниченном) числе. Все. Остальное от лукавого.
Все домыслы о том, что он мешает TDD - суть домыслы. Внятных аргументов, - чем он мешает, - нет, не было и не будет.
Боитесь статических связей? Откройте для себя делегаты и фабрики. И наслаждайтесь динамическими связями. Но причем тут Singleton и TDD?

Добавлено @ 22:30
Цитата(youri @  24.9.2009,  22:18 Найти цитируемый пост)
а кто сказал менять.

А вы не пробовали читать статью на которую ссылаетесь?
Я вам даже цитату оттуда приводил.

"В тестах иногда нужно иметь возможность изменить поведение этих методов"
Ага?

Там еще куча перлов. Например, паническая боязнь статических связей.
Пишем: Синглтон - зло он завязывает на себя объект статически.
и сразу код где мы напрямую в коде класса (статически) зависим от класса Log

Код

class Server{ 
  function serve(){
    […]
    Log :: logOk(‘Served Ok’);
  }
}


И тут же пишем какая классная вещь сервислокатор.
и сразу код.
Код

class Client(){
  protected $server;
 
  public function __construct(){
    $this->server = Locator :: instance()->getServer();
  }
 
  public function action(){
    [...]
    $this->server->serve();
    [..]
  }
}

Убейте меня тапком, если Locator :: instance()->getServer(); не статическая зависимость.
Что мы поменяли? Подсунули еще одну прослойку(абстракцию), а от статической связи не избавились.
Статическая - не значит что вызывается статический метод. А то что мы зависим от класса Locator напрямую

Черт побери! И эти люди запрещают ковыряться мне в носу?

Я вам говорил что статья очень спорна. И написана далеко не гуру. Специально освежил свои впечатления.
И таких ляпсусов там с полдесятка точно, и это на мой взгляд непрофессионала, который около полутора лет не писал ничего вообще.

Автор: bars80080 25.9.2009, 00:32
вот, а ещё говорите, что насоветовали надцать вариантов. singleton опять же оказывается одиночным, фабрика не к месту, а статья, которую обязательно надо прочитать, лучше не читать, или читать но осторожно

Цитата(youri @  24.9.2009,  21:31 Найти цитируемый пост)
Фактически, если не практикуешь TDD

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

Цитата(Simpliest @  24.9.2009,  22:21 Найти цитируемый пост)
Переменные в global scope могут быть изменены любым! случайным модулем. Этого быть не должно.

а разве в register я не могу поменять переменные любым случайным модулем?

Автор: youri 25.9.2009, 02:39
Цитата(Simpliest @  24.9.2009,  22:21 Найти цитируемый пост)
Переменные в global scope могут быть изменены любым! случайным модулем. Этого быть не должно.

если разумно использовать (для отдельных нужных везде объектов), никаких проблем не будет. Хотя если писать общедоступную библиотеку, то глобальные переменные не стоит использовать

Цитата(Simpliest @  24.9.2009,  22:21 Найти цитируемый пост)
Никакой прямой связи между Singleton и TDD нет. Проблема в узком мышлении и попытке покрыть непокрываемое, впихнуть невпихуемое.

может ты и прав, что проблема высосана из пальца

Цитата(Simpliest @  24.9.2009,  22:21 Найти цитируемый пост)
Пишем: Синглтон - зло он завязывает на себя объект статически.
и сразу код
includeSyntax('php');
class Server{   
function serve(){    
[…]    
Log :: logOk(‘Served Ok’);  
}
}

ты только забыл указать, что этот код - пример статической зависимости, там именно так прямо над кодом и написано

Цитата(Simpliest @  24.9.2009,  22:21 Найти цитируемый пост)
И тут же пишем какая классная вещь сервислокатор.

Цитата

Убейте меня тапком, если Locator :: instance()->getServer(); не статическая зависимость.

да, статическая зависимость, но мы же можем подменять объекты, которые service locator раздает

Цитата(bars80080 @  25.9.2009,  00:32 Найти цитируемый пост)
а разве в register я не могу поменять переменные любым случайным модулем?

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

Автор: NewDima 25.9.2009, 05:30
bars80080, может просто в конструктор передать? Агрегирование пойдет?

Автор: sTa1kEr 25.9.2009, 08:38
Цитата(bars80080 @  25.9.2009,  01:32 Найти цитируемый пост)
а разве в register я не могу поменять переменные любым случайным модулем? 

В register ты всегда можешь контролировать, что у тебя там лежит и зачем. К примеру, можешь сделать его read only или вести логи к его объектам или же вовсе изменить способ хранения объектов.
А globals - это просто бесконтрольная помойка переменных.

Автор: youri 25.9.2009, 08:52
Цитата(sTa1kEr @  25.9.2009,  08:38 Найти цитируемый пост)
А globals - это просто бесконтрольная помойка переменных

изначально - не помойка, но может такой стать

Автор: bars80080 25.9.2009, 09:39
Цитата(NewDima @  25.9.2009,  05:30 Найти цитируемый пост)
может просто в конструктор передать? Агрегирование пойдет? 

вот, интересный момент.

допустим, так:

Код

$some = new someclass($obj);

class someclass {

    var obj;
    function someclass(&$obj) {
        $this->obj = $obj;
    }
    function metod() {
        $this->obj->objmetod();
    }

}

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

Автор: MoLeX 25.9.2009, 10:49
Цитата(bars80080 @  25.9.2009,  09:39 Найти цитируемый пост)
дублированием объекта 

а с какой это стати объект будет дублирован?

Автор: NewDima 25.9.2009, 11:37
bars80080, иногда пугаешь)
ты пишешь под четверку?
По ссылке передашь и не будет никакого дублирования

Автор: solenko 25.9.2009, 12:04
bars80080, мой вам совет -- не пытайтесь решить одну конкретную проблему, задав вопрос на форуме. Вы вырываете ее из контекста и какие бы гуру вам не отвечали -- все равно получится костыль.

Получите системные знания по объектно ориентированом проектировании. Системности знаний могут помочь книги, а не ответы на форуме или статьи. 

Из того, что читал я, могу посоветовать:
Т.н. http://www.ozon.ru/context/detail/id/2457392/ - хрестоматийная книга, но тяжела для восприятия. 
Фаулер - http://www.ozon.ru/context/detail/id/1616782/. Опять же хрестоматия, но читается намного легче (как и все его книги).
Мэтт Зандстра - http://www.ozon.ru/context/detail/id/4574420/ - написана легко, примеры на php, примеры на web задачах.

Автор: bars80080 25.9.2009, 12:47
Цитата(MoLeX @  25.9.2009,  10:49 Найти цитируемый пост)
а с какой это стати объект будет дублирован? 

фиг знает. я тут заметил одну заморочку в js, что если приравнять один массив m1 к другому m2, то m1 станет ссылкой на m2.
а мне ответили, что так и должно быть (в смысле, это нормально для языка иметь такой механизм)


Цитата(NewDima @  25.9.2009,  11:37 Найти цитируемый пост)
ты пишешь под четверку?

ряд сайтов лежит на хосте с 4-кой. стало быть поддерживаем


Цитата(solenko @  25.9.2009,  12:04 Найти цитируемый пост)
мой вам совет -- не пытайтесь решить одну конкретную проблему, задав вопрос на форуме

это всё хорошо, но время, время...

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

возьмём эту литературу на заметку

Автор: Simpliest 25.9.2009, 13:44
Цитата(youri @  25.9.2009,  02:39 Найти цитируемый пост)
ты только забыл указать, что этот код - пример статической зависимости, там именно так прямо над кодом и написано

Для меня это было очевидно, но хорошо. Исправил.

Цитата(youri @  25.9.2009,  02:39 Найти цитируемый пост)
да, статическая зависимость, но мы же можем подменять объекты, которые service locator раздает

Минутку. Вам провести тест мешала именно статическая зависимость.
Вы ее не убрали, вы сменили шило на мыло. Теперь вместо правки кода Server мы будем править код Locator. А чем это лучше?

Избавится от статических зависимостей внутри класса вы можете инъекцией зависимости (Dependency injection), или паттерном строитель(Builder), который будет строить/собирать нужный объект. Вы не сделали ни того, ни другого. В чем был смысл сотрясания воздух в статье?

А финальный пример с toolkit вы там видели? Это же абзац полный. Вы создали жуткий звездный объект помойку. В котором неизвестно, что, где, когда и откуда.

Меня от этого вылечила идея автогенерируемой самоорганизующейся базы на архитектуре EAV. Идея прикольная - спору нет. Вот только удобство поддержки и качество ее работы - удручали.
Постоянный профайлинг (иначе не будет автооптимизации) - убивал производительность.
EAV - переложил всю логику связей и контроля целостности данных на приложение (это надо было реализовать таки, а в БД уже был готовый механизм).
Администрирование базы требовало написания специфических утилит потому что база практически ничего не знала о том, что лежит внутри нее.

Как итог куча лишнего геморроя. За облегчение жизни в виде прозрачного маппинга моделей в базу и отсутствие необходимости думать над ее структурой.

KISS - это сделать максимально просто насколько это возможно, но не проще. В противном случае облегчив жизнь в одном месте мы крайне усложним ее себе в другом.

Добавлено @ 13:55
Цитата(bars80080 @  25.9.2009,  09:39 Найти цитируемый пост)
по сути здесь мы и отделяем имя переменной от того что происходит в классе
такая постановка грозит чем-нибудь? дублированием объекта или иными заморочками?

Если не поставишь в конструкторе проверку на соответствие интерфейсу - грозит неработоспособностью smile

То что ты написал это dependency injection вкупе с delegation

P.S. что меня еще убивает в паттернах, так это то, что для осуществления похожих действий существует не один паттерн :(

Автор: youri 2.10.2009, 00:12
так эта...

Цитата(Simpliest @  24.9.2009,  22:21 Найти цитируемый пост)
Там еще куча перлов. Например, паническая боязнь статических связей.

кроме того, я не нашел там "панической боязни". Увидел только, что статическая зависимость рассматривается как один из недостатков. Если это учитывать, все становится не таким черным. Там не говориться, что делать. Там обсуждаются разные варианты с их плюсами и минусами. Сравниваются

Цитата(Simpliest @  25.9.2009,  13:44 Найти цитируемый пост)
Минутку. Вам провести тест мешала именно статическая зависимость.Вы ее не убрали, вы сменили шило на мыло. Теперь вместо правки кода Server мы будем править код Locator. А чем это лучше?

а разве статических зависимостей не стало меньше? 

Цитата(Simpliest @  25.9.2009,  13:44 Найти цитируемый пост)
А финальный пример с toolkit вы там видели? Это же абзац полный. Вы создали жуткий звездный объект помойку. В котором неизвестно, что, где, когда и откуда.

я этим toolkit'ом не пользовался и мне не очевидно, что это помойка. Я считаю так: ее можно превратить в помойку

Автор: Simpliest 2.10.2009, 01:16
Цитата(youri @  2.10.2009,  00:12 Найти цитируемый пост)
Там обсуждаются разные варианты с их плюсами и минусами. Сравниваются

Там останавливаются на конкретном решении, - которое им подошло, - Service Locator.
Dependency Injection упомянут вскользь, видимо, для них он оказался слишком сложным.

И в свете
Цитата(youri @  2.10.2009,  00:12 Найти цитируемый пост)
а разве статических зависимостей не стало меньше? 

Их осталось столько же.

Был один "звездный" объект мы его заменили другим объектом путем прямого редактирования кода объектов.
Статическая зависимость, которая якобы мешала ТДД осталась.
Надо будет опять поменять - мы будем или редактировать эти объекты или будем увеличивать "звездность" и запутанность Service Locator.

А представьте, если нам нужно будет добавить новый функционал не затронув старого для соседей?
В случае Injection я просто в конкретном месте передам новый объект реализующий нужный интерфейс.
В случае Locator -  мне придется выдумывать пляски с бубном.  Мне нужен объект с интерфейсом IA, а какой конкретно из 2х - хрен его знает. 

Смысла телодвижений 0. Оставались бы уже с Singleton.

Автор: bars80080 2.10.2009, 09:39
Цитата(Simpliest @  25.9.2009,  13:44 Найти цитируемый пост)
То что ты написал это dependency injection вкупе с delegation

в смысле?

Автор: solenko 2.10.2009, 12:04
Цитата(bars80080 @  2.10.2009,  08:39 Найти цитируемый пост)
Цитата(Simpliest @  25.9.2009,  13:44 )
То что ты написал это dependency injection вкупе с delegation

в смысле? 

http://forum.vingrad.ru/forum/topic-266904.html. Ну а по делигации -- в гугл )

Автор: bars80080 2.10.2009, 14:18
для нашего сурового и слегка окостеневшего моска там слишком тонко написано. тонко и размазанно

а в трёх фразах можно же?

Автор: solenko 2.10.2009, 17:17
Цитата(bars80080 @  2.10.2009,  13:18 Найти цитируемый пост)
а в трёх фразах можно же? 

Конечно можно. Внедрение зависимости, это когды зависимости внедряются, а не содержатся в исходном коде класса ))

Автор: youri 2.10.2009, 18:17
Цитата(Simpliest @  2.10.2009,  01:16 Найти цитируемый пост)
Там останавливаются на конкретном решении, - которое им подошло, - Service Locator.Dependency Injection упомянут вскользь, видимо, для них он оказался слишком сложным.

у тебя какое-то субъективно-негативное отношение к этой статье. Может потому, что не любишь TDD? Да, они для себя выбрали решение, но тем не менее они рассказали про другие варианты

Цитата(Simpliest @  2.10.2009,  01:16 Найти цитируемый пост)
Их осталось столько же.Был один "звездный" объект мы его заменили другим объектом путем прямого редактирования кода объектов.Статическая зависимость, которая якобы мешала ТДД осталась.

как это осталось столько же? Была куча звездных объектов, выполненных в качестве Sinleton'ов, вместо них остался один toolkit
Цитата

Начав с одиночек, мы быстро осознали их недостатки в модульном тестировании, и попробовали реализовать версию Service Locator, которая бы была удобной в использовании и не мешала тестированию.


Цитата(Simpliest @  2.10.2009,  01:16 Найти цитируемый пост)
Надо будет опять поменять - мы будем или редактировать эти объекты или будем увеличивать "звездность" и запутанность Service Locator.А представьте, если нам нужно будет добавить новый функционал не затронув старого для соседей?В случае Injection я просто в конкретном месте передам новый объект реализующий нужный интерфейс.В случае Locator -  мне придется выдумывать пляски с бубном.  Мне нужен объект с интерфейсом IA, а какой конкретно из 2х - хрен его знает. Смысла телодвижений 0. Оставались бы уже с Singleton.

не думаю, что это распространенная задача в TDD. У нас есть тесты. Можно исправить tool и тех, кто его использует. Но даже если мы хотим это оставить на потом, ничто не мешает добавить нам исправленный tool под другим именем в toolkit

Цитата(bars80080 @  2.10.2009,  14:18 Найти цитируемый пост)
а в трёх фразах можно же?

вот, например, статическая зависимость
Код

class Server{ 
  function serve(){
    […]
    $log = Log::get_instance();
    $log->logOk(‘Served Ok’);
  }
}

т.е. Server напрямую обращается к объекту. Но можно избавить его от лишней информации
Код

class Server(){
  protected $log;
 
  public function __construct($log){
    $this->log = $log;
  }
 
  public function serve(){
    [...]
    $this->log->logOk(‘Served Ok’);
  }
}

при этом мы сможем не меняя класс Server передать ему другой объект. Для одного клиента это не так важно, но когда клиентов много...

Автор: bars80080 2.10.2009, 19:02
так это здесь получилось копирование объекта?
а зачем? пусть один объект для всех идёт

Автор: youri 2.10.2009, 19:30
это не копирование, обьекты в php передаются http://us2.php.net/manual/en/language.oop5.references.php (упрощенно) 

Автор: bars80080 2.10.2009, 19:31
всегда, что ли?

Автор: youri 2.10.2009, 20:18
в 5-ой версии

Автор: nerezus 3.10.2009, 09:34
Цитата

всегда, что ли?
 Да, всегда. Пора бы уже и основы PHP знать.

Цитата

в 5-ой версии
 Во всех актуальных. Т.е. в 5 и 6(ее уже пора принимать во внимание).

Автор: bars80080 3.10.2009, 14:06
Цитата(nerezus @  3.10.2009,  09:34 Найти цитируемый пост)
Пора бы уже и основы PHP знать.

почему?

Автор: youri 3.10.2009, 14:41
зато у bars80080 одна награда есть smile 

Автор: nerezus 3.10.2009, 16:31
Цитата

почему?
 Что почему? Что объекты всегда передаются по ссылке?

Цитата

зато у bars80080 одна награда есть  
 А у авторов inphp.org есть сайт inphp.org, и что? Это еще не значит, что они хорошо знают php ;)

Автор: bars80080 3.10.2009, 20:38
Цитата(nerezus @  3.10.2009,  16:31 Найти цитируемый пост)
Что почему? Что объекты всегда передаются по ссылке?

почему отношение такое негативное? вы не кушали сегодня йогурт "нежный"? или вы опять кому-то отказали?

Автор: Simpliest 5.10.2009, 17:31
Цитата(youri @  2.10.2009,  18:17 Найти цитируемый пост)
как это осталось столько же?

Речь шла о конкретном объекте.

Для приложения пачка Singleton (почему появилась эта самая пачка - тот еще вопрос) хуже чем один Service Locator - это очевидно.

Цитата(youri @  2.10.2009,  18:17 Найти цитируемый пост)
добавить нам исправленный tool под другим именем в toolkit

А потом унаследовать класс и переопределить метод где мы вызывали этот самый tool на toolkit?

Старый класс
Код

class A
{
    public function __construct()
    {
        $this->service = ServiceLocator:getTool('tool');
    }
}


Новый класс
Код

class B extends A
{
    public function __construct()
    {
        $this->service = ServiceLocator:getTool('toolkit');
    }
}


Не проще ли
Код

class A
{
    public function __construct($service)
    {
        $this->service = $service;
    }
}

$a = new A(new Service('tool');
$b = new A(new NewService('toolkit'));
// можно даже так
$c = new A(ServiceLocator::getTool('toolkit'));


Почуствуйте разницу и уровень завязанности кода.

Автор: youri 6.10.2009, 09:18
Цитата(Simpliest @  5.10.2009,  17:31 Найти цитируемый пост)
Речь шла о конкретном объекте.

минутку. Где шла речь об одном объекте? Класс Server
Код

class Server{ 
  function serve(){
    […]
    Log :: logOk(‘Served Ok’);
  }
}

упоминается при описании http://wiki.agiledev.ru/doku.php?id=ooad:manage_dependencies_in_php_code#%D1%85%D0%B0%D1%80%D0%B0%D0%BA%D1%82%D0%B5%D1%80_%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D0%B5%D0%B9
и в том же разделе указывается один из вариантов обеспечения инверсии зависимостей
Код

class Client(){
  protected $server;
 
  public function __construct(){
    $this->server = Locator :: instance()->getServer();
  }
 
  public function action(){
    [...]
    $this->server->serve();
    [..]
  }
}

дальше идет более подробное обсуждение. В этом же разделе особого сравнения нету

Цитата(Simpliest @  5.10.2009,  17:31 Найти цитируемый пост)
А потом унаследовать класс и переопределить метод где мы вызывали этот самый tool на toolkit?

вы вырвали фразу из контекста. Я говорил об этом как о временном решении. А вообще, конечно, в данной ситуации dependency injection удобнее. Но такой подход имеет и недостатки
Цитата

Передача объектов по цепочке - решение, при котором часто используемые объекты передаются по цепочке на сколь угодную глубину. Нами этот способ раньше использовался, например, для передачи объектов Запроса и Ответа приложения. В целом этот способ имеет слишком большие недостатки тем, что раздувает количество передаваемых параметров в конструкторы или методы классов. Пытаясь преодолеть этот недостаток, некоторые вводят понятие контекста. Такой подход предусматривает создание такого весьма тяжелого контейнера, который в себе хранит (может также отвечать за инициализацию) все нужные приложению объекты. Этот контекст передается между всеми объектами приложения, если тем нужно что-либо из этого контекста. Как правило, контекст содержит четкий предопределенный набор объектов и четкий интерфейс. Такой подход применяется в php-фреймворках Symfony и CodeIgniter. Передача объектов по цепочке – push прием (Constructor Injection или Setter Injection), хотя в случае с контейнером уже двойной Inject + Lookup.

Цитата

Передача объектов по цепочке с использованием контейнера - в целом очень неплохой прием, который обеспечивает четкий интерфейс получения «звездных» объектов клиентским кодом. При необходимости расширения базового контейнера можно создать дочерний класс. Такой контейнер позволяет легко обеспечить lazy initialization часто используемых объектов.

Цитата

Я нашел следующие недостатки глобальных контейнеров:

    *
      Практика показала, что в такие контейнеры также загоняются и дополнительные сервисные и фабричные методы. В тестах иногда нужно иметь возможность изменить поведение этих методов. Однако при реализации контейнера, как в Symphony, мы имеем фактически статическую зависимость клиентского кода от класса контейнера, и эту подмену осуществить не удастся.
    *
      Если же контейнер не является одиночкой, а передается всегда явно, тогда нужно реализовать метод его получения из любого места приложения, так как делать метод setContext($context) в каждом классе не слишком приятно.

В принципе, для преодоления этих недостатков, достаточно сделать главный контейнер, в котором будет храниться набор конкретных контейнеров. В этом случае получится вариант решения, который мы долго использовали в Limb3 до появления современной версии пакета Toolkit (об этом чуть ниже). 

Автор: Simpliest 6.10.2009, 13:11
Цитата(youri @  6.10.2009,  09:18 Найти цитируемый пост)
минутку. Где шла речь об одном объекте?


Да вот же...
вы тут их и привели. Что непонятного?

Был класс Server с  1й статической зависимостью
Код

Log :: logOk(‘Served Ok’);


Мы показываем пример (используя другой класс), как избегать статических зависимостей, и... о чудо
Код

$this->server = Locator :: instance()->getServer();

приводим пример с Client с 1й статической зависимостью...

Я не понимаю smile  Куда вы пытаетесь мыслью уплыть?

Автор: youri 6.10.2009, 13:27
да, не внимательно прочитал тот раздел. Там приводиться пример статической зависимости класса Server от класса Log. Затем сравниваются статические и динамические зависимости. Затем приводиться примеры избавления от статических зависимостей (с предыдущими примерами практически не связаны). Пример для Service Locator показывает как избавиться для некоторого абстрактного класса от статической зависимости от одного из "звездных" объектов - класса Server. В чем проблема? Было много "звездных" объектов и статических зависимостей от них. В результате получили одну статическую зависимость от Service Locator

Автор: Simpliest 6.10.2009, 15:08
Цитата(youri @  6.10.2009,  13:27 Найти цитируемый пост)
 В чем проблема? Было много "звездных" объектов и статических зависимостей от них. В результате получили одну статическую зависимость от Service Locator 

Проблема в подаче и материале.

Избавиться от статических зависимостей
и 
Уменьшить число статических зависимостей

Разные вещи. Не так ли?

Автор: youri 6.10.2009, 16:03
а где там написано "Избавиться от статических зависимостей" (в смысле всех)?

Автор: Simpliest 6.10.2009, 19:34
Парень, я не люблю идиотов.

Цитата
В тестах иногда нужно иметь возможность изменить поведение этих методов. Однако при реализации контейнера, как в Symphony, мы имеем фактически статическую зависимость клиентского кода от класса контейнера, и эту подмену осуществить не удастся.


Больше чем идиотов я не люблю тех, кто ими прикидывается.

Разговор закончен.

Автор: youri 6.10.2009, 23:54
цитата на мой вопрос не отвечает
если тебя не понимают, это может значить, что ты не умеешь внятно объяснить свои мысли. Если честно, у меня такое впечатление, что ты надо мной издеваешься...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)