Почему PHP и PostgreSQL — это любовь с первого запроса?
Мир веб-разработки полон стереотипов. Один из них гласит: «PHP дружит только с MySQL». Доля правды в этом есть, но только до тех пор, пока вы не попробуете связку PHP и PostgreSQL. Это как перейти с велосипеда на спортивный мотоцикл: всё те же колёса, но скорость, манёвренность и надёжность совершенно иные.
PostgreSQL — это не просто база данных. Это объектно-реляционный монстр, который умеет работать с JSON, геоданными, полнотекстовым поиском и сложнейшими транзакциями. А PHP — идеальный дирижёр для этого оркестра. В этом руководстве мы разберём всё: от установки драйвера до написания production-ready кода. Поехали!
1. Установка и настройка: готовим инструменты
Прежде чем писать код, убедимся, что PHP знает о существовании PostgreSQL. В большинстве современных дистрибутивов PHP (например, XAMPP, OpenServer, Docker) расширение pdo_pgsql уже есть, но его нужно активировать.
1.1. Включаем расширение в php.ini
Откройте ваш php.ini и раскомментируйте (уберите точку с запятой в начале) строку:
extension=pdo_pgsql
Если вы используете Linux, установка выглядит так:
sudo apt-get install php-pgsql
sudo service apache2 restart # или nginx + php-fpm
1.2. Создаём базу и пользователя
Заходим в консоль PostgreSQL:
sudo -u postgres psql
Теперь создадим базу данных и пользователя для нашего проекта:
CREATE DATABASE pythonlib_blog;
CREATE USER myapp WITH PASSWORD 'SuperSecret123';
GRANT ALL PRIVILEGES ON DATABASE pythonlib_blog TO myapp;
\q
Готово. Теперь у нас есть база pythonlib_blog и пользователь myapp.
2. Первое подключение: PDO как стандарт
Никогда не используйте старые функции pg_connect(). В современном PHP есть PDO (PHP Data Objects) — единый интерфейс для работы с разными БД. Он безопаснее, удобнее и поддерживает подготовленные запросы.
2.1. Класс-обёртка для подключения
Создадим простой класс Database, который будет управлять подключением:
<?php
class Database {
private static ?PDO $instance = null;
private const DB_HOST = 'localhost';
private const DB_PORT = 5432;
private const DB_NAME = 'pythonlib_blog';
private const DB_USER = 'myapp';
private const DB_PASS = 'SuperSecret123';
public static function getConnection(): PDO {
if (self::$instance === null) {
$dsn = "pgsql:host=" . self::DB_HOST . ";port=" . self::DB_PORT . ";dbname=" . self::DB_NAME;
try {
self::$instance = new PDO($dsn, self::DB_USER, self::DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}
}
return self::$instance;
}
}
Почему это круто? Во-первых, синглтон — мы не создаём новое подключение при каждом запросе. Во-вторых, ATTR_EMULATE_PREPARES => false заставляет PostgreSQL использовать настоящие подготовленные запросы, а не эмуляцию на стороне PHP. Это повышает производительность и безопасность.
3. CRUD-операции: создаём, читаем, обновляем, удаляем
Теперь самое мясо. Допустим, у нас есть таблица articles для статей на pythonlib.ru.
3.1. Создание таблицы
Выполните этот SQL в вашей БД (через psql или админку):
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
author VARCHAR(100) DEFAULT 'Admin',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
3.2. INSERT (Создание записи)
<?php
require_once 'Database.php';
$pdo = Database::getConnection();
$sql = "INSERT INTO articles (title, content, author) VALUES (:title, :content, :author)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':title' => 'PHP и PostgreSQL: полное руководство',
':content' => 'Подробная статья о работе с PostgreSQL из PHP...',
':author' => 'Команда PythonLib'
]);
echo "Статья добавлена с ID: " . $pdo->lastInsertId();
Обратите внимание: мы используем именованные плейсхолдеры (:title). Это защищает от SQL-инъекций. Никогда не подставляйте переменные напрямую в строку запроса!
3.3. SELECT (Чтение данных)
Получим все статьи автора «Admin»:
<?php
$pdo = Database::getConnection();
$sql = "SELECT id, title, created_at FROM articles WHERE author = :author ORDER BY created_at DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute([':author' => 'Admin']);
$articles = $stmt->fetchAll();
foreach ($articles as $article) {
echo "<h3>" . htmlspecialchars($article['title']) . "</h3>";
echo "<p>Опубликовано: " . $article['created_at'] . "</p>";
}
Функция htmlspecialchars() — обязательный минимум для защиты от XSS-атак.
3.4. UPDATE (Обновление)
<?php
$pdo = Database::getConnection();
$sql = "UPDATE articles SET content = :content WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':content' => 'Обновлённое содержание статьи...',
':id' => 1
]);
echo "Обновлено строк: " . $stmt->rowCount();
3.5. DELETE (Удаление)
<?php
$pdo = Database::getConnection();
$sql = "DELETE FROM articles WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([':id' => 42]);
echo "Удалено строк: " . $stmt->rowCount();
4. Продвинутые фишки PostgreSQL в PHP
PostgreSQL — это не просто «положи-забери». Вот несколько killer-фич, которые вы можете использовать из PHP.
4.1. Работа с JSON
В PostgreSQL есть нативный тип JSONB. Можно хранить сложные структуры и делать запросы к ним прямо на стороне БД.
Создадим таблицу с JSONB-полем:
CREATE TABLE user_profiles (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE,
metadata JSON