Чтение записей из базы данных в PHP
Основные подходы к получению данных из базы данных в PHP
Наиболее эффективным речением для извлечения данных из базы данных в современных PHP-приложениях является использование расширения PDO (PHP Data Objects) с подготовленными запросами. Этот способ обеспечивает защиту от SQL-инъекций, поддержку различных СУБД (MySQL, PostgreSQL, SQLite и других) и удобный синтаксис. Пример базового получения всех строк из таблицы users:
<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
$user = 'root';
$password = '';
try {
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT id, name, email FROM users WHERE active = :active');
$stmt->execute([':active' => 1]);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($users as $user) {
echo $user['name'] . ' - ' . $user['email'] . "<br>";
}
} catch (PDOException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
?>
Php данные из бд (получение данных из базы данных php)
Пояснение:
- Строка DSN задаёт тип базы данных, хост, имя БД и кодировку.
- Подготовленный запрос (prepare) отделяет логику SQL от данных.
- Метод execute принимает массив с параметрами, подставляя их безопасно.
- fetchAll(PDO::FETCH_ASSOC) возвращает все строки в виде ассоциативных массивов.
Типичные проблемы и их решение:
- Ошибка подключения: Проверить правильность DSN, имя пользователя и пароль. Включить исключения при создании PDO.
- SQL-инъекция при прямом использовании query: Избегать конкатенации значений в SQL. Всегда использовать подготовленные запросы.
- Некорректные типы данных в bindParam: Указывать тип параметра (PDO::PARAM_INT и т.д.) при явной привязке.
Как получить данные с помощью mysqli в процедурном стиле?
Этот вариант подходит для старых проектов или быстрых скриптов, где нет необходимости в поддержке разных СУБД. Пример:
<?php
$connection = mysqli_connect('localhost', 'root', '', 'testdb');
if (!$connection) {
die('Ошибка подключения: ' . mysqli_connect_error());
}
$result = mysqli_query($connection, "SELECT id, name FROM users WHERE active = 1");
if ($result) {
while ($row = mysqli_fetch_assoc($result)) {
echo $row['name'] . "<br>";
}
mysqli_free_result($result);
} else {
echo 'Ошибка запроса: ' . mysqli_error($connection);
}
mysqli_close($connection);
?>
Shows php name (показ имени в php)
Проблема:
Прямое использование mysqli_query с конкатенацией данных приводит к SQL-инъекциям. Для защиты необходимо применять mysqli_prepare и mysqli_stmt_bind_param.
Как использовать объектно-ориентированный mysqli?
Более современный синтаксис в рамках расширения mysqli:
<?php
$mysqli = new mysqli('localhost', 'root', '', 'testdb');
if ($mysqli->connect_error) {
die('Ошибка: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('SELECT id, name FROM users WHERE active = ?');
$stmt->bind_param('i', $active);
$active = 1;
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
echo $row['name'] . "<br>";
}
$stmt->close();
$mysqli->close();
?>
вывод mysql php (вывод данных из mysql в php)
Здесь bind_param с типом 'i' (integer) предотвращает инъекции.
Как получить результат в виде объекта, а не массива?
Для PDO можно использовать fetch(PDO::FETCH_OBJ) или fetchAll(PDO::FETCH_OBJ). Для mysqli – fetch_object(). Пример с PDO:
$stmt = $pdo->query('SELECT id, name FROM users');
while ($obj = $stmt->fetch(PDO::FETCH_OBJ)) {
echo $obj->name;
}
Как обработать ошибки при получении данных?
В PDO – режим исключений (ERRMODE_EXCEPTION). В mysqli – проверять возвращаемые значения и вызывать mysqli_error. Всегда закрывать соединения и освобождать результаты.
Ошибки при использовании устаревшего mysql_*:
Функции mysql_* удалены в PHP 7.0. При попытке их использования возникает фатальная ошибка. Необходимо переходить на mysqli или PDO.
Расширенные примеры получения данных
Пример 1. Именованные плейсхолдеры и выборка с условием IN
<?php
$ids = [1, 2, 3];
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("SELECT id, name FROM users WHERE id IN ($placeholders)");
$stmt->execute($ids);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
Array
(
[0] => Array ( [id] => 1 [name] => Ivan )
[1] => Array ( [id] => 2 [name] => Maria )
[2] => Array ( [id] => 3 [name] => Petr )
)
Пример 2. Маппинг на пользовательский класс через PDO::FETCH_CLASS
<?php
class User {
public int $id;
public string $name;
public string $email;
}
$stmt = $pdo->prepare('SELECT id, name, email FROM users WHERE active = ?');
$stmt->execute([1]);
$users = $stmt->fetchAll(PDO::FETCH_CLASS, 'User');
foreach ($users as $user) {
echo $user->name . "\n";
}
?>
Ivan Maria Petr
Пример 3. Пагинация с использованием LIMIT и OFFSET
<?php
$page = 2;
$perPage = 10;
$offset = ($page - 1) * $perPage;
$stmt = $pdo->prepare('SELECT * FROM posts ORDER BY created_at DESC LIMIT :limit OFFSET :offset');
$stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
Пример 4. Получение одного столбца с помощью fetchColumn
<?php
$stmt = $pdo->query('SELECT DISTINCT city FROM users');
while ($city = $stmt->fetchColumn()) {
echo $city . "<br>";
}
?>
Пример 5. Использование транзакций с блокировкой для согласованного чтения
<?php
$pdo->beginTransaction();
try {
// Блокировка строк для чтения (FOR UPDATE)
$stmt = $pdo->prepare('SELECT balance FROM accounts WHERE id = ? FOR UPDATE');
$stmt->execute([1]);
$balance = $stmt->fetchColumn();
// Выполнение обновления
$pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
echo 'Ошибка: ' . $e->getMessage();
}
?>
Пример 6. Ленивая загрузка больших наборов данных с fetch()
<?php
$stmt = $pdo->prepare('SELECT * FROM logs WHERE date > ?');
$stmt->execute(['2024-01-01']);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// Обработка каждой строки без загрузки всех в память
processLog($row);
}
?>
Пример 7. Использование MYSQL_ATTR_USE_BUFFERED_QUERY для больших запросов
<?php
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->query('SELECT * FROM huge_table');
foreach ($stmt as $row) {
// unbuffered query – данные передаются строкой за строкой
}
?>
Пример 8. Получение данных с подсчётом общего количества строк (пагинация + count)
<?php
$stmtCount = $pdo->prepare('SELECT COUNT(*) FROM users WHERE active = ?');
$stmtCount->execute([1]);
$total = $stmtCount->fetchColumn();
$stmtData = $pdo->prepare('SELECT * FROM users WHERE active = ? LIMIT ? OFFSET ?');
$stmtData->execute([1, $perPage, $offset]);
$data = $stmtData->fetchAll();
?>