Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

MySQLi

Кроме PDO, в PHP есть второе расширение для баз данных — MySQLi. Оно работает только с MySQL и MariaDB, зато знакомо почти каждому: на нём написано огромное количество существующих сайтов. Понимать оба способа нужно, чтобы читать чужой код.

Примерам этого урока нужен сервер MySQL, поэтому здесь они не запускаются.

Старые функции mysql_

В старых учебниках встречаются mysql_connect() и mysql_query(). Этих функций больше нет: их удалили из PHP в версии 7. Их современная замена — MySQLi, буква «i» означает «improved», улучшенный.

Подключение

Объект mysqli получает адрес сервера, имя пользователя, пароль и название базы:

<?php
 
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
 
$db = new mysqli('localhost', 'root', 'secret', 'shop');
$db->set_charset('utf8mb4');

Первая строка включает исключения при ошибках. Кодировка utf8mb4 нужна, чтобы правильно хранить кириллицу и эмодзи.

Простой запрос

Метод query() выполняет запрос без параметров. Строки результата читают методом fetch_assoc():

<?php
 
$db = new mysqli('localhost', 'root', 'secret', 'shop');
 
$result = $db->query('SELECT id, title FROM products ORDER BY id');
 
while ($row = $result->fetch_assoc()) {
    echo $row['id'], ': ', $row['title'], "\n";
}

fetch_all(MYSQLI_ASSOC) возвращает сразу все строки массивом.

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

Данные от пользователя передают только через подготовленный запрос. В MySQLi у значений указывают типы: s — строка, i — целое число, d — дробное:

<?php
 
$db = new mysqli('localhost', 'root', 'secret', 'shop');
 
$statement = $db->prepare('SELECT title FROM products WHERE price < ? AND category = ?');
$statement->bind_param('is', $maxPrice, $category);
 
$maxPrice = 300;
$category = 'drinks';
$statement->execute();
 
$rows = $statement->get_result()->fetch_all(MYSQLI_ASSOC);

Начиная с PHP 8.1 значения можно передать прямо в execute(), как в PDO: $statement->execute([300, 'drinks']).

Добавление записи

<?php
 
$db = new mysqli('localhost', 'root', 'secret', 'shop');
 
$statement = $db->prepare('INSERT INTO products (title, price) VALUES (?, ?)');
$statement->execute(['Чай', 250]);
 
echo $db->insert_id;       // идентификатор новой строки
echo $db->affected_rows;   // число затронутых строк

Процедурный стиль

У каждого метода MySQLi есть двойник-функция. Этот стиль чаще всего встречается в старом коде:

<?php
 
$db = mysqli_connect('localhost', 'root', 'secret', 'shop');
 
$result = mysqli_query($db, 'SELECT title FROM products');
 
while ($row = mysqli_fetch_assoc($result)) {
    echo $row['title'], "\n";
}
 
mysqli_close($db);

Оба стиля делают одно и то же; в новом коде используют объектный.

MySQLi или PDO

MySQLiPDO
Базы данныхТолько MySQL и MariaDBMySQL, PostgreSQL, SQLite и другие
Именованные параметры :nameНетДа
Процедурный стильДаНет
Возможности, специфичные для MySQLБольшеМеньше

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

Частая ошибка

Самая опасная привычка из старого кода — вставлять переменные прямо в текст запроса. Это открывает дорогу SQL-инъекции:

<?php
 
$db = new mysqli('localhost', 'root', 'secret', 'shop');
$name = $_GET['name'] ?? '';
 
// Опасно: $db->query("SELECT * FROM users WHERE name = '$name'");
 
$statement = $db->prepare('SELECT * FROM users WHERE name = ?');
$statement->execute([$name]);

Функция mysqli_real_escape_string(), которой раньше «обезвреживали» значения, защищает не во всех случаях. Используйте подготовленные запросы.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.