PHP. Как грамотно создать дополнительный класс (ООП) для «конкретных» select'ов для работы с БД? Есть в модели класс работы с бд с синглтоном (назовём его M_MSQLI). Синтаксис используется "классический" с обёртыванием данных $this->mysqli->real_escape_string() перед вставкой в запрос. Кроме общих стандартных функций в нём есть пачка "одноразовых" функций Select'ов, которые используются только в одном разделе сайта. Чтобы каждый раз не прогружать весь зоопарк функций, хочется выделить функции со "специальными" запросам в отдельный класс, который будет прокладкой между моделью и бд (назовём его M_MSQLI_SELECT). Вот тут и возникает вопрос как грамотно это сделать. Итак, внимание, вопрос: Каким образом оптимально и правильно вызвать соединение с БД в классе M_MSQLI_SELECT, чтобы использовать real_escape_string() в функциях этого класса, если учесть, что он использует некоторые функции класса M_MSQLI? Варианты, которые посещали мои пэхэпэхнутые извилины:Вариант[0]. Наследование: Полистав гугл и тостер, стало понятно, что наследовать новый класс от M_MSQLI моветон и не есть гуд. Огорчает еще то, что при этом придётся изменить область видимости свойства $mysqli (с private на protected), знаний оценить насколько это чревато не хватает, но ощущение, что не стоит этого делать есть.Вариант[1]. Новое подключение к БД в доп.классе: Заново вызвать в конструкторе класса M_MSQLI_SELECT подключение к БД и в функциях обращаться к нему. Тут возникает вопрос: проблема ли, что при обращении M_MSQLI_SELECT к M_MSQLI подключение будет создаваться повторно? Или это нормально?Вариант[2]. Использование класса M_MSQLI как объект: В этом случае вообще придётся забыть об инкапсуляции и все требуемые свойства и функции делать публичными. Тут уже никаких "ощущений" нет - это явно лишнее.Вариант[3]. Копипаст: Можно просто скопировать класс M_MSQLI в M_MSQLI_SELECT, добавить в последний специальные запросы и обращаться к нему только по необходимости. Но - дублирование кода и прочие неприятности. Поэтому не хотелось бы. Не судите строго, это мой первый вопрос поcле освоения php. Буду признателен, если укажите на ошибки в соображениях, поделитесь подходящей ссылкой или подскажите в каком направлении копать. Что смог найти по теме - прочитал, кстати, спасибо FanatPHP за развёрнутые комментарии на тостере и терпение, были очень кстати! Как выглядит класс M_MSQLI (кусок, далее аналогично стандартные функции для работы):mysqli = new mysqli(M_dbconfig::DB_HOST, M_dbconfig::DB_USER, M_dbconfig::DB_PASS, M_dbconfig::DB_NAME); // Назначение кодировки $this->mysqli->query('SET NAMES utf8'); // Установка внутренней кодировки в UTF-8 mb_internal_encoding("UTF-8"); } // Далее идут общие функции.
// Выборка строк (внутренняя функция) // $query - полный текст SQL запроса // результат - массив выбранных объектов $arr private function Select($query) { // Запрос к БД $result = $this->mysqli->query($query);
// Проверка на успешный результат if ($this->mysqli->error) {...} // Создаём массив для конечного результата $arr = array(); // Извлекаем ряд таблицы в виде ассоциативного массива. Цикл повторяется пока строки есть while ($row = $result->fetch_assoc()) $arr[] = $row; // Помещаем извлеченные ряды в общий массив // Возвращаем полученный общий массив return $arr; }
// Вставка строки // $table - имя таблицы // $object - ассоциативный массив с парами вида "имя столбца - значение" // результат - идентификатор новой строки ($this->mysqli->insert_id) public function Insert($table, $object) { // Создаём массив для столбцов куда будем вставлять новое значение $columns = array(); // Создаём массив для значений которые будем вставлять $values = array();
// Разбираем массив с данными по столбцам. array('title' => '1223', 'content' => 'dadsd') foreach ($object as $column => $value) { // Экранируем специальные символы в названии столбца $column = $this->mysqli->real_escape_string($column);
// Добавляем каждый столбец в массив столбцов $columns[] = "`$column`";
// Записываем нулы пустых значений, чтобы длины значений и столбцов были равны if ($value === NULL) { // Добавляем значение в массив значений $values[] = "''"; } else { // Экранируем специальные символы в значении $value = $this->mysqli->real_escape_string($value);
// Добавляем каждое значение в массив значений $values[] = "'$value'"; } } // Собираем столбцы в строку $columns_s = implode(', ', $columns); // Собираем значения в строку $values_s = implode(', ', $values); // Маска запроса $sql = "INSERT INTO `%s` (%s) VALUES (%s)"; // Экранируем и форматируем переменные в запросе $query = sprintf($sql, $this->mysqli->real_escape_string($table), $columns_s, $values_s); // Запрос к БД $result = $this->mysqli->query($query); // Проверка на успешный результат if ($this->mysqli->error) {...}
// Возвращаем индификатор новой строки return $this->mysqli->insert_id; }
// Изменение строк // $table - имя таблицы // $object - ассоциативный массив с парами вида "имя столбца - значение" // $where_column - имя столбца для WHERE (часть SQL запроса) // $where_value - значение столбца для WHERE (часть SQL запроса) // результат - число измененных строк ($this->mysqli->affected_rows) public function Update($table, $object, $where_column, $where_sign, $where_value) { // аналогичный код. }
// Удаление строк // $table - имя таблицы // $where_column - имя столбца для WHERE (часть SQL запроса) // $where_value - значение столбца для WHERE (часть SQL запроса) // результат - число удаленных строк ($this->mysqli->affected_rows) public function Delete($table, $where_column, $where_sign, $where_value) { // и так далее. }
// Количество строк в таблице // $table - имя таблицы // результат - число строк из массива public function Count($table) { // и так далее. } Далее пример функции, которые пишутся под конкретный вызов для конкретного раздела. Их хотелось бы выделить в отдельный класс:= '%s' AND `some_field` mysqli->real_escape_string($var1), $this->mysqli->real_escape_string($var2), $this->mysqli->real_escape_string($id)); // Подготавливаем результат запроса в метод M_MSQLI $result = $this->Select($query); // Возращаем массив return $result; }
Для создания дополнительного класса M_MSQLI_SELECT, который будет работать с конкретными select'ами для работы с БД и использует функции класса M_MSQLI, можно использовать следующий подход:
Передайте экземпляр класса M_MSQLI в конструктор класса M_MSQLI_SELECT. Это позволит использовать объект M_MSQLI внутри класса M_MSQLI_SELECT для вызова функций класса M_MSQLI, таких как real_escape_string().
Пример кода для класса M_MSQLI_SELECT:
class M_MSQLI_SELECT { private $msqli_instance; public function __construct($msqli_instance) { $this->msqli_instance = $msqli_instance; // передача экземпляра класса M_MSQLI } // Функция для выполнения специального select запроса public function SelectSomethingUnusual($var1, $var2, $id) { $sql = "SELECT * FROM `table` WHERE `var1` = '%s' AND `var2` = '%s' AND `id` = '%s'"; $query = sprintf($sql, $this->msqli_instance->real_escape_string($var1), $this->msqli_instance->real_escape_string($var2), $this->msqli_instance->real_escape_string($id)); // Вызов функции Select из класса M_MSQLI $result = $this->msqli_instance->Select($query); return $result; } }При создании экземпляра класса M_MSQLI_SELECT передайте в конструктор объект M_MSQLI, который был создан из синглтона.
Пример использования классов:
// Получаем экземпляр класса M_MSQLI через синглтон $msqli_instance = M_MSQLI::Instance(); // Создаем экземпляр класса M_MSQLI_SELECT с передачей объекта M_MSQLI $msqli_select = new M_MSQLI_SELECT($msqli_instance); // Вызываем функцию SelectSomethingUnusual $results = $msqli_select->SelectSomethingUnusual($var1, $var2, $id);
Таким образом, вы сможете использовать класс M_MSQLI_SELECT для выполнения специфических select запросов к БД, используя функции класса M_MSQLI, включая real_escape_string(). Главное, чтобы экземпляр M_MSQLI был передан в конструктор M_MSQLI_SELECT для использования его функций.
Для создания дополнительного класса M_MSQLI_SELECT, который будет работать с конкретными select'ами для работы с БД и использует функции класса M_MSQLI, можно использовать следующий подход:
Передайте экземпляр класса M_MSQLI в конструктор класса M_MSQLI_SELECT. Это позволит использовать объект M_MSQLI внутри класса M_MSQLI_SELECT для вызова функций класса M_MSQLI, таких как real_escape_string().Пример кода для класса M_MSQLI_SELECT:
class M_MSQLI_SELECT{
private $msqli_instance;
public function __construct($msqli_instance)
{
$this->msqli_instance = $msqli_instance; // передача экземпляра класса M_MSQLI
}
// Функция для выполнения специального select запроса
public function SelectSomethingUnusual($var1, $var2, $id)
{
$sql = "SELECT * FROM `table` WHERE `var1` = '%s' AND `var2` = '%s' AND `id` = '%s'";
$query = sprintf($sql,
$this->msqli_instance->real_escape_string($var1),
$this->msqli_instance->real_escape_string($var2),
$this->msqli_instance->real_escape_string($id));
// Вызов функции Select из класса M_MSQLI
$result = $this->msqli_instance->Select($query);
return $result;
}
}При создании экземпляра класса M_MSQLI_SELECT передайте в конструктор объект M_MSQLI, который был создан из синглтона.
Пример использования классов:
// Получаем экземпляр класса M_MSQLI через синглтон$msqli_instance = M_MSQLI::Instance();
// Создаем экземпляр класса M_MSQLI_SELECT с передачей объекта M_MSQLI
$msqli_select = new M_MSQLI_SELECT($msqli_instance);
// Вызываем функцию SelectSomethingUnusual
$results = $msqli_select->SelectSomethingUnusual($var1, $var2, $id);
Таким образом, вы сможете использовать класс M_MSQLI_SELECT для выполнения специфических select запросов к БД, используя функции класса M_MSQLI, включая real_escape_string(). Главное, чтобы экземпляр M_MSQLI был передан в конструктор M_MSQLI_SELECT для использования его функций.