Основы взаимодействия PHP с MySQL: от подключения к продвинутым техникам

Раздел: Базы данных PHP -> Основные операции с базой данных

Работа с MySQL в PHP: обзор подходов

Как наиболее эффективно взаимодействовать с MySQL в современном PHP?

Основное решение: PDO (PHP Data Objects)

PDO предоставляет единый интерфейс для работы с разными базами данных, поддерживает подготовленные запросы, которые защищают от SQL-инъекций, и удобную обработку ошибок через исключения.


// Подключение к базе данных с PDO
$host = '127.0.0.1';
$dbname = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';

try {
    $dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "Подключение установлено";
} catch (PDOException $e) {
    die("Ошибка подключения: " . $e->getMessage());
}
  

Php работа с базой mysql (работа с базой данных mysql в php)

Подключение установлено

Типичные проблемы при использовании PDO:

  • Отсутствует расширение PDO и драйвер pdo_mysql. Решение: установить через пакетный менеджер (apt install php-pdo php-mysql) или раскомментировать строки в php.ini.
  • Неверные учётные данные или хост. Решение: проверить параметры подключения, права пользователя.
  • Ошибки кодировки – символы отображаются как '?'. Решение: установить charset utf8mb4 в DSN и в таблицах.

После подключения выполняются запросы. Пример вставки данных с подготовленным запросом:


$sql = "INSERT INTO users (name, email) VALUES (:name, :email)";
$stmt = $pdo->prepare($sql);
$stmt->execute([':name' => 'Иван', ':email' => 'ivan@example.com']);
echo "Добавлена запись с ID: " . $pdo->lastInsertId();
  
Добавлена запись с ID: 1

Выборка данных:


$stmt = $pdo->query("SELECT * FROM users");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo $row['name'] . ' - ' . $row['email'] . "<br>";
}
  
Иван - ivan@example.com

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


$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();
} catch (Exception $e) {
    $pdo->rollBack();
    echo "Ошибка транзакции: " . $e->getMessage();
}
  

Как подключиться к MySQL с помощью расширения mysqli?

Вариант: mysqli (объектно-ориентированный стиль)

mysqli – расширение, ориентированное только на MySQL, но оно также поддерживает подготовленные запросы и может быть удобнее для проектов, работающих исключительно с этой СУБД.


$mysqli = new mysqli('127.0.0.1', 'root', '', 'test');
if ($mysqli->connect_error) {
    die("Ошибка: " . $mysqli->connect_error);
}
echo "Подключение успешно";
  
Подключение успешно

Проблемы при использовании mysqli:

  • Не установлено расширение mysqli. Решение: аналогично PDO, установить php-mysqli.
  • Разница между объектным и процедурным стилем может вызывать путаницу. Рекомендуется придерживаться объектного для лучшей читаемости.

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


$stmt = $mysqli->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param('ss', $name, $email);
$name = 'Петр';
$email = 'petr@example.com';
$stmt->execute();
echo "Добавлена запись с ID: " . $stmt->insert_id;
  
Добавлена запись с ID: 2

Выборка:


$result = $mysqli->query("SELECT * FROM users");
while ($row = $result->fetch_assoc()) {
    echo $row['name'] . ' - ' . $row['email'] . "<br>";
}
  

Как использовать устаревшее расширение mysql_* и почему его не стоит применять?

Вариант: функции mysql_* (устарело с PHP 5.5, удалено в PHP 7.0)

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


$connection = mysql_connect('127.0.0.1', 'root', '');
if (!$connection) {
    die("Ошибка: " . mysql_error());
}
mysql_select_db('test', $connection);
echo "Подключение (устаревшее)";
  
Подключение (устаревшее)

Основные проблемы mysql_* :

  • Функции устарели и удалены – код не будет работать на PHP 7+.
  • Отсутствие поддержки подготовленных запросов – высокий риск SQL-инъекций.
  • Нет объектного интерфейса, код плохо читается.

Если проект ещё использует mysql_*, его необходимо мигрировать на PDO или mysqli. Пример простой выборки (не рекомендуется):


$result = mysql_query("SELECT * FROM users", $connection);
while ($row = mysql_fetch_assoc($result)) {
    echo $row['name'] . "<br>";
}
  

Какие ещё подходы существуют для работы с MySQL в PHP?

Вариант: использование ORM (например, Doctrine, Eloquent)

