PHP и SQL: руководство по работе с базами данных

Раздел: -> Работа с базами данных

Основы работы PHP с SQL

Как обеспечить безопасное и гибкое взаимодействие PHP с SQL?

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

$dsn = 'mysql:host=localhost;dbname=test;charset=utf8';
$user = 'root';
$password = '';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
    $pdo = new PDO($dsn, $user, $password, $options);
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
    $stmt->execute(['email' => 'user@example.com']);
    $user = $stmt->fetch();
} catch (PDOException $e) {
    die('Ошибка подключения: ' . $e->getMessage());
}

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

Типичная ошибка: забыть указать кодировку в DSN, что приводит к ошибкам с кириллицей. Решение: добавить charset=utf8.

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

Расширение mysqli предназначено исключительно для MySQL. Оно также поддерживает подготовленные запросы, но синтаксис отличается от PDO.

$mysqli = new mysqli('localhost', 'root', '', 'test');
if ($mysqli->connect_error) {
    die('Ошибка подключения: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ?');
$stmt->bind_param('s', $email);
$email = 'user@example.com';
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();

В этом варианте используется объектно-ориентированный интерфейс. Подготовленный запрос требует явного связывания параметров с помощью bind_param. Ошибки подключения проверяются через свойство connect_error.

Частая проблема: путаница между процедурным и объектным стилем mysqli. Например, mysqli_connect возвращает ресурс, а не объект. Рекомендуется использовать единый стиль. Также при использовании get_result() может потребоваться установка драйвера mysqlnd.

Как абстрагироваться от конкретной СУБД с помощью ORM?

ORM (Object-Relational Mapping) упрощает работу, позволяя оперировать объектами вместо SQL. Пример с популярной библиотекой Eloquent (часть Laravel).

use illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule;
$capsule->addConnection([
    'driver' => 'mysql',
    'host' => 'localhost',
    'database' => 'test',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
]);
$capsule->bootEloquent();

$users = User::where('email', 'user@example.com')->get();

Eloquent автоматически экранирует параметры и поддерживает миграции. Однако для небольших проектов ORM может быть избыточным и добавлять лишние накладные расходы.

Ошибка: неправильная настройка соединения или отсутствие автозагрузки классов. Решение: использовать Composer и правильно подключать автозагрузчик.

Расширенные примеры взаимодействия PHP с SQL

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

Пример
try {
    $pdo->beginTransaction();
    $stmt = $pdo->prepare('UPDATE accounts SET balance = balance - :amount WHERE id = :from');
    $stmt->execute(['amount' => 100, 'from' => 1]);
    $stmt = $pdo->prepare('UPDATE accounts SET balance = balance + :amount WHERE id = :to');
    $stmt->execute(['amount' => 100, 'to' => 2]);
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    echo 'Ошибка: ' . $e->getMessage();
}
Результат: баланс счета 1 уменьшен на 100, счета 2 увеличен на 100. При ошибке все изменения откатываются.

Работа с SQLite и PostgreSQL через PDO

Пример
// SQLite
$dsn = 'sqlite:/path/to/database.db';
$pdo = new PDO($dsn);
$pdo->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');

// PostgreSQL
$dsn = 'pgsql:host=localhost;dbname=test';
$pdo = new PDO($dsn, 'user', 'pass');
$stmt = $pdo->query('SELECT NOW()');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo $row['now'];
Результат: для SQLite создается таблица, для PostgreSQL выводится текущее время сервера.

Пагинация с использованием PDO

Пример
$page = 1;
$perPage = 10;
$offset = ($page - 1) * $perPage;
$stmt = $pdo->prepare('SELECT * FROM articles LIMIT :limit OFFSET :offset');
$stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$articles = $stmt->fetchAll();
Результат: массив из 10 записей первой страницы.

Разные режимы выборки fetch mode

Пример
$stmt = $pdo->query('SELECT id, name FROM users');

// Ассоциативный массив
$assoc = $stmt->fetchAll(PDO::FETCH_ASSOC);

// Объект stdClass
$objects = $stmt->fetchAll(PDO::FETCH_OBJ);

// Один столбец в массив
$names = $stmt->fetchAll(PDO::FETCH_COLUMN, 1);

// Пара ключ-значение
$pairs = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
Результат: различные форматы данных для удобной обработки.

PHP и SQL - comments

En
Php sql (php)