Лучший курс действий для вас будет зависеть от того, как вы подходите к доступу к данным. Вы можете выбрать один из трех подходов:
- Использовать хранимые процедуры
- Сохраняйте запросы в коде (но поместите все свои запросы в функции и исправьте все, чтобы использовать параметры PDO, как упоминалось ранее)
- Используйте инструмент ORM
Если вы хотите передать свой собственный необработанный SQL в ядро базы данных, то хранимые процедуры - это то, что вам нужно, если все, что вам нужно, это извлечь необработанный SQL из вашего кода PHP, но сохранить его относительно неизменным. Хранимые процедуры против дебатов по сырому SQL - это что-то вроде священной войны, но К. Скотт Аллен делает отличное замечание - хотя и однозначно - в статье о версиях баз данных :
Во-вторых, хранимые процедуры перестали быть в моих глазах. Я приехал из школы идеологической обработки WinDNA, которая сказала, что хранимые процедуры должны использоваться все время. Сегодня я рассматриваю хранимые процедуры как уровень API для базы данных. Это хорошо, если вам нужен уровень API на уровне базы данных, но я вижу множество приложений, которые несут накладные расходы на создание и поддержку дополнительного уровня API, который им не нужен. В этих приложениях хранимые процедуры являются большим бременем, чем выгодой.
Я склонен не использовать хранимые процедуры. Я работал над проектами, в которых БД имеет API, предоставляемый через хранимые процедуры, но хранимые процедуры могут накладывать некоторые собственные ограничения, и в этих проектах все , в различной степени, используется динамически генерируемый необработанный SQL в код для доступа к БД.
Наличие уровня API в БД позволяет лучше разграничить обязанности между командой БД и командой разработчиков за счет некоторой гибкости, которую вы имели бы, если бы запрос хранился в коде, однако проекты PHP менее вероятны иметь достаточно значительные команды, чтобы извлечь выгоду из этого разграничения.
Концептуально, вы, вероятно, должны иметь версию вашей базы данных. С практической точки зрения, однако, у вас гораздо больше шансов на то, что ваш код будет версионирован, чем на базе данных. Скорее всего, вы изменяете свои запросы, когда вносите изменения в свой код, но если вы изменяете запросы в хранимых процедурах, хранящихся в базе данных, вы, вероятно, не будете проверять их при регистрации кода, и вы потеряете многие из преимуществ управления версиями для значительной области вашего приложения.
Независимо от того, решите вы или нет использовать хранимые процедуры, вы должны как минимум гарантировать, что каждая операция базы данных хранится в независимой функции, а не встраивается в каждый из сценариев вашей страницы - по сути, уровень API для ваша БД, которая поддерживается и поддерживается с вашим кодом. Если вы используете хранимые процедуры, это фактически означает, что у вас есть два уровня API для вашей БД, один с кодом и один с БД, что может показаться вам излишне усложняющим, если в вашем проекте нет отдельных команд. Я конечно делаю.
Если проблема связана с аккуратностью кода, есть способы сделать код с застрявшим в нем SQL более презентабельным, и класс UserManager, показанный ниже, является хорошим способом для начала - класс содержит только запросы, относящиеся к пользователю 'таблица, каждый запрос имеет свой собственный метод в классе, и запросы вставляются в операторы prepare и форматируются так, как если бы вы форматировали их в хранимой процедуре.
// UserManager.php:
class UserManager
{
function getUsers()
{
$pdo = new PDO(...);
$stmt = $pdo->prepare('
SELECT u.userId as id,
u.userName,
g.groupId,
g.groupName
FROM user u
INNER JOIN group g
ON u.groupId = g.groupId
ORDER BY u.userName, g.groupName
');
// iterate over result and prepare return value
}
function getUser($id) {
// db code here
}
}
// index.php:
require_once("UserManager.php");
$um = new UserManager;
$users = $um->getUsers();
foreach ($users as $user) echo $user['name'];
Однако, если ваши запросы очень похожи, но у вас есть огромное количество перестановок в условиях запроса, таких как сложное разбиение на страницы, сортировка, фильтрация и т. Д., Инструмент Object / Relational mapper, вероятно, подходит, хотя процесс капитального ремонта Ваш существующий код для использования инструмента может быть довольно сложным.
Если вы решите исследовать инструменты ORM, вам следует обратиться к Propel , компоненту ActiveRecord Yii или PHP ORM королевского папы, Doctrine, Каждый из них дает вам возможность программно создавать запросы к вашей базе данных со всеми видами сложной логики. Doctrine - это наиболее полнофункциональный инструмент, позволяющий вам создавать шаблоны базы данных с такими вещами, как шаблон дерева вложенных наборов из коробки.
С точки зрения производительности хранимые процедуры являются самыми быстрыми, но обычно не намного по сравнению с raw sql. Инструменты ORM могут оказать значительное влияние на производительность по ряду причин - неэффективные или избыточные запросы, огромный ввод-вывод файлов при загрузке библиотек ORM при каждом запросе, динамическая генерация SQL для каждого запроса ... все эти вещи могут оказать влияние, но использование инструмента ORM может значительно увеличить доступную вам мощность при гораздо меньшем объеме кода, чем создание собственного уровня БД с ручными запросами.
Гари Ричардсон абсолютно прав, хотя, если вы собираетесь продолжать использовать SQL в своем коде, вы всегда должны использовать подготовленные операторы PDO для обработки параметров независимо от того, используете ли вы запрос или хранимая процедура. Санация ввода выполняется для вас с помощью PDO.
// optional
$attrs = array(PDO::ATTR_PERSISTENT => true);
// create the PDO object
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass", $attrs);
// also optional, but it makes PDO raise exceptions instead of
// PHP errors which are far more useful for debugging
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('INSERT INTO venue(venueName, regionId) VALUES(:venueName, :regionId)');
$stmt->bindValue(":venueName", "test");
$stmt->bindValue(":regionId", 1);
$stmt->execute();
$lastInsertId = $pdo->lastInsertId();
var_dump($lastInsertId);
Предупреждение: при условии, что идентификатор равен 1, вышеприведенный скрипт выдаст string(1) "1"
. PDO->lastInsertId()
возвращает идентификатор в виде строки независимо от того, является ли фактический столбец целым числом или нет. Это, вероятно, никогда не будет проблемой для вас, так как PHP выполняет приведение строк к целым числам автоматически.
Будет выведено bool(true)
:
// regular equality test
var_dump($lastInsertId == 1);
но если у вас есть код, который ожидает, что значение будет целым числом, например, is_int или PHP "действительно, действительно, на 100% равно оператору" :
var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);
Вы можете столкнуться с некоторыми проблемами.
Редактировать: Хорошее обсуждение хранимых процедур здесь