Разработка общего интерфейса базы данных на PHP - PullRequest
11 голосов
/ 17 марта 2010

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

У меня не было проблем при разработке и кодировании инфраструктуры, когда речь идет о таких элементах, как структура ядра, обработка запросов и т. Д., Но я застрял при разработке интерфейса базы данных для моих модулей.

Я уже думал об использовании шаблона MVC, но обнаружил, что это будет немного излишним для моих довольно небольших проектов.

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

  • Является ли (все еще) хорошей идеей смешивать SQL непосредственно с PHP-кодом? (Будет "по-старому": mysql_query( 'SELECT firstname, lastname(.....))?

  • Как я могу абстрагировать запрос, подобный следующему?

    SELECT firstname, lastname FROM customers WHERE id=X
    

Будет ли MySQL "вспомогательным" функционировать как

$this->db->customers->getBy( 'id', $x );

хорошая идея?

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

  • Является ли модель "Модель" из MVC моей единственной реальной возможностью решить эту проблему?

  • Что вы используете в настоящее время для решения проблем, указанных выше?

Ответы [ 11 ]

6 голосов
/ 22 марта 2010

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

Например, у вас может быть файл, например models / Customers.php с таким кодом:

<?php

class Customers {

    public function getById($id) {
        $sql = "SELECT first_name, last_name FROM customers WHERE id='$id'";
        $res = $DB::getRow($sql);
        return ($res);
    }
}

Я предполагаю, что какой-то помощник по БД уже создан и доступен как $ DB. Здесь - простой, использующий PDO.

Теперь вы должны включить это в свой модуль и использовать следующий способ:

<?php

include_once "models/Customers.php";

$customers = new Customers();
$theCustomer = $customers->getById(intval($_REQUEST['cust_id']));


echo "Hello " . $theCustomer['first_name']

Приветствие.

5 голосов
/ 17 марта 2010

Вы изучили http://www.doctrine -project.org / или другие фреймворки php orm (на ум приходит zend_db)?

3 голосов
/ 28 марта 2010

Если вам нужна скорость, используйте необработанные запросы (но вам действительно следует использовать PDO с подготовленными запросами ).

Если вы хотите что-то более ООП, вы можете - как вы предлагаете - разработать это с помощью помощников.

Однажды я разработал нечто подобное, которое имело следующую концепцию:

  1. Классы соединений / обработчиков БД (обработка нескольких соединений с разными базами данных и разными серверами, такими как MySQL, Oracle и т. Д.);
  2. Класс за действие (т. Е. SELECT, DELETE и т. Д.);
  3. Классы фильтров (например, RangeFilter);

Код выглядел примерно так:

$select = new Select('field1', 'field2', );
$result = $select->from('myTable')
                 ->addFilter(SQLFilter::RangeFilter, 'field2')
                 ->match(array(1, 3, 5))
                 ->unmatch(array(15, 34))
                 ->fetchAll();

Это простой пример того, как вы можете его построить.

Вы можете пойти дальше и внедрить автоматизированную обработку отношений таблиц, проверку типов полей (с помощью самоанализа в таблицах), поддержку псевдонимов таблиц и полей и т. Д.

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

2 голосов
/ 17 марта 2010

Три совета:

  • Использовать хранимые процедуры (чтобы вы могли отделить php от БД)
  • Используйте PDO / MySQLi для подготовленных операторов CALL NEWS_LIST(?, ?)
  • Используйте статический класс для вашей БД. Позволяет получить к нему доступ в любом модуле.
1 голос
/ 28 марта 2010

Не то, чтобы я знал окончательный ответ (и при этом я не думаю, что он существует), но я думал, что могу просто поделиться тем, что у меня есть здесь. Я использую свой собственный «каркас» базы данных, легкий (в настоящее время ~ 1000 строк) и простой в использовании. Моей главной целью было упростить использование sql, а не «прятать» его от программиста (я :). Некоторые примеры:

 // row() is 'query' + 'fetch' in one
 $user = $db->row("select * from users where id=25");

 // the same, injection safe
 $user = $db->row("select * from users where id=?", $_GET['id']);

 // ? placeholders are smart
 $someUsers = $db->rows("select * from users where id IN(?)", array(1, 2, 10));

 // ...and even smarter
 $data = array('name' => 'Joe', 'age' => 50);
 $id = 222;
 $db->exec("update users set ?a where id=?", $data, $id);

 // 'advanced' fetch functions
 $topNames   = $db->vlist("select name from users order by name limit 10");
 $arrayOfIds = $db->nlist("select id from users where age > 90");

 // table() returns a Table Gateway
 $db->table('users')->delete('where id=?', 25);

 // yes, this is safe
 $db->table('users')->insert($_POST);

 // find() returns a Row Gateway object
 $db->table('users')
     ->find('where name=?', 'Joe')
     ->set('status', 'confirmed')
     ->save();
1 голос
/ 27 марта 2010

Ты говоришь как я. Вы видели http://github.com/Xeoncross/micromvc и один файл ORM в http://github.com/Xeoncross/database? Просмотрите мой код, и я думаю, вы найдете то, что ищете.

Решение состоит в том, чтобы использовать всю необработанную мощь некоторых запросов, при этом позволяя ORM и компоновщикам запросов (например, AR для Codeigniter) для других целей.

Оба хороши.

1 голос
/ 17 марта 2010

Сырой SQL по-прежнему для меня победитель, мне нравится контролировать то, что я отправляю на сервер (для таких случаев, как использование индекса, сложные предложения JOIN и т. Д.), Поэтому я обычно держусь подальше от вспомогательных функций.

Вам следует использовать PDO, который уже обеспечивает большую мощность, а если этого недостаточно, вы можете расширить ее (возможно, с помощью своих собственных функций, таких как проверка на попадания в Memcached / APC перед фактическим запросом к базе данных). Вы также можете расширить класс для реализации своих собственных функций SQL, таких как:

function getUser($user_id) {
    return $this->query("SELECT * FROM users WHERE id = " . (int) $user_id);
}

Конечно, от модели вы все равно сможете отправить:

$this->db->query("SELECT * FROM users WHERE id = " . (int) $user_id);

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

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

0 голосов
/ 28 марта 2010

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

Я использую одноэлементный класс MySQL для обработки соединения и самых простых запросов, а также ошибок, которые могут возникнуть.

Отдельные страницы, такие как /users/show/1 (с использованием mod_rewrite), не используют сырой SQL, а представляют собой некоторый облегченный ORM, который работает, как в следующем примере:

$user = $this->db
             ->users
             ->getBy( 'id', $id );

$this->db - это экземпляр класса Database Abstraction с методом __get( $tableName ). Доступ к неопределенному users свойству затем вызывает его. Остальное объясняется само собой; Запрос формируется из аргументов, переданных getBy( ) (экранирование SQL также обрабатывается им), и его результаты возвращаются в виде массива.

Я еще не закончил всю идею, но добавление нового пользователя в базу данных может выглядеть следующим образом:

$user = $this->db
             ->users
             ->new;
$user->id = 2;
$user->name = 'Joe';
$user->save( );

Как я уже сказал, концепция на самом деле не завершена и может иметь (огромные) недостатки в ней. Тем не менее, я думаю, что это может быть легче написать, более безопасно и легче поддерживать, чем простой MySQL. Другими хорошими сторонами всей этой «вещи» было бы то, что она маленькая, поэтому довольно быстрая, а также довольно прямолинейная.

Я знаю, что это не может конкурировать с чрезвычайно мощными ORM и фреймворками, которые уже существуют, но я все еще создаю это по некоторым причинам, упомянутым в одном из моих комментариев выше.

0 голосов
/ 27 марта 2010

Я только что сошел с пути «вспомогательных функций», и единственное, что меня беспокоило, это то, что я продолжал добавлять функции в один файл, который рос и рос с помощью идентичных или похожих или несуществующих функций. Я думаю, что количество строк составило 600, и это, на мой взгляд, слишком много для отдельного файла. Это не оттолкнуло меня от идеи, но я буду более организованным для следующего похода. Я, вероятно, разделю функции db на несколько файлов в соответствии с операцией db (выберите, вставьте и т. Д.).

Поэтому я советую попробовать «вспомогательные функции» и быть как можно более организованным.

Кроме того, я впервые использовал PDO и он мне очень понравился. Это не такая низкая технология, как функции mysql () или такая технология, как мы могли бы упомянуть, но не будем. Я снова буду использовать PDO.

0 голосов
/ 24 марта 2010

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

global $db;
$db = new db;
$db->query ('... sql ...');

является излишним, когда вы можете сделать

db::query ('... sql ...');

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

get_element ($table, $element, $value, $column='id');
get_row ($table, $value, $column='id');

Так что, если вы просто хотите получить имя из таблицы «клиенты», где идентификатор равен 4, вы:

$name = db::get_element ('customers', 'name', 4);

Существуют также сопутствующие функции query_element и query_row, где вы просто передаете ей строку SQL, и она возвращает один элемент / строку.

Наряду с функциями вставки / обновления, например

$array = array (
    'name' => 'bob jones',
    'age' => 28
);
$insert_id = db::insert_array ('customers', $array);

$customer_details = db::get_row ('customers', $insert_id);

$customer_details['age'] = 30;

db:update_array ('customers, $customer_details);

Создает новую строку, извлекает детали обратно, обновляет возраст, а затем перезаписывает его в базу данных.

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

Если вам нужно что-то использовать со сложными объединениями, то всегда лучше создать для него функцию, например, getCustomerInfo (), но если вы просто хотите получить общий поиск по табличным значениям, создание множества пользовательских методов просто увеличивает вероятность ошибок в одном из них. Плюс экранирование данных очень важно - если вы можете использовать не-sql как можно больше и использовать его с помощью нескольких основных функций, вы можете убедиться, что все правильно экранировано довольно легко.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...