LINUX.ORG.RU

Большой PHP-класс, работающий с БД

 , ,


0

1

Всем привет! Мне по работе передали один проект на великом и могучем PHP. Обычное веб-приложение. Но очень много работы с БД - много разных выборок и вставок для каждой группы данных. Посколько кода много (сотни функций, автор разбил работу с БД на разные классы по сущностям: пользователи, группы, логи...

Чтобы не «тащить» за собой всегда кучу экземпляров разных классов, он создал один главный класс «dtb» конструктору которого передает ссылку на подключение к базе, а он в свою очередь заполняет свои public поля экземплярами других классов.

Выглядит очень странно:

http://pastebin.com/MGha5CmY

/* Класс поля которого ($user, $log, ...) будут содержать
       экземпляры других классов для работы с БД   
*/
class dtb {
	public $user = null; // экземпляр класса dtbUser
	public $log = null;  // экземпляр класса dtbLog
	// и еще десяток разных
	
	private function __construct(&$connectionLink) {
		if ($connectionLink instanceof MongoDB) {
			$this->user = new dtbUser($connectionLink);
			$this->log = new dtbLog($connectionLink);
			// ...
		}
		else 
			trigger_error('wrong connection', E_USER_ERROR);
	}
}


class dtbItem {
	protected $db = null;
	function __construct(&$connectionLink)
		$this->db = $connectionLink;
}

class dtbUser extends dtbItem{
	public function getOne() {
		$coll = $this->db->selectCollection('users');
		$obj = $coll->findOne();
		return $obj;
	}
	// куча других функций


class dtbLog extends dtbItem{
	public function getTwo() {
		$coll = $this->db->selectCollection('log');
		$obj = $coll->findOne();
		return $obj;
	}
	// куча других функций
}


/* Работает это так: */

$conn = new MongoClient();
$dtbs = new dtb($conn);

var_dump( $dtbs->user->getOne() );
var_dump( $dtbs->log->getTwo() );

Беда этого способа в том, что из класса dtbUser нельзя получить методы класса dtbLog и проектировщик каждый раз описывал всё заново в каждом классе.

А как правильно в PHP реализуется работа с БД когда очень много (сотни) функций получения данных?
И вообще, как правильно в PHP реализуется работа с БД?

p.s. класс dtb инстанцируется как синглтон (но это не важно)


Нужен менеджер зависимостей. Будет проще. Pimple, к примеру. Если там что-то по сложнее, то можно нормальную либу подобрать. http://php-di.org/ или симфониевский DI

Kilte ★★★★★ ()

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

Kilte ★★★★★ ()
Ответ на: комментарий от goingUp

получить методы

class dtbLog extends dtbItem{
	public function getTwo() {
...
	}
        public function logUsers() {
		$coll = $this->db->selectCollection('log');
                $obj_to_insert = /* вот тут нужно вызвать метод getOne() класса dtbUser, то есть получить пользователя */;
                $coll->insert($obj_to_insert);
        }
}

описывал заново

Функция logUsers состояла из двух частей: копипаста функции getOne (класс dtbUser) и далее сама функция.

Да, это ад.

JANB ()
Ответ на: комментарий от JANB

Если dtb синглтон, то у него должны быть средства, чтобы получить инстанс? Получай юзера из dtb. Вообще, это какая-то кривая реализация паттерна Registry.

Про копипасту - это можно сделать стандартными средствами ООП, например наследованием или аггрегированием.

goingUp ★★★★★ ()
Ответ на: комментарий от goingUp

Если dtb синглтон, то у него должны быть средства, чтобы получить инстанс? Получай юзера из dtb

class dtb {
    private static $_instance;    
    public $user = null;
    public $log = null;
    //....
    
    private function __construct(&$connectionLink) {
        if ($connectionLink instanceof MongoDB) {
            $this->user = new dtbUser($connectionLink);
            $this->log = new dtbLog($connectionLink);
        }
        else 
            trigger_error('Ы', E_USER_ERROR);
    }
    
    public static function singleton($connectionLink) {
        if (self::$_instance === null) {
            self::$_instance = new self($connectionLink);
        }
        return self::$_instance;
    }
    //... тут еще блокировка __clone и __wakeup
}

Чтобы мне его вызывать в dtbLog мне нужно иметь ссылку на подключение....

class dtbLog extends dtbItem{
    public function logUsers() {
        $coll = $this->db->selectCollection('log');
	$tmp_dtb = dtb::singleton($this->db)
        $obj_to_insert = $tmp_dtb->users->getOne();
        $coll->insert($obj_to_insert);
    }
}

меня бросает от этого в дрожь:

$tmp_dtb = dtb::singleton($this->db);
$obj_to_insert = $tmp_dtb->users->getOne();

Пока читаю про Registry. Это точно подходящий паттерн?

Про копипасту - это можно сделать стандартными средствами ООП, например наследованием или аггрегированием.

Любой пример, хотя бы на словах, как тут обойтись наследованием? Не могу придумать.

JANB ()
Ответ на: комментарий от umren

Ну я «образно». Разумеется, это не _ад_. И даже не ААААААД. Так, ерунда.



Извините за вопрос, а вы специалист по Аду или по PHP?

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

JANB ()
Ответ на: комментарий от goingUp

Почитал про Registry. Ну да, что-то подобное.

Мне кажется, что имеет смысл доделать весь код до Multiton (пул синглтонов) - тогда будет мне счастье?

JANB ()
Ответ на: комментарий от JANB

Чтобы не «тащить» за собой всегда кучу экземпляров разных классов, он создал один главный класс «dtb» конструктору которого передает ссылку на подключение к базе, а он в свою очередь заполняет свои public поля экземплярами других классов.

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

Вот на примере Pimple: http://code.re/61y

Kilte ★★★★★ ()

используй примеси или агрегацию (создай класс LoggedUser например)

Проблема фигня.

anonymous ()
Ответ на: комментарий от JANB

Делать все синглтонами не очень хорошая идея, например, когда тебе понадобится два инстанса, придется все переделать. Или для юнит тестирования. Kilte советует dependancy injection container, и это в общем более продвинутый способ, чем синглтоны-регистри.

goingUp ★★★★★ ()

Беда этого способа в том, что из класса dtbUser нельзя получить методы класса dtbLog и проектировщик каждый раз описывал всё заново в каждом классе.

Создай общего предка если есть дубли

А как правильно в PHP реализуется работа с БД когда очень много (сотни) функций получения данных?

И вообще, как правильно в PHP реализуется работа с БД?
Собственно, от языка не зависит, опять же используй общую абстракцию, собственно наследование+полиморфизм

kiotoze ★★★★ ()
Ответ на: комментарий от Kilte

Pimple это конечно очень круто, но ему бы понять саму структуру что есть, а то не думаю, что будет весь этот ад на pimple перегонять

Главное, чтобы он понял, что инстанс юзера нужно передать в конструктор DtbLog

kiotoze ★★★★ ()
Ответ на: комментарий от kiotoze

Главное, чтобы он понял, что инстанс юзера нужно передать в конструктор DtbLog

Угу. Я сейчас понял...

Создай общего предка если есть дубли

А это не понял. У меня вроде итак общий предок $dtbItem

JANB ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.