Обзор популярных расширений MySQL в PHP

Раздел: Веб-разработка -> Расширения и функции MySQL

Обзор расширений MySQL для PHP

Для работы с базами данных MySQL в PHP исторически использовалось несколько расширений: устаревшее mysql, более современное mysqli и универсальное PDO. Каждое из них имеет свои особенности, сценарии применения и уровень безопасности. Далее рассмотрим основной рекомендуемый вариант, а затем альтернативы.

Какое расширение обеспечивает безопасную и гибкую работу с MySQL в PHP?

Наиболее эффективным решением является PDO (PHP Data Objects). Оно поддерживает не только MySQL, но и другие СУБД, предоставляя единый интерфейс. Подготовленные выражения (prepared statements) защищают от SQL-инъекций. Пример подключения и выполнения простого запроса:


<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$user = 'root';
$pass = '';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
    $pdo = new PDO($dsn, $user, $pass, $options);
    $stmt = $pdo->query('SELECT * FROM users');
    $users = $stmt->fetchAll();
    print_r($users);
} catch (PDOException $e) {
    echo 'Ошибка подключения: ' . $e->getMessage();
}
?>
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Иван
        )
)

Частая проблема: отсутствие драйвера PDO для MySQL (php_pdo_mysql). Ошибка: PDOException: could not find driver. Решение: раскомментировать строку extension=pdo_mysql в php.ini и перезапустить веб-сервер.

Другая ошибка: неверный DSN (например, неправильный хост или имя базы). При использовании режима исключений PDO выбросит PDOException с подробным сообщением. Рекомендуется всегда оборачивать подключение в try-catch.

PDO позволяет использовать подготовленные выражения с плейсхолдерами (:name) или вопросительными знаками. Это снижает риск инъекций. Пример вставки данных:


$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute([':name' => 'Мария', ':email' => 'maria@example.com']);
echo 'Добавлен ID: ' . $pdo->lastInsertId();

Такое расширение удобно при проектах, где требуется поддержка нескольких баз данных или миграция на другую СУБД.

Как использовать функциональность MySQLi для работы с MySQL?

Расширение mysqli (MySQL Improved) является преемником устаревшего mysql. Оно предоставляет объектный и процедурный стиль. Основное преимущество - полная поддержка всех возможностей MySQL 5.x и 8.x (хранимые процедуры, множественные запросы, транзакции). Пример подключения и выборки в объектном стиле:


<?php
$mysqli = new mysqli('localhost', 'root', '', 'testdb');
if ($mysqli->connect_error) {
    die('Ошибка соединения: ' . $mysqli->connect_error);
}
$result = $mysqli->query('SELECT * FROM users');
$users = $result->fetch_all(MYSQLI_ASSOC);
print_r($users);
$result->free();
$mysqli->close();
?>

Проблема: слишком доверчивые запросы с конкатенацией строк могут привести к SQL-инъекциям. Решение: использовать подготовленные выражения с bind_param.


$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ?');
$stmt->bind_param('s', $email);
$email = 'test@example.com';
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();

Ошибка: неправильная проверка результата query() - если запрос неуспешен, возвращается false. Следует явно проверять if (!$result) и выводить ошибку через $mysqli->error.

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

Как работало раннее расширение mysql?

Расширение mysql (без i) было доступно в PHP 4 и 5, но с PHP 7 полностью удалено. Оно не поддерживает подготовленные выражения, используется процедурный стиль. Пример:


<?php
$link = mysql_connect('localhost', 'root', '');
if (!$link) {
    die('Ошибка: ' . mysql_error());
}
mysql_select_db('testdb', $link);
$result = mysql_query('SELECT * FROM users', $link);
while ($row = mysql_fetch_assoc($result)) {
    echo $row['name'];
}
mysql_close($link);
?>

Главная проблема: отсутствие защиты от SQL-инъекций - все данные нужно экранировать вручную с помощью mysql_real_escape_string(), что легко забыть. Кроме того, расширение не поддерживает транзакции и новые возможности MySQL. Использовать его в новых проектах категорически не рекомендуется.

Типичная ошибка: устаревший код на старых серверах выдаёт Fatal error: Call to undefined function mysql_connect(). Решение: обновить PHP до версии, где есть mysqli или PDO, и переписать код.

Расширение mysql можно встретить только в легаси-проектах, где требуется минимальная поддержка до миграции.

Расширенные примеры использования расширений MySQL в PHP

Транзакции с PDO

Транзакции позволяют выполнить несколько запросов атомарно. При ошибке изменения откатываются. Пример:

Пример

<?php
$dsn = 'mysql:host=localhost;dbname=bank;charset=utf8mb4';
$pdo = new PDO($dsn, 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
try {
    $pdo->beginTransaction();
    $pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
    $pdo->exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    echo 'Ошибка транзакции: ' . $e->getMessage();
}
?>
(Выполнение без ошибок - изменения применены; при ошибке - откат)

Работа с хранимыми процедурами в MySQLi

MySQLi позволяет вызывать хранимые процедуры и получать множественные наборы результатов. Пример простой процедуры:

Пример

-- SQL: CREATE PROCEDURE get_users_by_status(IN status VARCHAR(10)) BEGIN SELECT * FROM users WHERE status = status; END;
<?php
$mysqli = new mysqli(...);
$stmt = $mysqli->prepare('CALL get_users_by_status(?)');
$stmt->bind_param('s', $status);
$status = 'active';
$stmt->execute();
$result = $stmt->get_result();
$activeUsers = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
$mysqli->close();
?>

Использование PDO с разными СУБД

PDO даёт возможность переключить базу данных простой заменой DSN. Например, с MySQL на PostgreSQL:

Пример

$dsn_mysql = 'mysql:host=localhost;dbname=mydb';
$dsn_pgsql = 'pgsql:host=localhost;dbname=mydb';
$pdo = new PDO($dsn_mysql, ...);
// Код с подготовленными выражениями остаётся тем же

Это упрощает разработку приложений, которые должны работать с разными СУБД без переписывания кода.

Пример массовой вставки с PDO и транзакцией

Пример

$pdo->beginTransaction();
$stmt = $pdo->prepare('INSERT INTO logs (message, level) VALUES (:msg, :lvl)');
$entries = [
    ['msg' => 'Пользователь вошёл', 'lvl' => 'info'],
    ['msg' => 'Ошибка входа', 'lvl' => 'error'],
];
foreach ($entries as $entry) {
    $stmt->execute([':msg' => $entry['msg'], ':lvl' => $entry['lvl']]);
}
$pdo->commit();
echo 'Вставлено записей: ' . count($entries);
Вставлено записей: 2

Обработка ошибок при множественных запросах в MySQLi

MySQLi поддерживает выполнение нескольких запросов через multi_query(). Важно корректно обрабатывать каждый результат:

Пример

$mysqli->multi_query('SELECT 1; SELECT 2;');
do {
    if ($result = $mysqli->store_result()) {
        $row = $result->fetch_row();
        echo 'Результат: ' . $row[0] . '<br>';
        $result->free();
    }
} while ($mysqli->more_results() && $mysqli->next_result());
if ($mysqli->error) {
    echo 'Ошибка: ' . $mysqli->error;
}
Результат: 1
Результат: 2

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

Расширение MySQL для PHP - comments

En
расширение php mysql (php)