Использование PDO в index.php: от подключения до сложных запросов

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

Основные подходы к реализации index.php с PDO

Как создать index.php с безопасным подключением к базе данных через PDO?

Наиболее распространенный и рекомендуемый способ - использование PDO с подготовленными выражениями. Рассмотрим базовый пример.


<?php
$host = 'localhost';
$dbname = 'test';
$username = 'root';
$password = '';

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

Пояснение:

  • Устанавливается соединение с указанием charset utf8.
  • Включается режим исключений для обработки ошибок.
  • В случае неудачи выводится сообщение и выполнение прекращается.

Типичные проблемы:

  • Не указан charset - возможны проблемы с кодировкой.
  • Не установлен режим исключений - ошибки могут остаться незамеченными.
  • Пароль или имя пользователя неверны - нужно проверять параметры подключения.

Как организовать подключение в отдельном файле и подключать его в index.php?

Часто удобно вынести настройки подключения в конфигурационный файл, а затем подключать его.


// config.php
<?php
return [
    'host' => 'localhost',
    'dbname' => 'test',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8mb4'
];
?>

// index.php
<?php
$config = require 'config.php';
$dsn = "mysql:host={$config['host']};dbname={$config['dbname']};charset={$config['charset']}";

try {
    $pdo = new PDO($dsn, $config['username'], $config['password'], [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]);
} catch (PDOException $e) {
    http_response_code(500);
    echo "Ошибка сервера";
    exit;
}
?>

Пояснение:

  • Конфигурация хранится отдельно, что упрощает её изменение.
  • Используется массив опций при создании объекта PDO.
  • Устанавливается режим выборки по умолчанию FETCH_ASSOC.

Возможные ошибки:

  • Файл config.php не найден или содержит ошибки синтаксиса.
  • Не учтены права доступа к базе данных.

Как использовать класс-обертку для PDO в index.php?

Для повторного использования подключения можно создать класс, который будет возвращать единый экземпляр PDO (одиночка).


class Database {
    private static $instance = null;
    private $pdo;

    private function __construct() {
        $config = require 'config.php';
        $dsn = "mysql:host={$config['host']};dbname={$config['dbname']};charset={$config['charset']}";
        $this->pdo = new PDO($dsn, $config['username'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        ]);
    }

    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function getConnection() {
        return $this->pdo;
    }
}

// index.php
<?php
require 'Database.php';
$pdo = Database::getInstance()->getConnection();
// далее используем $pdo
?>

Пояснение:

  • Класс Database реализует паттерн Singleton.
  • Подключение создается только один раз.
  • Удобно для крупных проектов.

Недостатки:

  • Сложность тестирования (трудно подменить экземпляр).
  • При изменении конфигурации во время выполнения не сбросит соединение.

Как обрабатывать ошибки PDO в index.php без остановки скрипта?

Иногда необходимо продолжить выполнение, даже если запрос не удался. Используется режим PDO::ERRMODE_WARNING.


$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$stmt = $pdo->query("SELECT * FROM non_existing_table");
if ($stmt === false) {
    echo "Запрос не выполнен, но скрипт продолжается";
}

Пояснение:

  • Вместо исключения выводится предупреждение.
  • Результат query можно проверить на false.

Проблемы:

  • Предупреждения могут быть скрыты настройками PHP.
  • Код становится менее читаемым из-за множества проверок.

Расширенные примеры работы с PDO в index.php

Пример 1: Подготовленный запрос с параметрами и получение данных.

Пример

<?php
// Предполагается, что $pdo уже создан
$user_id = 42;
$stmt = $pdo->prepare("SELECT name, email FROM users WHERE id = :id");
$stmt->execute(['id' => $user_id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($user);
?>

Результат:

Array
(
    [name] => Иван
    [email] => ivan@example.com
)

Пример 2: Вставка нескольких записей в одной транзакции.

Пример

<?php
$pdo->beginTransaction();
try {
    $stmt = $pdo->prepare("INSERT INTO products (name, price) VALUES (:name, :price)");
    $products = [
        ['name' => 'Товар 1', 'price' => 100],
        ['name' => 'Товар 2', 'price' => 200],
        ['name' => 'Товар 3', 'price' => 300],
    ];
    foreach ($products as $product) {
        $stmt->execute($product);
    }
    $pdo->commit();
    echo "Вставлено " . count($products) . " записей";
} catch (Exception $e) {
    $pdo->rollBack();
    echo "Ошибка: " . $e->getMessage();
}
?>

Результат:

Вставлено 3 записей

Пример 3: Использование именованных placeholder'ов с разными типами данных.

Пример

<?php
$stmt = $pdo->prepare("INSERT INTO logs (message, created_at, level) VALUES (:msg, :created, :level)");
$stmt->execute([
    'msg' => 'Пользователь вошел в систему',
    'created' => date('Y-m-d H:i:s'),
    'level' => (int)1
]);
echo "ID новой записи: " . $pdo->lastInsertId();
?>

Результат:

ID новой записи: 15

Пример 4: Пейджинация с помощью LIMIT и OFFSET.

Пример

<?php
$page = 2;
$perPage = 10;
$offset = ($page - 1) * $perPage;
$stmt = $pdo->prepare("SELECT * FROM articles 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();
$articles = $stmt->fetchAll();
foreach ($articles as $article) {
    echo $article['title'] . "<br>";
}
?>

Результат:

Статья 11
Статья 12
...

Пример 5: Обработка ошибок с использованием исключений.

Пример

<?php
try {
    $stmt = $pdo->query("SELECT invalid_column FROM users");
} catch (PDOException $e) {
    echo "Код ошибки: " . $e->getCode() . "<br>";
    echo "Сообщение: " . $e->getMessage();
}
?>

Результат:

Код ошибки: 42S22
Сообщение: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'invalid_column' in 'field list'

Пример 6: Получение всех записей в виде массива объектов.

Пример

<?php
$stmt = $pdo->query("SELECT id, name FROM categories");
$categories = $stmt->fetchAll(PDO::FETCH_OBJ);
foreach ($categories as $cat) {
    echo $cat->id . ': ' . $cat->name . "<br>";
}
?>

Результат:

1: Категория A
2: Категория B
...

Index.php с PDO - comments

En
Index php pdo (php)