ORM (Object-Relational Mapping) скрывает детали SQL и позволяет работать с базой данных через объекты. Это удобно для крупных проектов, но добавляет overhead и требует изучения.

Пример (с использованием Eloquent из Laravel, но можно использовать standalone):


// После настройки Capsule Manager
$users = User::where('active', 1)->get();
foreach ($users as $user) {
    echo $user->name;
}
  

Проблемы ORM:

  • Сложность настройки для простых задач.
  • Потеря производительности при сложных запросах.
  • Необходимость изучения синтаксиса ORM.

Расширенные примеры работы с MySQL в PHP

1. Использование PDO с именованными и позиционными плейсхолдерами

Пример

// Именованные плейсхолдеры
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name AND email = :email");
$stmt->execute([':name' => 'Иван', ':email' => 'ivan@example.com']);
$user = $stmt->fetch();

// Позиционные плейсхолдеры (знак вопроса)
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ? AND email = ?");
$stmt->execute(['Иван', 'ivan@example.com']);
$user = $stmt->fetch();
Array
(
    [id] => 1
    [name] => Иван
    [email] => ivan@example.com
)

Разница: именованные читаемее, позиционные компактнее. Выбор зависит от стиля кода.

2. Пакетная вставка множества записей

Пример

$data = [
    ['name' => 'Анна', 'email' => 'anna@test.com'],
    ['name' => 'Борис', 'email' => 'boris@test.com'],
    // ... много записей
];

$pdo->beginTransaction();
try {
    $stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
    foreach ($data as $row) {
        $stmt->execute($row);
    }
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    echo "Ошибка: " . $e->getMessage();
}
echo "Вставлено " . count($data) . " записей";
Вставлено 3 записей (если в массиве 3 элемента)

3. Получение результатов в разных форматах

PDO::FETCH_ASSOC, FETCH_NUM, FETCH_OBJ, FETCH_CLASS и др.

Пример

// FETCH_OBJ - объект
$stmt = $pdo->query("SELECT * FROM users LIMIT 1");
$user = $stmt->fetch(PDO::FETCH_OBJ);
echo $user->name;

// FETCH_CLASS - в объект указанного класса
class User {
    public $name;
    public $email;
}
$stmt->setFetchMode(PDO::FETCH_CLASS, 'User');
$user = $stmt->fetch();
echo $user->name;
Иван (в обоих случаях)

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

Пример

// MySQL хранимая процедура
// CREATE PROCEDURE GetUser(IN uid INT) SELECT * FROM users WHERE id = uid;
$stmt = $pdo->prepare("CALL GetUser(:uid)");
$stmt->execute([':uid' => 1]);
$user = $stmt->fetch();
print_r($user);
Array ( [id] => 1 [name] => Иван ... )

Важно: процедуры могут возвращать несколько результирующих наборов. Для работы с ними используется nextRowset().

5. Запрос с объединением таблиц (JOIN) и группировкой

Пример

$sql = "
    SELECT u.name, COUNT(o.id) as order_count
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    GROUP BY u.id
    HAVING order_count > 0
    ORDER BY order_count DESC
";
$stmt = $pdo->query($sql);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $row) {
    echo $row['name'] . ' сделал ' . $row['order_count'] . ' заказов<br>';
}
Иван сделал 3 заказов
Петр сделал 1 заказов

6. Обработка ошибок: получение информации об исключении

Пример

try {
    $pdo->exec("INSERT INTO wrong_table (id) VALUES (1)");
} catch (PDOException $e) {
    echo "Код ошибки: " . $e->getCode() . "<br>";
    echo "Сообщение: " . $e->getMessage() . "<br>";
    echo "Файл: " . $e->getFile() . " строка " . $e->getLine();
}
Код ошибки: 42S02
Сообщение: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.wrong_table' doesn't exist
Файл: /var/www/example.php строка 5

7. Работа с большими объёмами данных: использование unbuffered query

Пример

// Для mysqli можно отключить буферизацию
$mysqli->real_query("SELECT * FROM big_table");
$result = $mysqli->use_result();
while ($row = $result->fetch_assoc()) {
    // обработка каждой строки без загрузки всего в память
}
// Для PDO аналог - использование MYSQL_ATTR_USE_BUFFERED_QUERY = false при создании соединения

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

Работа с базой данных MySQL в PHP - comments

En
Php работа с базой mysql (php)