При запрос в базу и получает данные с чата. $chat = array(с базы); При каждый foreach вызываю user_id где то 20 раз за это мы вызываем класс new User($user_id); А там уже идет запрос на базу узера и получаем логина и так далее.... за 20 раз мы отправляем запрос в базу это немного значительно обьема. Есть ли обойти его? Ответ нужен: - Как его уменшить с 20 запроса на 1 раз. Подробно: точнее при нового класса храним индификатор при полного сбора пока не закончит и начнет собирать запрос 1 раз всех индификатор. Но этого не помогает как сделать хз! Пример: Код (PHP): $array_chat = array( array('user_id' = 1), array('user_id' = 2), array('user_id' = 3), array('user_id' = 1), foreach($array_chat AS $message) { $user = new user($message['user_id']); print $user->login; } ); Извини за плохой русского языка. +) Если вам не понравилось можете оставить плохой коммент, что я тупой или вроде!
Собрать все уникальные user_id в массив, к примеру $user_ids, и потом сделать один запрос in. А потом сделать что-то типа: Код (PHP): class UsersRepository { private $users; public function __construct($ids) { global $mysqli; // Не хотите глобал, сделайте статическое поле какого-нибудь класса. Не суть в данном случае // Для безопасности foreach ($ids as &$id) { $id = (int) $id; } $ids_str = implode(",", $ids); $res = $mysqli->query("select * from users where id in ($ids)"); while ($u = $res->fetch_object()) { $this->users[$u->id] = $u; } $res->close(); } function getUser($id) { return isset($this->users[$id]) ? $this->users[$id] : null; } }
У меня есть вариант, но он специфический и не для всех ситуаций подойдет. В большинстве случаев нам не нужны сразу 100500 экземпляров User. Мы обрабатываем их последовательно внутри цикла и на каждой итерации цикла используем новый объект. А старый просто теряется и ждет когда его утилизует сборщик мусора ))) Или мы хотим получить только какой-то конкретный объект по его индексу/айдишнику. Но почти никогда нам не нужны сразу два разных объекта из одной выборки! Исходя из этих соображений я делал класс-итератор, реализующий стандартные интерфейсы Iterator и ArrayAccess и который на входе получает массив строк из базы. Двумерный массив: колонки и записи. Полученные одним запросом и считанные в цикле. Что-то вроде: Код (PHP): // где-то внутри репозитория while ($row = mysqli_fetch_assoc($result)) { $rows[] = $row; } return new MyIterator($rows); Итератор НЕ создаёт сразу все объекты-записи. А делает new MyClass() только тогда, когда требуются запись — в перекрытых методах offsetGet() и current(). (см. описание интерфейсов по ссылкам выше) Код (PHP): // итератор выглядит как массив, но на самом деле при получении элемента "массива" // происходит обращение к методу, где мы можем создать новый объект-запись. foreach ($userIterator as $user) { echo $user->id, $user->name; } Я пошел даже дальше и стал создавать только один экземпляр объекта-записи, а в методах итератора просто присваиваю его полям нужные значения из массива. И за всё время использования только в одной задаче мне понадобилось зафиксировать состояние объекта-записи чтобы работать сразу с двумя разными экземплярами. Это возможно через операцию clone: Код (PHP): // этот экземпляр объекта уже не изменится при получении новой записи из итератора $savedUser = clone $user;
artoodetoo, суть уловил но не много не понял =) Добавлено спустя 5 минут 4 секунды: У меня такой код класс User и Auth Класс Auth Код (PHP): <?php namespace Classes\Core; class Auth { static protected $_data = null; /** * Инициализация пользователя * @return User */ static protected function InitUser() { if (!empty($_SESSION ['SESSION_ID_USER'])) { self::$_data = new User($_SESSION ['SESSION_ID_USER']); } else { self::$_data = new User(); } if (self::isGuest() && isset($_SESSION ['SESSION_ID_USER'])) { unset($_SESSION ['SESSION_ID_USER']); } } /** * @return User */ static public function GetUser() { if (is_null(self::$_data)) { self::InitUser(); } return self::$_data; } /** * @return True/False */ static public function IsGuest() { return !self::GetUser()->id; } /** * @return True/False */ static public function IsUser() { return !!self::GetUser()->id; } } модельный дата Класс User Код (PHP): <?php namespace Classes\Core; class User { static protected $_data = array(); static protected $_update = array(); /** * Инициализация Пользователя */ static protected function InitUser($id) { $res = Db::GetPdo()->prepare("SELECT * FROM `users` WHERE `id` = ? LIMIT 1"); $res->execute(Array($id)); return self::$_data = $res->fetch(); } /** * Инициализация Гостя */ static protected function InitGuest() { return self::$_data['id'] = false; } /** * */ public function __construct($id = false) { if ($id) { return self::InitUser($id); } return self::InitGuest(); } public function __destruct() { if (self::$_update) { $sql = array(); foreach (self::$_update as $key => $value) { $sql[] = "`" . $key . "` = " . Db::GetPdo()->quote($value); } Db::GetPdo()->query("UPDATE `users` SET " . implode(', ', $sql) . " WHERE `id` = '" . self::$_data['id'] . "' LIMIT 1"); self::$_update = array(); } } /** * */ public function __get($name) { switch($name) { default: return !isset(self::$_data[$name]) ? false : self::$_data[$name]; break; } } /** * */ public function __set($name, $value) { if (empty(self::$_data['id'])) { return; } if (!isset(self::$_data[$name])) { throw new \Exception(sprintf('Поле %s не существует', $name)); } self::$_data[$name] = $value; self::$_update[$name] = $value; } } Auth это который я сижу и выдает только мои данные! Добавлено спустя 41 минуту 21 секунду: Сделал так но много код даже 2 раза foreach как то муторно =) Код (PHP): $res = $db->GetPdo()->prepare("SELECT * FROM `chat` LIMIT 100"); $res->execute(Array(1)); if($chat = $res->fetchAll()) { echo '<pre>'; print_r($chat); echo '</pre>'; foreach($chat AS $comment) { $array[] = $comment['user_id']; } $users = new Users($array); foreach($chat AS $comment) { $user = $users->GetUser($comment['user_id']); echo 'Писал: ' . $user->login . '</br>'; echo $comment['text']; } }
engine.energy, идея коротко: 1. нам не нужны лишние объекты; 2. класс из предметной области не знает ничего о способе его хранения.
artoodetoo, и что ты предлогаеш? все пользовать в базе ? Нет так как каждый обьект служит для аватара и прочие функции дабы быстро обрашать!