Языки программирования

PHP: PDO, работа с MySQL

PDO – PHP Data Objects – это прослойка, которая предлагает универсальный способ работы с несколькими базами данных.
Смысл PDO в том, что отсутствует привязка к конкретной системе управления базами данных. PDO поддерживает СУБД: MySQL, PostgreSQL, SQLite, Oracle, Microsoft SQL Server и другие.

Почему стоит использовать PDO

Функции mysql в PHP для работы с БД давно уже устарели, на сегодняшний день желательно использовать mysqli или PDO (PHP Data Objects). Кроме того, mysqli — эта библиотека, которая по большому счёту, не предназначена для использования напрямую в коде.
При работе с mysqli следует также помнить об обеспечении безопасности вашего приложения, в частности о защите от SQL-инъекций. В случае использования PDO (с его подготовленными запросами), такая защита идёт уже «из коробки», главное правильно применить необходимые методы.

Подключение

Способы подключения к разным СУБД могут незначительно отличаться. Рассмотрим примеры подключения к наиболее популярным из них:
try {  
  # MS SQL Server и Sybase через PDO_DBLIB  
  $DBH = new PDO("mssql:host=$host;dbname=$dbname", $user, $pass);  
  $DBH = new PDO("sybase:host=$host;dbname=$dbname", $user, $pass);  
  
  # MySQL через PDO_MYSQL  
  $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);  
  
  # SQLite  
  $DBH = new PDO("sqlite:my/database/path/database.db");  
}  
catch(PDOException $e) {  
    echo $e->getMessage();  
}
В блок try/catch – всегда стоит оборачивать все PDO-операции и использовать механизм исключений.

Исключения и PDO

PDO умеет выбрасывать исключения при ошибках, поэтому все должно находиться в блоке try/catch. Сразу после создания подключения, PDO можно перевести в любой из трех режимов ошибок:

PDO::ERRMODE_SILENT

Это режим по умолчанию. Примерно то же самое, что используется для отлавливания ошибок в расширениях mysql и mysqli. Следующие два режима больше подходят для DRY программирования.

PDO::ERRMODE_WARNING

Этот режим вызовет стандартный Warning и позволит скрипту продолжить выполнение. Удобен при отладке.

PDO::ERRMODE_EXCEPTION

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

PDO и MySQL

Рассмотрим пример подключения базы данных MYSQL
// Создаем константы
define("HOST", "localhost");
define("DBNAME", "сюда вносим имя БД");
define("DBUSER", "сюда вносим имя пользователя от БД");
define("DBPASSWORD", "сюда вносим пароль пользователя от БД");

// Подключаемся к базе данных через PDO
try {
	$mysql = new PDO('mysql:host=' . HOST . ';dbname=' . DBNAME, DBUSER, DBPASSWORD,
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
} catch (PDOException $e) {
	print "Возникла ошибка соединения!: " . $e->getMessage() . "<br/>";
	die();
}

Подготовленные и прямые запросы

В PDO существует два способа выполнения запросов:

Прямые запросы

query() используется для операторов, которые не вносят изменения, например SELECT. Возвращает объект PDOStatemnt, из которого с помощью методов fetch() или fetchAll извлекаются результаты запроса.
exec() используется для операторов INSERT, DELETE, UPDATE. Возвращает число обработанных запросом строк.
Прямые запросы используются только в том случае, если в запросе отсутствуют переменные и есть уверенность, что запрос безопасен и правильно экранирован.
$stmt = $db->query("SELECT * FROM categories");
while ($row = $stmt->fetch())
{
  echo '<pre>';
  print_r($row);
}

Подготовленные запросы

Если же в запрос передаётся хотя бы одна переменная, то этот запрос в обязательном порядке должен выполняться только через подготовленные выражения.
Это обычный SQL запрос, в котором вместо переменной ставится специальный маркер — плейсхолдер. PDO поддерживает позиционные плейсхолдеры (?), для которых важен порядок передаваемых переменных, и именованные (:name), для которых порядок не важен. Примеры:
$sql = "SELECT name FROM categories WHERE id = ?";
$sql = "SELECT name FROM categories WHERE name = :name";
Чтобы выполнить такой запрос, сначала его надо подготовить с помощью метода prepare(). Она также возвращает PDO statement, но ещё без данных.

Чтобы их получить, надо исполнить этот запрос, предварительно передав в него наши переменные. Передать можно двумя способами: Чаще всего можно просто выполнить метод execute(), передав ему массив с переменными:
$stmt = $pdo->prepare("SELECT `name` FROM categories WHERE `id` = ?");
$stmt->execute([$id]);
 
$stmt = $pdo->prepare("SELECT `name` FROM categories WHERE `name` = :name");
$stmt->execute(['name' => $name]);
Далее мы рассмотрим методы PDO для получения данных.

Метод fetch()

Метод fetch() служит для последовательного получения строк из БД. Этот метод является аналогом функции mysq_fetch_array() и ей подобных, но действует по-другому: вместо множества функций здесь используется одна, но ее поведение задается переданным параметром. Пример:
$id = 1;
$stmt = $db->prepare("SELECT * FROM categories WHERE `id` = ?");
$stmt->execute([$id]);
while ($row = $stmt->fetch(PDO::FETCH_LAZY)) {
    echo 'Category name: '.$row->name;
}

Метод fetchColumn()

Также у PDO есть метод для получения значения единственной колонки. Очень удобно, если мы запрашиваем только одно поле — в этом случае значительно сокращается количество кода. Пример:
$id = 1;
$stmt = $db->prepare("SELECT `name` FROM categories WHERE `id` = ?");
$stmt->execute([$id]);
$name = $stmt->fetchColumn();
echo 'Category name: '.$name;

Метод fetchAll()

PDOStatement::fetchAll — Возвращает массив, содержащий все строки результирующего набора. Пример:
$data = $db->query("SELECT * FROM categories")->fetchAll(PDO::FETCH_ASSOC);
foreach ($data as $k => $v){
  echo 'Category name: '.$v['name'].'<br>';
}

Insert, Update и delete

Вставка новых, обновление и удаление существующих данных являются одними из наиболее частых операций с БД. В случае с PDO этот процесс обычно состоит из двух шагов. Рассмотрим примеры:
// Добавление записей
$name = 'Новая категория';
$query = "INSERT INTO `categories` (`name`) VALUES (:name)";
$params = [
    ':name' => $name
];
$stmt = $pdo->prepare($query);
$stmt->execute($params);
// Изменение записей
$id = 1;
$name = 'Изменённая запись';
$query = "UPDATE `categories` SET `name` = :name WHERE `id` = :id";
$params = [
    ':id' => $id,
    ':name' => $name
];
$stmt = $pdo->prepare($query);
$stmt->execute($params);
// Удаление записей
$id = 1;
$query = "DELETE FROM `categories` WHERE `id` = ?";
$params = [$id];
$stmt = $pdo->prepare($query);
$stmt->execute($params);
Самоучитель по PHP