Работа с MySQL в PHP: выбор расширения и практические примеры
Основы работы с MySQL в PHP
Как эффективно и безопасно взаимодействовать с базой данных MySQL из PHP?
Самым современным и рекомендуемым решением является расширение PDO (PHP Data Objects). Оно предоставляет единый интерфейс для работы с разными СУБД, поддерживает подготовленные выражения и защиту от SQL-инъекций.
Пример подключения к MySQL через PDO:
<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
$username = 'user';
$password = 'pass';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
$pdo = new PDO($dsn, $username, $password, $options);
echo 'Соединение установлено';
} catch (PDOException $e) {
echo 'Ошибка подключения: ' . $e->getMessage();
}
?>
Mysql functions php (функции mysql в php)
В коде задаётся DSN – строка с именем хоста, именем базы и кодировкой. Опции включают режим ошибок (исключения) и способ извлечения данных (ассоциативный массив). Блок try/catch обрабатывает неудачное подключение.
Типичные ошибки:
- Неверные учётные данные – ловится исключением PDOException.
- Отсутствие расширения PDO или драйвера mysql – проверяется через extension_loaded('pdo_mysql').
- Проблемы с кодировкой – указывать charset в DSN обязательно (utf8mb4 для эмодзи).
Как выполнять запросы с помощью PDO?
Для простых запросов без пользовательских данных используется метод query(). Пример выборки всех записей:
$stmt = $pdo->query('SELECT * FROM users');
$users = $stmt->fetchAll();
foreach ($users as $user) {
echo $user['name'] . '<br>';
}
Для запросов с параметрами обязательны подготовленные выражения – метод prepare() и execute(). Это предотвращает SQL-инъекции.
$sql = 'SELECT * FROM users WHERE email = :email';
$stmt = $pdo->prepare($sql);
$stmt->execute(['email' => 'user@example.com']);
$user = $stmt->fetch();
Именованные плейсхолдеры (:email) более читаемы. Возможна также позиционная подстановка (?).
Проблемы:
- Забыли выполнить prepare – прямой подстановкой данных увеличивается риск инъекций.
- Несовпадение типов (например, передача строки вместо числа) – PDO может привести к неожиданным ошибкам, лучше явно указывать типы через bindValue().
Как работать с MySQL через расширение mysqli?
mysqli – альтернатива, специфичная только для MySQL. Доступно два стиля: объектно-ориентированный и процедурный.
Объектный стиль:
$mysqli = new mysqli('localhost', 'user', 'pass', 'testdb');
if ($mysqli->connect_error) {
die('Ошибка: ' . $mysqli->connect_error);
}
$result = $mysqli->query('SELECT * FROM users');
while ($row = $result->fetch_assoc()) {
echo $row['name'];
}
Процедурный стиль:
$link = mysqli_connect('localhost', 'user', 'pass', 'testdb');
if (!$link) {
die('Ошибка: ' . mysqli_connect_error());
}
$result = mysqli_query($link, 'SELECT * FROM users');
while ($row = mysqli_fetch_assoc($result)) {
echo $row['name'];
}
Подготовленные выражения в mysqli:
$stmt = $mysqli->prepare('INSERT INTO users (name, email) VALUES (?, ?)');
$stmt->bind_param('ss', $name, $email);
$name = 'Alex';
$email = 'alex@example.com';
$stmt->execute();
Строка 'ss' означает два строковых параметра. Доступны типы: i (int), d (double), s (string), b (blob).
Ошибки и ограничения:
- Не забыть проверить connect_error – при ошибке объект может быть частично создан.
- Процедурный стиль сложнее поддерживать, но быстрее пишется в простых скриптах.
- Подготовленные выражения в mysqli требуют явного указания типов, что может запутать.
Как использовать устаревшее расширение mysql_*?
Расширение mysql_* удалено из PHP 7.0 и не должно применяться в новых проектах. Пример (только для справки):
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
$result = mysql_query('SELECT * FROM users');
while ($row = mysql_fetch_assoc($result)) {
echo $row['name'];
}
Проблемы:
- Функции объявлены устаревшими и удалены, нет поддержки подготовленных выражений.
- Нет объектной модели, только процедурный стиль.
- Высокая вероятность SQL-инъекций.
Случаи использования: только при работе с легаси-кодом на PHP 5.x. Для новых разработок выбирают PDO или mysqli.
Расширенные примеры работы с MySQL в PHP
Пример 1. Транзакции в PDO
Перевод денег между счетами требует атомарности. PDO поддерживает транзакции.
<?php
$pdo->beginTransaction();
try {
$pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
$pdo->exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
$pdo->commit();
echo 'Перевод выполнен успешно';
} catch (Exception $e) {
$pdo->rollBack();
echo 'Ошибка: ' . $e->getMessage();
}
?>
Перевод выполнен успешно (при условии, что начальные балансы позволяют списание)
Пример 2. Массовая вставка через подготовленные выражения
Вставка нескольких строк одним запросом с использованием одного подготовленного выражения.
<?php
$data = [
['Anna', 'anna@example.com'],
['Bob', 'bob@example.com'],
['Charlie', 'charlie@example.com']
];
$sql = 'INSERT INTO users (name, email) VALUES (:name, :email)';
$stmt = $pdo->prepare($sql);
foreach ($data as $row) {
$stmt->execute(['name' => $row[0], 'email' => $row[1]]);
}
echo 'Вставлено ' . count($data) . ' записей';
?>
Вставлено 3 записи
Пример 3. Вызов хранимой процедуры с выходными параметрами в mysqli
<?php
$mysqli = new mysqli('localhost', 'user', 'pass', 'testdb');
$stmt = $mysqli->prepare('CALL get_user_count(?)');
$stmt->bind_param('i', $dummy);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
echo 'Количество пользователей: ' . $row['cnt'];
?>
Предполагается, что процедура get_user_count возвращает результат как SELECT.
Пример 4. Обработка результатов с курсором (PDO)
<?php
$stmt = $pdo->prepare('SELECT * FROM logs ORDER BY id', [
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL
]);
$stmt->execute();
// Перемещение по результатам без извлечения всех строк сразу
$row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST);
echo 'Последняя запись: ' . $row['message'];
?>
Пример 5. Динамическое построение запроса (безопасное) с помощью IN()
<?php
$ids = [1, 2, 3, 5];
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$sql = "SELECT * FROM products WHERE id IN ($placeholders)";
$stmt = $pdo->prepare($sql);
$stmt->execute($ids);
$products = $stmt->fetchAll();
foreach ($products as $p) {
echo $p['name'] . '<br>';
}
?>