Александр Некрасов · Автономное руководство

PHP: полный мануал с примерами, функциями и ООП

Разделы этой страницы
  1. PDO: полный справочник, драйверы и работа с данными
  2. Как запустить любую карточку: файлы, схема и каталог
  3. Нулевой остаток, отсутствующий товар и счётчик
  4. Выгрузить каталог в CSV небольшими страницами
  5. Сначала работающий каталог, затем справочник
  6. Зачем PDO: сохранить заказ и прочитать его в следующем запросе
  7. Таблица → строка → массив: первый полезный результат
  8. Установка, требования и конфигурация PDO
  9. Время жизни соединения, повторное использование и состояние
  10. PDO, PDOStatement, PDORow и PDOException: кто за что отвечает
  11. Подготовленные запросы и процедуры: что именно защищается
  12. Транзакция: несколько изменений становятся одним действием
  13. Ошибки: не путать отказ, отсутствие строки и отсутствие изменений
  14. LOB: файл, поток, двоичные данные и выдача пользователю
  15. Все общие константы: параметры, атрибуты и события
  16. Все режимы чтения: массив, объект, группа и преобразование
  17. Все одиннадцать драйверов: выбрать свою ветку
  18. MySQL и MariaDB: настройка, DSN и границы переносимости
  19. PostgreSQL: настройка, DSN и границы переносимости
  20. SQLite: локальный файл или база в памяти: настройка, DSN и границы переносимости
  21. ODBC: общий мост к установленному драйверу: настройка, DSN и границы переносимости
  22. Microsoft SQL Server и Azure SQL: настройка, DSN и границы переносимости
  23. FreeTDS: SQL Server и Sybase: настройка, DSN и границы переносимости
  24. Firebird: настройка, DSN и границы переносимости
  25. IBM Db2: настройка, DSN и границы переносимости
  26. IBM Informix: настройка, DSN и границы переносимости
  27. Oracle: настройка, DSN и границы переносимости
  28. CUBRID: настройка, DSN и границы переносимости
  29. Полный список драйверных констант и их назначение
  30. CUBRID: коллекции, схема и все флаги
  31. Практика: каталог, скорость и границы памяти
  32. Указатель всех методов PDO по объектам
  33. Частые затруднения из реальной разработки
  34. Функции и методы этой темы
  35. Код и руководство с собой
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 127 · С нуля → справочник

PDO: полный справочник, драйверы и работа с данными

От первой строки SELECT до параметров, транзакций, всех методов PDO/PDOStatement, драйверных классов и одиннадцати DSN.

Как запустить любую карточку: файлы, схема и каталог

Наглядная модель

Из SQL-шаблона в понятный массив PHP

Запрос, его параметры и результат — три разных вещи. Проследим путь товара с ID 2.

  1. PHP готовит запрос

    prepare('SELECT name, price FROM products WHERE id = :id') сохраняет структуру. Значение ID пока не передано.

  2. В execute входит число 2

    execute(['id' => 2]) сопоставляет ключ id с маркером :id. Значение передаётся как данные, а не как часть SQL-грамматики.

  3. База находит строку

    products: id = 2, name = Notebook, price = 350. PDOStatement представляет текущий результат, но ещё не является массивом товара.

  4. fetch возвращает значение в PHP

    fetch(PDO::FETCH_ASSOC) → $product = ['name' => 'Notebook', 'price' => 350]. Теперь можно проверить, преобразовать и вывести поля.

Если строки нет, fetch возвращает false; SQL-ошибка в режиме EXCEPTION бросает PDOException. Параметры защищают структуру SQL, а права на товар и HTML-экранирование проверяются отдельно.

Все новые карточки используют один небольшой каталог мастерской. Пример можно запускать отдельно: его архив содержит example.php, catalog.php, schema.sql и README. Молоток имеет остаток 8, Перчатки — 15, Кисть — 0. Ноль здесь означает известное отсутствие товара, а не пропавшую строку.

Кто за что отвечает
  1. schema.sql: структура и три известные строки
  2. catalog.php: подключение и создание учебных данных
  3. example.php: один изучаемый механизм
  4. stdout: название товара, остаток или понятный отказ

require выполняет подключаемый PHP-файл. __DIR__ — папка текущего файла, . склеивает строки. SQL в schema.sql описывает таблицу: id отличает товары, name хранит название, stock — целое неотрицательное количество. INSERT заполняет строки. Код подключения показан полностью: никаких скрытых таблиц урок не предполагает.

Нужно расширение pdo_sqlite. SQLite работает внутри PHP; установка MySQL для этих примеров не требуется. :memory: означает временную базу одного соединения. Чтобы изучать сохранение между запусками, используйте проект с файлом catalog.sqlite.

schema.sql

CREATE TABLE products (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    stock INTEGER NOT NULL CHECK (stock >= 0)
);
INSERT INTO products VALUES
    (1, 'Молоток', 8),
    (2, 'Перчатки', 15),
    (3, 'Кисть', 0);

catalog.php

<?php
$db = new PDO('sqlite::memory:');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$db->exec(file_get_contents(__DIR__ . '/schema.sql'));

Команда php example.php выводит результат в терминал. Для HTML нужен отдельный обработчик и веб-сервер — переход от строк базы к странице каталога. В рабочем сайте создание постоянной схемы выполняют отдельно от посещения страницы; здесь временные исходные данные нужны для воспроизводимого урока.

Нулевой остаток, отсутствующий товар и счётчик

Каталог должен отличать существующую Кисть с остатком 0 от неизвестного номера 99. Загрузка всех товаров ради количества также не требуется: COUNT(*) возвращает одну строку с числом.

Нулевой остаток, отсутствующий товар и счётчик
  1. schema.sql создаёт Кисть: id3, stock0
  2. execute([3]) → fetch: массив с name/stock → Нет в наличии
  3. execute([99]) → fetch: false → Товар не найден
  4. COUNT(*) → одна строка, одно поле 3

=== false проверяет именно конец/отсутствие строки, сохраняя значение 0 в найденной строке. ? : выбирает один из двух текстов. Запрос использует явный FETCH_ASSOC и SQLite-схему: здесь stock возвращается целым; при другом драйвере нормализуйте тип согласно его контракту.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Нулевой остаток, отсутствующий товар и счётчикСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->prepare('SELECT name, stock FROM products WHERE id = ?');
foreach ([3, 99] as $id) {
    $statement->execute([$id]);
    $row = $statement->fetch(PDO::FETCH_ASSOC);
    if ($row === false) {
        echo 'Товар #', $id, " не найден
";
    } else {
        echo $row['name'], ': ', $row['stock'] === 0 ? 'Нет в наличии' : $row['stock'].' шт.', "
";
    }
}
echo 'Всего карточек: ', $db->query('SELECT COUNT(*) FROM products')->fetchColumn(), "
";
Ожидаемый результат
Кисть: Нет в наличии
Товар #99 не найден
Всего карточек: 3

Успешно найденная строка не означает положительный остаток. Счётчик 3 включает отсутствующую в наличии Кисть, поскольку она остаётся записью каталога.

Проверьте изменение требования. Задание: показывать только доступные товары. Решение: WHERE stock > 0 и тот же предикат в COUNT(*); результат списка — Молоток 8 и Перчатки 15, счётчик 2. rowCount для переносимого подсчёта SELECT не подходит. Как вывести такие строки на HTML-странице.

Выгрузить каталог в CSV небольшими страницами

Оператору нужен файл остатков для сверки, а приложению нельзя создавать массив из миллионов строк. Сначала попробуем на трёх товарах и размере страницы 2; каждую строку сразу запишем в файл.

Выгрузить каталог в CSV небольшими страницами
  1. after0 → id1/id2 → две строки CSV → after2
  2. after2 → id3 → третья строка CSV → after3
  3. Получена 1 строка, меньше LIMIT2 → остановка
  4. inventory.csv рядом с example.php содержит заголовок и 3 товара

ORDER BY id задаёт устойчивый порядок; id > :after продолжает после последней выгруженной записи. do ... while сначала выполняет страницу, потом решает, нужна ли следующая. fputcsv сам заключает поля в кавычки при необходимости; пустой escape явно отключает особый обратный слеш. Режим xb не перезаписывает существующий файл.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
while (...)Повторяет блок, пока условие истинно. В чтении результата проверка конца связана с конкретным методом: false или null указаны в его контракте.
try / catch / finallytry содержит действие, catch обрабатывает отказ, finally выполняет освобождение ресурсов и при успехе, и при исключении.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Выгрузить каталог в CSV небольшими страницамиСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$path = __DIR__ . '/inventory.csv';
$file = fopen($path, 'xb');
if ($file === false) { throw new RuntimeException('Не удалось создать inventory.csv'); }
$statement = $db->prepare('SELECT id, name, stock FROM products WHERE id > :after ORDER BY id LIMIT 2');
$after = 0;
try {
    if (fputcsv($file, ['name', 'stock'], ';', '"', '', "
") === false) { throw new RuntimeException('Ошибка заголовка CSV'); }
    do {
        $statement->bindValue(':after', $after, PDO::PARAM_INT);
        $statement->execute();
        $rows = $statement->fetchAll(PDO::FETCH_ASSOC);
        foreach ($rows as $row) {
            if (fputcsv($file, [$row['name'], $row['stock']], ';', '"', '', "
") === false) { throw new RuntimeException('Ошибка строки CSV'); }
            $after = $row['id'];
        }
    } while (count($rows) === 2);
} finally {
    fclose($file);
}
$contents = file_get_contents($path);
if ($contents === false) { throw new RuntimeException('CSV записан, но не читается'); }
echo "Файл inventory.csv:
", $contents;
Ожидаемый результат
Файл inventory.csv:
name;stock
Молоток;8
Перчатки;15
Кисть;0

На первой странице находятся только два массива, на второй один. SELECT, bindValue, fetchAll и fputcsv выполняют разные части одной задачи. Содержимое файла показано полностью; его можно открыть текстовым редактором или импортировать с разделителем «;».

Проверьте изменение требования. В большом экспорте не читайте готовый файл целиком обратно: здесь это сделано только ради видимого учебного результата. Ограничение памяти PHP-массива не доказывает отсутствие буфера драйвера; ограниченный LIMIT ограничивает и размер отдельного ответа. Удаляемые/изменяемые id и конкурентные правки требуют определённой политики снимка. CSV с недоверенным текстом для Excel требует отдельной политики формул, а не только SQL-параметров. Задание: LIMIT1 — содержимое CSV сохранится, число запросов возрастёт.

Сначала работающий каталог, затем справочник

Если база данных для вас новая тема, начните с последовательного каталога товаров. Там показаны создание файла и таблицы, добавление записей, чтение в массив, foreach, готовая HTML-страница и ошибки каждого этапа. Здесь — подробные возможности PDO; их удобнее изучать, когда уже видна общая задача.

Зачем PDO: сохранить заказ и прочитать его в следующем запросе

Переменная PHP живёт в выполняющемся процессе. Сайту нужно хранить заказы, пользователей и остатки так, чтобы к ним можно было вернуться. База данных хранит структурированные записи, а PDO даёт PHP единый набор действий для соединения, выполнения SQL и чтения результата. PDO не заменяет саму СУБД, не делает SQL разных серверов одинаковым и не создаёт схему магазина автоматически.

Представьте картотеку: таблица — набор карточек одного вида, строка — один товар, колонка — конкретное поле, например name. Но база отличается от бумажной картотеки: она проверяет ограничения, выполняет запросы и управляет одновременной работой. Первичный ключ id позволяет отличить два товара с одинаковым названием. SQL — отдельный язык команд для этой базы.

Маршрут самого маленького запроса
  1. PHP создаёт $db — соединение SQLite в памяти
  2. query отправляет SQL SELECT 42
  3. База формирует одну строку с одной колонкой
  4. fetchColumn переносит значение 42 в $result
  5. echo показывает 42

$db = сохраняет значение в переменную. new PDO(...) создаёт объект, представляющий соединение; строка sqlite::memory: выбирает SQLite и учебную базу в памяти. -> обращается к методу этого объекта. query() возвращает объект результата, fetchColumn() читает значение. echo выводит его; " " добавляет перевод строки. Пока не нужны собственные классы, функции и циклы.

Как читать этот вариант. Каждая строка делает один шаг. SELECT — команда языка SQL, которую исполняет база. В кавычках находится текст команды, а $result после fetchColumn содержит число; PDOStatement не является самим числом.

Первый запрос: получить одно числоСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:');
$statement = $db->query('SELECT 42');
$result = $statement->fetchColumn();
echo $result, "\n";
Ожидаемый результат
42

Дальше разберём запись и чтение товара, затем параметры, ошибки и транзакции. Ссылка дополняет объяснение, но не требует угадать синтаксис: переменные, что такое объект, массив как контейнер полей.

Таблица → строка → массив: первый полезный результат

exec выполняет команду без чтения набора строк. query сразу выполняет SQL и даёт результат. prepare сначала создаёт шаблон, execute передаёт значения и запускает его. fetch переносит следующую строку в PHP. Имя name в SELECT становится ключом $product['name'] в режиме FETCH_ASSOC: это та самая связь между базой и массивом.

Как читать этот вариант. CREATE создаёт таблицу, INSERT добавляет строку, SELECT читает. ATTR_ERRMODE => ERRMODE_EXCEPTION задаёт реакцию на SQL-ошибку явно; FETCH_ASSOC превращает строку в массив с ключами id и name. В настоящем приложении схему создают миграцией, а не при каждом посещении страницы.

Создать таблицу и прочитать сохранённый товарСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
$db->exec("INSERT INTO products (id, name) VALUES (1, 'Pen')");
$statement = $db->query('SELECT id, name FROM products WHERE id = 1');
$product = $statement->fetch(PDO::FETCH_ASSOC);
echo $product['name'], "\n";
Ожидаемый результат
Pen
Разделяем структуру запроса и данные
  1. Шаблон: WHERE id = :id
  2. Значение PHP: $productId = 2
  3. execute([id=>2]) связывает параметр
  4. Результат: [name=>Notebook, price=>350]

Как читать этот вариант. В SQL :id — место для одного значения. В PHP-массиве ключ id сопоставляет ему число 2. execute исполняет, fetch читает; === false проверяет конец/отсутствие строки, не приравнивая к нему пустое значение. Цена здесь в минимальных денежных единицах.

Найти товар по внешнему значению без склеивания SQLСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$productId = 2;
$statement = $db->prepare('SELECT name, price FROM products WHERE id = :id');
$statement->execute(['id' => $productId]);
$product = $statement->fetch(PDO::FETCH_ASSOC);
if ($product === false) {
    echo "Товар не найден\n";
} else {
    echo $product['name'], ':', $product['price'], "\n";
}
Ожидаемый результат
Notebook:350

Параметризация защищает синтаксис SQL, но не решает, имеет ли текущий пользователь право читать этот товар/заказ. Проверка авторизации и допустимых диапазонов выполняется отдельно. При выводе строки в HTML используйте экранирование HTML; SQL-параметр не является HTML-экранированием.

Установка, требования и конфигурация PDO

PDO включён в PHP по умолчанию; при сборке его можно исключить --disable-pdo. Сам PDO не требует библиотеку конкретной БД: её требует драйвер. Для MySQL нужно pdo_mysql, для PostgreSQL pdo_pgsql и libpq и т. д. При общей динамической сборке базовый PDO должен загрузиться перед зависимыми драйверами. В Windows комплект зависит от сборки PHP: включайте подходящие DLL драйверов и необходимые клиентские библиотеки, совпадающие по версии/разрядности/TS. DLL должны находиться в extension_dir; строка extension=pdo_sqlite включает драйвер, а ;extension=pdo_odbc с точкой с запятой оставляет ODBC выключенным. После изменения php.ini перезапускают соответствующий PHP-процесс/службу. Не подключайте старую php_pdo.dll из чужой версии.

Как читать этот вариант. Вывод относится к среде примеров PHP 8.5.11. PHP командной строки и PHP-FPM/Apache могут иметь разные ini и набор расширений. Публичную страницу phpinfo с секретной конфигурацией оставлять не нужно.

Проверить именно тот PHP, которым запускается приложениеСамостоятельный пример
<?php
echo extension_loaded('PDO') ? "PDO есть\n" : "PDO нет\n";
echo in_array('sqlite', PDO::getAvailableDrivers(), true) ? "SQLite доступен\n" : "Нужен pdo_sqlite\n";
echo PHP_VERSION_ID >= 80400 ? "Есть API подклассов PHP 8.4+\n" : "Используйте базовый PDO\n";
Ожидаемый результат
PDO есть
SQLite доступен
Есть API подклассов PHP 8.4+

У PDO одна группа собственных ini-настроек: pdo.dsn.* задаёт псевдоним DSN только в php.ini, не через ini_set. Например, pdo.dsn.shop="sqlite:/srv/app/shop.sqlite" позволяет передать shop конструктору. Пароль отдельно хранится в защищённой конфигурации. DSN определяет драйвер/адрес/базу; URI-вариант читает DSN из доверенного файла. Полные три способа показаны в PDO::__construct().

У каждой драйверной ветки ниже есть собственные требования, параметры подключения и два примера. Если could not find driver возникает раньше SQL, сначала проверьте getAvailableDrivers в нужном SAPI, ini и установку расширения. Наличие mysqli или pgsql не означает наличие одноимённого PDO-драйвера.

Время жизни соединения, повторное использование и состояние

Открытие нового PDO может стоить сети, аутентификации и настройки сессии. Не создавайте соединение внутри каждого прохода цикла. Передавайте уже созданный объект тому коду, который выполняет запрос. Отдельного метода PDO::close нет: обычное соединение освобождается после исчезновения всех ссылок, в том числе из PDOStatement; при завершении запроса PHP освобождает обычные ресурсы.

Как читать этот вариант. Присваивание null одной переменной не уничтожает объект, пока на него ссылаются другие объекты/переменные. closeCursor освобождает результат, но не является close соединения.

Statement сохраняет связь с соединениемСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->query('SELECT 42');
$db = null;
echo $statement->fetchColumn(), "\n";
$statement = null;
echo "Все ссылки освобождены\n";
Ожидаемый результат
42
Все ссылки освобождены

Persistent включается только в constructor options. bool включает/выключает повторное использование, нечисловая строка выбирает отдельный пул. Соединения принадлежат процессам/воркерам и не превращаются в один общий объект всего сайта. Выигрыш зависит от стоимости подключения и модели нагрузки. У долгоживущего worker обычное соединение и так может жить долго.

Как читать этот вариант. Контекстный пример, только lint. Нечисловая строка создаёт отдельную группу повторного использования. Она не обеспечивает очистку session variables, временных таблиц и иных настроек между задачами.

Назвать отдельный пул совместимых соединенийПример для указанного окружения
<?php
$db = new Pdo\Mysql(getenv('MYSQL_DSN'), getenv('DB_USER'), getenv('DB_PASSWORD'), [
    PDO::ATTR_PERSISTENT => 'shop-read-buffered',
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    Pdo\Mysql::ATTR_USE_BUFFERED_QUERY => true,
]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
mysql

PDO не обещает очистить всё состояние persistent: временные таблицы, блокировки, параметры сессии и другие изменения способны пережить предыдущую работу. Задайте политику инициализации/завершения задачи и измерьте эффект. В PDO_ODBC при доступном ODBC pooling обычно оставляют пул нижнему слою, иначе соединение не возвращается в него и возникает лишнее кеширование. Ошибка подключения всегда PDOException, даже при ERRMODE_SILENT. В рабочей среде display_errors=0, журнал защищён, посетителю — понятное общее сообщение.

PDO, PDOStatement, PDORow и PDOException: кто за что отвечает

КлассСмысл
PDOСоединение, настройки, транзакции и создание statement. Общие методы перечислены ниже.
PDOStatementКоманда, привязки параметров и текущий результат; создаётся prepare/query. Имеет queryString и реализует IteratorAggregate с PHP 8.0.
PDORowВстроенное представление текущей строки FETCH_LAZY; не создают new, не клонируют/сериализуют как независимый снимок.
PDOExceptionНаследник RuntimeException: ошибка PDO. Унаследованные message/file/line/trace/getPrevious описывают исключение; errorInfo — nullable массив SQLSTATE/driver code/message. getCode может содержать строку SQLSTATE.

Как читать этот вариант. queryString показывает шаблон команды, а не безопасный готовый журнал со всеми параметрами. Каждый объект отвечает за свой этап. Прямой new PDOStatement не заменяет prepare/query.

Различить соединение и командуСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->prepare('SELECT :number AS number');
echo get_class($db), "\n";
echo get_class($statement), "\n";
echo $statement->queryString, "\n";
$statement->execute(['number' => 42]);
echo $statement->fetchColumn(), "\n";
Ожидаемый результат
PDO
PDOStatement
SELECT :number AS number
42

Как читать этот вариант. Диагностика демонстрируется в локальном CLI. В HTTP-ответ не отправляют SQL, трассировку или сообщение драйвера. errorInfo может отсутствовать при некоторых видах отказа; SQLSTATE имеет строковую семантику.

Обработать ошибку ограничения, не раскрывая SQL посетителюСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE users (id INTEGER PRIMARY KEY)');
$db->exec('INSERT INTO users VALUES (1)');
try {
    $db->exec('INSERT INTO users VALUES (1)');
} catch (PDOException $error) {
    echo 'SQLSTATE:', $error->getCode(), "\n";
    echo isset($error->errorInfo[1]) ? "Есть код драйвера\n" : "Нет кода драйвера\n";
    echo "Повторный идентификатор не сохранён\n";
}
Ожидаемый результат
SQLSTATE:23000
Есть код драйвера
Повторный идентификатор не сохранён

Для собственных бизнес-ошибок создают свою ошибку/RuntimeException, не конструируют PDOException для имитации драйвера. Перехватывают там, где есть действие: откатить, перевести конфликт в понятный ответ, либо передать выше. Пустой catch скрывает потерю данных. Подклассы Pdo\Mysql, Pdo\Pgsql, Pdo\Sqlite, Pdo\Odbc, Pdo\Firebird и Pdo\Dblib доступны с 8.4 при установленном драйвере; добавляют свои методы/константы и наследуют общие. PDO::connect выбирает подкласс автоматически; new PDO остаётся базовым объектом. Наследование здесь показывает реальную пользу общего интерфейса, но не уравнивает SQL-диалекты. См. PDO::connect() и PDOStatement::getIterator().

Подготовленные запросы и процедуры: что именно защищается

Шаблон оставляет место для целого значения. Маркеры :name или ? не обрамляют SQL-кавычками, не используют как имя таблицы, направление сортировки или список значений IN. Именованные и позиционные маркеры в одной команде не смешивают. Для LIKE передают целое значение %pen%; LIKE '%?%' ищет буквальный знак ?, а не параметр. Экранирование специальных символов самого LIKE — отдельный вопрос.

Как читать этот вариант. SQL подготовлен один раз. Массивы передают значения для каждого запуска; порядок именованных ключей не важен. Для большого импорта добавьте транзакцию и согласованные ограничения.

Повторить шаблон для двух входных значенийСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE labels (name TEXT, quantity INTEGER)');
$s = $db->prepare('INSERT INTO labels VALUES (:name, :quantity)');
$s->execute(['name' => 'Pen', 'quantity' => 2]);
$s->execute(['name' => 'Box', 'quantity' => 1]);
echo $db->query('SELECT COUNT(*) FROM labels')->fetchColumn(), "\n";
Ожидаемый результат
2

При native prepare сервер получает структуру и параметры отдельно; при эмуляции клиент строит корректную SQL-команду по правилам драйвера. Эмуляция позволяет применять единый приём и там, где серверная подготовка ограничена, но имеет особенности парсера и момента ошибки. Повторная подготовка может экономить анализ SQL, однако не гарантирует ускорение каждого одиночного запроса: важны серверный план, сеть и объём. Имена объектов остаются доверенными/из allowlist; если кусок SQL склеили с непроверенным вводом, подготовка других параметров его не защитит.

Три договора параметра процедуры
  1. IN: PHP передаёт значение серверу
  2. OUT: сервер записывает результат в привязанную переменную
  3. INOUT: начальное значение уходит и изменённое возвращается
  4. bindParam и размер буфера согласованы с драйвером и процедурой

Как читать этот вариант. Контекстный lint: нужна описанная процедура и совместимый ODBC-драйвер. Выходные параметры в некоторых драйверах доступны после полного чтения/закрытия результатов. Размер буфера должен вмещать договорённый результат; MySQL PDO не реализует этот INOUT таким же способом.

Получить результат процедуры через привязанную переменнуюПример для указанного окружения
<?php
$db = new PDO(getenv('ODBC_DSN'), getenv('DB_USER'), getenv('DB_PASSWORD'));
// В учебной БД существует процедура course_normalize_label(INOUT label VARCHAR(100)),
// превращающая ' pen ' в 'PEN'. Драйвер поддерживает INOUT.
$s = $db->prepare('{CALL course_normalize_label(?)}');
$label = ' pen ';
$s->bindParam(1, $label, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 100);
$s->execute();
$s->closeCursor();
echo $label, "\n";
Ожидаемый результат
PEN

Обычный return PHP-функции и OUT SQL-процедуры — разные механизмы. Procedure может возвращать также несколько result sets: их читают PDOStatement::nextRowset(). Объявление процедуры, транзакционные эффекты и OUT/INOUT требуют документации вашей СУБД; для обычного SELECT проще массив результата. В примерах PDOStatement::bindParam() и PDOStatement::bindValue() показаны обе стратегии связывания.

Транзакция: несколько изменений становятся одним действием

Заказ требует уменьшить остаток и записать покупку. Если подтверждено только одно изменение, данные расходятся. Транзакция задаёт границу «всё вместе»: beginTransaction начинает, commit подтверждает, rollBack отменяет. ACID: атомарность действия, соблюдение ограничений, изоляция параллельных действий и долговечность подтверждённых изменений. Конкретная изоляция и гарантии хранения зависят от СУБД/настроек, PDO их не усиливает автоматически.

Перенос товара в заказ
  1. BEGIN: начать единое действие
  2. UPDATE уменьшает доступный остаток с проверкой quantity > 0
  3. INSERT создаёт заказ
  4. COMMIT подтверждает оба; при отказе ROLLBACK отменяет оба

По умолчанию обычные соединения в autocommit. Поддержка транзакции проверяется драйвером, но таблица может быть нетранзакционной: MySQL MyISAM не получает rollback только от вызова beginTransaction. MySQL/Oracle и другие СУБД могут делать implicit commit при DDL, поэтому не смешивайте миграцию CREATE/ALTER с бизнес-откатом. Вложенный beginTransaction не создаёт переносимую вложенную транзакцию; SAVEPOINT — отдельный SQL-договор сервера.

Автоматический откат незавершённой транзакции при освобождении обычного соединения — страховка, не способ управления заказом. Он относится к транзакциям, начатым через PDO API; ручной BEGIN в exec усложняет знание PDO о состоянии. При обработке ошибки проверяйте inTransaction перед rollback. Deadlock/busy требуют ограниченной повторной попытки всего подходящего действия с идемпотентностью; уже отправленное банковское/Telegram-сообщение rollback базы не отменит. Для этого применяют очередь/outbox и отдельную доставку.

Ошибки: не путать отказ, отсутствие строки и отсутствие изменений

Не найденный товар даёт fetch=false. Повторная запись тех же данных может дать rowCount=0. Неудачный SQL в ERRMODE_EXCEPTION выбрасывает PDOException. Эти события нельзя объединять в одно «ошибка». SQLSTATE — пять символов общего класса/состояния, собственный числовой код и сообщение уточняются у драйвера. Для операции statement читайте его errorInfo, а не только соединение.

Как читать этот вариант. Диагностика демонстрируется в локальном CLI. В HTTP-ответ не отправляют SQL, трассировку или сообщение драйвера. errorInfo может отсутствовать при некоторых видах отказа; SQLSTATE имеет строковую семантику.

Обработать ошибку ограничения, не раскрывая SQL посетителюСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE users (id INTEGER PRIMARY KEY)');
$db->exec('INSERT INTO users VALUES (1)');
try {
    $db->exec('INSERT INTO users VALUES (1)');
} catch (PDOException $error) {
    echo 'SQLSTATE:', $error->getCode(), "\n";
    echo isset($error->errorInfo[1]) ? "Есть код драйвера\n" : "Нет кода драйвера\n";
    echo "Повторный идентификатор не сохранён\n";
}
Ожидаемый результат
SQLSTATE:23000
Есть код драйвера
Повторный идентификатор не сохранён
Выбрать действие по смыслу
  1. fetch=false → корректно сообщить «не найдено»
  2. execute=false при SILENT → прочитать errorInfo и обработать отказ
  3. PDOException → откатить активное действие и передать безопасный ответ
  4. rowCount=0 → проверить договор UPDATE, не объявлять автоматически ошибкой

EXCEPTION позволяет централизовать остановку/откат. SILENT полезен лишь при дисциплине каждой проверки, WARNING добавляет диагностический вывод и часто неудобен для JSON/HTML. Подробный SQL, параметры и backtrace могут раскрыть данные; журналируйте идентификатор операции и разрешённые поля, не пароль/содержимое формы целиком. Повторять любой отказ бесконечно опасно: уникальный ключ, неверный SQL и отсутствие прав ожиданием не исправляются. См. PDO::errorCode(), PDO::errorInfo(), PDOStatement::errorInfo().

LOB: файл, поток, двоичные данные и выдача пользователю

Большое вложение не обязательно удобно превращать в одну строку. LOB — большой текстовый/двоичный объект БД, PARAM_LOB связывает его с потоковым API PHP. Историческая вводная PHP приводит ориентир около 4–32 KiB, но это не универсальный порог: типы и лимиты выбираются по СУБД. Для части файлов выгоднее отдельное файловое/объектное хранилище с метаданными в БД.

Данные файла проходят через поток
  1. Проверенный файл открывается rb
  2. bindParam(PARAM_LOB) связывает поток
  3. execute записывает содержимое
  4. bindColumn(PARAM_LOB) + FETCH_BOUND получает результат
  5. fread/stream_get_contents/fpassthru читают поток

Как читать этот вариант. php://temp — временный поток; нулевой байт внутри сохранён. Привязанный через bindParam входной поток PDO_SQLITE может преобразовать в строку при execute: прежде чем fclose, проверяем is_resource. Драйвер может вернуть LOB ресурсом либо строкой, поэтому граница чтения обработана явно. Потоковый API не доказывает, что каждый драйвер обошёлся без внутреннего полного буфера.

Сохранить двоичные данные потоком и прочитать обратноСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE attachments (id INTEGER PRIMARY KEY, body BLOB)');
$stream = fopen('php://temp', 'w+b');
fwrite($stream, "A\0B");
rewind($stream);
$s = $db->prepare('INSERT INTO attachments VALUES (1, ?)');
$s->bindParam(1, $stream, PDO::PARAM_LOB);
$s->execute();
if (is_resource($stream)) { fclose($stream); }
$read = $db->query('SELECT body FROM attachments WHERE id = 1');
$read->bindColumn(1, $body, PDO::PARAM_LOB);
$read->fetch(PDO::FETCH_BOUND);
$bytes = is_resource($body) ? stream_get_contents($body) : $body;
echo bin2hex($bytes), "\n";
Ожидаемый результат
410042

Как читать этот вариант. Только lint: нужны Oracle, pdo_oci, таблица и проверенный receipt.bin. Транзакция предотвращает фиксацию пустого BLOB раньше записи. Пример не является обработчиком произвольной загрузки файла.

Oracle: записать LOB в рамках транзакцииПример для указанного окружения
<?php
$db = new PDO(getenv('ORACLE_DSN'), getenv('DB_USER'), getenv('DB_PASSWORD'));
// Учебная таблица attachments(id NUMBER, body BLOB) создана заранее.
$stream = fopen(__DIR__ . '/receipt.bin', 'rb');
if ($stream === false) { throw new RuntimeException('Нет входного файла'); }
$db->beginTransaction();
try {
    $s = $db->prepare('INSERT INTO attachments (id, body) VALUES (42, EMPTY_BLOB()) RETURNING body INTO ?');
    $s->bindParam(1, $stream, PDO::PARAM_LOB);
    $s->execute();
    $db->commit();
    echo "Вложение сохранено\n";
} catch (Throwable $error) {
    if ($db->inTransaction()) { $db->rollBack(); }
    throw $error;
} finally { fclose($stream); }
Ожидаемый результат
Вложение сохранено

При загрузке сначала проверяют метод/CSRF/авторизацию, UPLOAD_ERR_OK, размер, настоящий MIME через finfo и политику расширений; $_FILES['type'] ненадёжен. При скачивании проверяют владельца/право доступа до SELECT; Content-Type выбирают из разрешённых значений, задают Content-Disposition и nosniff по назначению. Никогда не публикуют произвольный MIME/заголовок прямо из базы. fpassthru посылает байты браузеру и расходует вывод, поэтому заголовки должны быть установлены заранее. База гарантирует свои данные, а не безопасность HTML/SVG-вложения.

У PostgreSQL bytea и large object OID — разные модели, у SQLite есть прямой доступ Pdo\Sqlite::openBlob(). Сравните Pdo\Pgsql::lobCreate() и PDOStatement::bindColumn().

Все общие константы: параметры, атрибуты и события

Константа — понятное имя фиксированного значения. PDO::PARAM_INT читается «целочисленный параметр PDO»; двойное двоеточие обращается к имени в классе. Атрибут — настройка соединения или команды. Одинаковые числа у констант разных семейств не делают их взаимозаменяемыми. Наличие PDO-константы не доказывает, что конкретный драйвер поддерживает настройку.

PDO::Значение и практический смысл
PARAM_NULLSQL NULL: отсутствие значения, не строка "NULL".
PARAM_BOOLЛогическое значение; конкретное SQL-представление зависит от драйвера.
PARAM_INTЦелое число. Флаг связывания не заменяет проверку допустимого диапазона входа.
PARAM_STRСтрока, обычный тип параметра.
PARAM_LOBБольшие/двоичные данные; строка или поток согласно драйверу.
PARAM_STMTТип набора записей, сейчас не поддержан драйверами.
PARAM_INPUT_OUTPUTФлаг INOUT процедуры: объединяют через | с типом, используют bindParam и поддерживающий драйвер.
PARAM_STR_NATLФлаг национального набора символов для строки, PHP 7.2+; не универсальное включение UTF-8.
PARAM_STR_CHARОбычный набор символов для строки, PHP 7.2+.

Как читать этот вариант. Имя константы передаёт намерение без магических чисел. NULL означает отсутствие примечания; строка пустого примечания имела бы другой смысл.

Связать число, строку и отсутствие значенияСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$s = $db->prepare('SELECT :quantity AS quantity, :label AS label, :note AS note');
$s->bindValue(':quantity', 2, PDO::PARAM_INT);
$s->bindValue(':label', 'Pen', PDO::PARAM_STR);
$s->bindValue(':note', null, PDO::PARAM_NULL);
$s->execute();
var_export($s->fetch(PDO::FETCH_ASSOC));
Ожидаемый результат
array (
  'quantity' => 2,
  'label' => 'Pen',
  'note' => NULL,
)
PDO::ATTR_…Поведение
AUTOCOMMITПопытка включить/выключить автоматическую фиксацию; поддержка и побочные фиксации зависят от СУБД.
PREFETCHРазмер предварительного чтения: обычно баланс памяти/скорости. У PostgreSQL 8.5 значение 0 включает lazy single-row, другое — буферизацию.
TIMEOUTСекунды ожидания, точный смысл драйверный: не универсальный лимит всего HTTP-запроса.
ERRMODESILENT, WARNING или EXCEPTION, описание ниже.
SERVER_VERSIONВерсия сервера, только чтение.
CLIENT_VERSIONВерсия клиентской библиотеки, только чтение.
SERVER_INFOМетаданные сервера, только чтение.
CONNECTION_STATUSСтатус соединения в формате драйвера.
CASECASE_NATURAL, CASE_LOWER, CASE_UPPER для имён колонок, не для текста значений.
CURSOR_NAMEИмя курсора, полезно для scrollable/positioned update.
CURSORCURSOR_FWDONLY по умолчанию либо CURSOR_SCROLL при поддержке драйвера; задаётся в prepare options.
DRIVER_NAMEИмя драйвера, например sqlite; не версия SQL.
ORACLE_NULLSNULL_NATURAL без преобразования; NULL_EMPTY_STRING: пустая строка → null; NULL_TO_STRING: null → пустая строка. Это изменяет смысл отсутствующих значений.
PERSISTENTПостоянное соединение; задают при открытии, не setAttribute после него.
STATEMENT_CLASSМассив [имя класса-наследника PDOStatement, аргументы его конструктора]; несовместим с persistent.
FETCH_CATALOG_NAMESПрефикс catalog. у имён возвращаемых колонок, если драйвер поддерживает.
FETCH_TABLE_NAMESПрефикс table. у имён возвращаемых колонок, если драйвер поддерживает.
STRINGIFY_FETCHESПолучать значения строками, кроме null; NULL_TO_STRING может преобразовать и null.
MAX_COLUMN_LENМаксимальная длина имени колонки; наличие константы не гарантирует поддержку атрибута.
DEFAULT_FETCH_MODEРежим чтения по умолчанию; исходно FETCH_BOTH. Для прикладных массивов часто удобен FETCH_ASSOC.
EMULATE_PREPARESЭмуляция подготовленных команд; поддержка native SQL зависит от драйвера. Подробности в prepare.
DEFAULT_STR_PARAMPARAM_STR_NATL либо PARAM_STR_CHAR по умолчанию для строк; PHP 7.2+.

Как читать этот вариант. CASE_LOWER нормализует имена, STRINGIFY_FETCHES — типы значений. Менять договор стоит осознанно: сравнение === 42 после преобразования в строку уже не пройдёт.

Менять имена ключей, сохраняя значениеСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
$row = $db->query("SELECT 'Pen' AS PRODUCT_NAME")->fetch(PDO::FETCH_ASSOC);
echo $row['product_name'], "\n";
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
var_dump($db->query('SELECT 42')->fetchColumn());
Ожидаемый результат
Pen
string(2) "42"

Ошибки: ERRMODE_SILENT требует проверять false и errorInfo; ERRMODE_WARNING дополнительно выдаёт E_WARNING; ERRMODE_EXCEPTION выбрасывает PDOException, это default с PHP 8.0. ERR_NONE — строка SQLSTATE 00000, успех. Исключения аргументов/состояния и ошибка соединения не обязаны подчиняться выбранному режиму SQL-ошибок.

КурсорСмысл
CURSOR_FWDONLYБыстрый обычный проход вперёд.
CURSOR_SCROLLПрокрутка при поддержке драйвера; может иметь цену памяти/буферизации.
FETCH_ORI_NEXT / PRIORСледующая / предыдущая строка.
FETCH_ORI_FIRST / LASTПервая / последняя.
FETCH_ORI_ABS / RELАбсолютный номер / смещение относительно позиции; третий аргумент fetch.

События для разработчиков драйверов: PARAM_EVT_ALLOC выделение, PARAM_EVT_FREE освобождение, PARAM_EVT_EXEC_PRE/POST до/после исполнения, PARAM_EVT_FETCH_PRE/POST до/после чтения, PARAM_EVT_NORMALIZE нормализация имени при регистрации привязки. Они не регистрируют PHP callback приложения и не являются заменой обработчикам событий сайта.

Разные семейства выполняют разные роли
  1. PARAM_INT описывает значение 2
  2. ATTR_CASE выбирает политику ключей
  3. CASE_LOWER — значение этой политики
  4. FETCH_ASSOC выбирает форму результата

Примеры применения: PDO::setAttribute(), PDOStatement::bindValue(), PDOStatement::fetch().

Все режимы чтения: массив, объект, группа и преобразование

Один SELECT может дать одинаковые значения в разных контейнерах PHP. Сначала определите нужную форму: строка товара, словарь, группа заказов или последовательный экспорт. fetch читает следующую строку; fetchAll забирает весь остаток, поэтому режим нельзя выбирать отдельно от размера результата.

PDO::Форма и ограничение
FETCH_DEFAULTРежим, ранее установленный statement/соединению; значение 0 с PHP 8.0.
FETCH_ASSOCМассив имя колонки → значение. Одинаковые имена из JOIN перезаписываются; задавайте AS.
FETCH_NUMМассив с индексами 0, 1… в порядке SELECT. Перестановка колонок меняет индексы.
FETCH_BOTHИменованные и числовые ключи одновременно; это не удвоение числа строк.
FETCH_NAMEDИменованные ключи; одинаковые имена колонок дают массив их значений.
FETCH_OBJНовый stdClass со свойствами, соответствующими колонкам.
FETCH_COLUMNОдна колонка, индекс с нуля; fetchColumn не отличает boolean false от конца.
FETCH_KEY_PAIRТолько fetchAll, ровно две колонки: первая ключ, вторая значение. Дубликаты ключа перезаписываются.
FETCH_CLASSНовый объект указанного класса для каждой строки; свойства по умолчанию заполняются до конструктора.
FETCH_PROPS_LATEФлаг с FETCH_CLASS: сначала конструктор, затем свойства. Проверки конструктора ещё не видят эти SQL-данные.
FETCH_CLASSTYPEФлаг с FETCH_CLASS: первая колонка выбирает имя класса и исключается из данных. Не принимайте имя произвольного класса от внешнего ввода.
FETCH_INTOfetch в заранее переданный объект; следующие строки изменяют тот же объект. Не подходит fetchAll.
FETCH_LAZYfetch возвращает PDORow с доступом по свойству/индексу. Это живое представление текущей строки, не независимый DTO.
FETCH_BOUNDfetch записывает значения в переменные bindColumn и возвращает true; конец false. Не предназначен для fetchAll.
FETCH_FUNCТолько fetchAll: callback получает выбранные колонки аргументами, результат callback становится элементом массива.
FETCH_GROUPФлаг fetchAll: группировка по первой колонке, её убирают из содержимого строки; дубликаты объединяются в список.
FETCH_UNIQUEФлаг fetchAll: индекс по первой колонке без неё в строке; последняя строка с тем же ключом заменяет предыдущую.
FETCH_SERIALIZEИсторический флаг с FETCH_CLASS для Serializable, deprecated с PHP 8.1. Не используйте для нового кода; явное отображение полей понятнее и безопаснее.
Одна таблица — разные формы
  1. SELECT id,name даёт две колонки
  2. FETCH_ASSOC → [id=>1,name=>Pen]
  3. FETCH_KEY_PAIR → [1=>Pen,2=>Notebook,…]
  4. FETCH_GROUP → ключ группы и список её строк

Как читать этот вариант. NAMED сохраняет оба id, но такая форма неудобна для бизнеса. Явные AS product_id и AS category_id обычно лучше показывают смысл.

Увидеть одинаковые имена JOIN-колонокСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$s = $db->query("SELECT 10 AS id, 20 AS id, 'Pen' AS name");
var_export($s->fetch(PDO::FETCH_NAMED));
Ожидаемый результат
array (
  'id' => 
  array (
    0 => 10,
    1 => 20,
  ),
  'name' => 'Pen',
)

Как читать этот вариант. Нужны ровно две колонки. Такой словарь удобен для списка выбора; отсутствующий ключ надо проверять, он не означает пустую строку.

Получить словарь ID → названиеСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
var_export($db->query('SELECT id, name FROM products ORDER BY id')->fetchAll(PDO::FETCH_KEY_PAIR));
Ожидаемый результат
array (
  1 => 'Pen',
  2 => 'Notebook',
  3 => 'Box',
)

Как читать этот вариант. Callback получает колонки по порядку SELECT, а не массив строки. fetchAll всё равно собирает полный результирующий массив; это не потоковый экспорт.

Преобразовать строки в подписи спискаСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$labels = $db->query('SELECT name, price FROM products ORDER BY id')->fetchAll(PDO::FETCH_FUNC, fn ($name, $price) => $name . ': ' . $price);
echo implode("\n", $labels), "\n";
Ожидаемый результат
Pen: 120
Notebook: 350
Box: 200

Как читать этот вариант. Оператор | объединяет режим и флаг. UNIQUE не проверяет уникальность и не сообщает о потере old; для списка под каждым ключом используют GROUP.

Понять перезапись повторяющегося ключаСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$rows = $db->query("SELECT 'a' AS key, 'old' AS name UNION ALL SELECT 'a', 'new'")->fetchAll(PDO::FETCH_UNIQUE | PDO::FETCH_ASSOC);
echo $rows['a']['name'], "\n";
Ожидаемый результат
new

Как читать этот вариант. Сохраняется тот же объект: ссылка first после следующего fetch видит Notebook. Для независимых снимков читайте отдельные массивы/объекты.

Обновлять один объект текущей строкойСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$current = new stdClass();
$s = $db->query('SELECT name FROM products ORDER BY id');
$s->setFetchMode(PDO::FETCH_INTO, $current);
$first = $s->fetch();
echo $first->name, "\n";
$s->fetch();
echo $first->name, "\n";
var_dump($first === $current);
Ожидаемый результат
Pen
Notebook
bool(true)

Как читать этот вариант. PDORow даёт доступ по имени свойства, строковому и числовому ключу. Его queryString хранит SQL исходного statement. Отсутствующее свойство возвращает null без warning; запись/удаление свойства бросает Error, поэтому это не обычный изменяемый stdClass. Он связан с statement и не сериализуется; независимые данные копируют явно.

Прочитать PDORow, затем сделать независимый снимокСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$s = $db->query('SELECT id, name FROM products ORDER BY id');
$row = $s->fetch(PDO::FETCH_LAZY);
echo get_class($row), ':', $row->name, ':', $row[0], "\n";
$snapshot = ['id' => $row['id'], 'name' => $row['name']];
$s->fetch(PDO::FETCH_LAZY);
echo $snapshot['name'], "\n";
Ожидаемый результат
PDORow:Pen:1
Pen

Как читать этот вариант. Имя класса здесь — доверенный литерал SQL, а не поле, записанное посетителем. Для сложных моделей явный конструктор/mapper даёт более ясные проверки.

Выбрать заранее известный класс строкиСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
class ProductRow { public string $name; }
$s = $db->query("SELECT 'ProductRow' AS class_name, 'Pen' AS name");
$row = $s->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE)[0];
echo get_class($row), ':', $row->name, "\n";
Ожидаемый результат
ProductRow:Pen

Для FETCH_CLASS конструктор и заполнение свойств — разные этапы. Без PROPS_LATE значения свойств доступны конструктору, но обходят его параметры/проверки; неизвестная колонка может вызвать __set либо динамическое свойство (deprecated с PHP 8.2). У readonly/типизированных свойств есть дополнительные ограничения. CLASSTYPE извлекает класс из первой колонки; вместе с GROUP первой становится колонка ключа группы, следующей — класс. GROUP/UNIQUE съедают ключ группировки; FETCH_FUNC получает оставшиеся колонки. Повтор GROUP|UNIQUE не создаёт «уникальные группы» — UNIQUE уже задаёт своё поведение.

У FETCH_COLUMN|FETCH_GROUP индекс задаёт колонку значения с учётом правил fetchAll; явно выбирайте SQL и сравните ожидаемую форму, не угадывайте индексы. Для уникальных ключей SQL-тип может превращаться в ключ PHP: числовые строковые ключи подчиняются правилам массивов. Не формируйте бизнес-индекс без проверки дубликатов. FETCH_SERIALIZE устарел: его исторический callback Serializable::unserialize получает сериализованное содержимое первой колонки, остальные становятся свойствами; новый код преобразует разрешённые поля явно.

Полные примеры GROUP, CLASS/PROPS_LATE, BOUND и scrollable: PDOStatement::fetchAll(), PDOStatement::setFetchMode(), PDOStatement::bindColumn(), PDOStatement::fetch().

Все одиннадцать драйверов: выбрать свою ветку

PDO унифицирует работу со значениями, но не разницы SQL, типов дат, auto increment, транзакций и блокировок. Для новой системы выбирают подходящую СУБД по задаче и сопровождению; для интеграции часто уже задана существующая. Драйвер подключается к ней, не заменяет сервер.

Методы общих PDO/PDOStatement читают в едином справочнике ниже. Драйверные методы и константы используются только в своей ветке. Контекстные примеры других СУБД имеют ожидаемый результат и необходимые условия, но локальная проверка PHP-синтаксиса не выдаётся за подключение к этим серверам.

MySQL и MariaDB: настройка, DSN и границы переносимости

Задача: подключить PHP к MySQL и MariaDB и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_mysql
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

Драйвер pdo_mysql использует mysqlnd по умолчанию либо libmysqlclient. В пакетной системе устанавливают расширение для своей версии PHP; старые имена php5-mysql из исторических руководств к PHP 8 не относятся. При сборке --with-pdo-mysql[=DIR], путь сокета --with-mysql-sock; библиотека сжатия задаётся --with-zlib-dir. Современный PHP поддерживает caching_sha2_password (mysqlnd с 7.4.4): не понижайте серверную аутентификацию ради старого учебного совета.

Компонент DSNСмысл
host / portАдрес и TCP-порт. На Unix localhost выбирает Unix-сокет, а 127.0.0.1 — TCP.
dbnameИмя базы.
charsetКодировка соединения, для современного текста обычно utf8mb4.
unix_socketПуть Unix-сокета вместо host/port.
user / passwordДопустимы в DSN, но отдельно переданные аргументы конструктора имеют приоритет; секреты удобнее не включать в диагностируемую строку.

pdo_mysql.default_socket (INI_SYSTEM, Unix; типичный default /tmp/mysql.sock, может определяться сборкой) задаёт сокет mysqlnd. pdo_mysql.debug (INI_SYSTEM, default NULL) доступен только с mysqlnd и PDO debug build. При libmysqlclient сокет берётся из её настроек сборки. Эмуляция prepare включена по умолчанию. Укажите выбранный режим явно и проверьте поддержку SQL. INOUT bindParam у PDO_MYSQL не обновляет выходное значение; используйте поддерживаемый договор процедуры/результатов. Транзакции требуют транзакционных таблиц, DDL может вызвать implicit commit. Параметры TLS задаются при создании соединения: setAttribute после подключения не включает шифрование задним числом. Буферизация результатов по умолчанию хранит их у клиента; unbuffered экономит этот буфер, но до дочитывания нельзя свободно выполнять следующий запрос.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с MySQL и MariaDB не устанавливалось.

Подключение: MySQL и MariaDBПример для указанного окружения
<?php
$dsn = 'mysql:host=127.0.0.1;port=3306;dbname=shop;charset=utf8mb4';
$db = new Pdo\Mysql($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
mysql

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: MySQL и MariaDBПример для указанного окружения
<?php
$dsn = 'mysql:unix_socket=/run/mysqld/mysqld.sock;dbname=shop;charset=utf8mb4';
$db = new Pdo\Mysql($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

PostgreSQL: настройка, DSN и границы переносимости

Задача: подключить PHP к PostgreSQL и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_pgsql
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

Нужны pdo_pgsql и libpq; с PHP 8.4 требуется libpq не ниже 10.0. Сборка --with-pdo-pgsql[=DIR], где DIR — база установки PostgreSQL либо pg_config. Расширение даёт обычный PDO и поток для large objects; наличие расширения PostgreSQL pgsql отдельно не означает наличие pdo_pgsql.

Компонент DSNСмысл
host / portСервер/порт; абсолютный каталог host=/var/run/postgresql выбирает Unix-сокет.
dbnameБаза.
user / passwordС PHP 8.4 значения в DSN имеют приоритет над аргументами конструктора; раньше наоборот.
sslmodedisable, allow, prefer, require, verify-ca, verify-full. Для проверки цепочки и имени сервера нужен соответствующий строгий режим и настроенный доверенный CA.
РазделительПробелы или ;. PDO заменяет все ; пробелами: точка с запятой внутри компонента DSN не поддерживается.

Драйверный парсер PHP 8.4 понимает обычные кавычки, E-строки, dollar quoting, -- и невложенные /* */. Оператор ? снаружи строк при переписывании экранируют ??; внутри dollar-quoted строки этого не нужно, такое удвоение deprecated с 8.4. bytea возвращается потоком и отличается от отдельного large object с OID. В PHP 8.5 ATTR_PREFETCH=0 включает последовательную выдачу одной строки, любое другое значение оставляет буферизацию; новый запрос на соединении молча отбрасывает непрочитанные строки предыдущего lazy-result. Планируйте одно активное чтение.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с PostgreSQL не устанавливалось.

Подключение: PostgreSQLПример для указанного окружения
<?php
$dsn = 'pgsql:host=db.example.test;port=5432;dbname=shop;sslmode=verify-full';
$db = new Pdo\Pgsql($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
pgsql

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: PostgreSQLПример для указанного окружения
<?php
$dsn = 'pgsql:host=/var/run/postgresql;port=5432;dbname=shop';
$db = new Pdo\Pgsql($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

SQLite: локальный файл или база в памяти: настройка, DSN и границы переносимости

Задача: подключить PHP к SQLite: локальный файл или база в памяти и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_sqlite
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

PDO_SQLITE обычно включён вместе с PDO; для исключения при сборке --without-pdo-sqlite[=DIR]. С PHP 7.4 нужна внешняя libsqlite >=3.5.0, с PHP 8.5 >=3.7.17; отдельные новые API требуют более новой библиотеки. На Windows libsqlite3.dll должна находиться в доступном PATH рядом с корректным PHP-окружением; копировать библиотеки в системную папку ради урока не следует.

Компонент DSNСмысл
sqlite:/absolute/path/shop.sqliteПостоянный файл; на Windows допустим sqlite:C:/data/shop.sqlite. Каталог и сам файл должны иметь нужные права.
sqlite::memory:Новая независимая база в памяти конкретного соединения.
sqlite:Временная база, удаляемая при закрытии соединения.
Логин / парольОбычный SQLite не использует их для аутентификации; защита определяется доступом к файлу/процессу.

PDO_SQLITE поддерживает PARAM_LOB как потоки и строки. SQLite исполняется внутри процесса, отдельного DB-сервера нет; это удобно для учебных примеров, небольших сервисов и локальных инструментов. Конкурентные записи и блокировки требуют собственного проектирования: замена MySQL DSN на sqlite: не делает диалекты/режимы конкурентности идентичными. Парсер понимает одинарные/двойные/backtick кавычки с удвоением, квадратные скобки идентификаторов и --, /* */ комментарии.

Как читать этот вариант. new создаёт объект соединения, sqlite: выбирает драйвер, :memory: — временную область этой базы. query исполняет SELECT, fetchColumn достаёт его единственное значение.

Создать учебную базу SQLite без сервераСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
echo $db->query('SELECT 42')->fetchColumn(), "\n";
Ожидаемый результат
42

Как читать этот вариант. Пустая часть после sqlite: выбирает временную БД. Когда исчезнут все ссылки на соединение/statement, ресурс закрывается; эту схему не используют для постоянных пользовательских данных.

Использовать временную базу без имени файлаСамостоятельный пример
<?php
$db = new PDO('sqlite:');
$db->exec('CREATE TABLE notes (text TEXT)');
$db->exec("INSERT INTO notes VALUES ('Draft')");
echo $db->query('SELECT text FROM notes')->fetchColumn(), "\n";
$db = null;
Ожидаемый результат
Draft

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

ODBC: общий мост к установленному драйверу: настройка, DSN и границы переносимости

Задача: подключить PHP к ODBC: общий мост к установленному драйверу и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_odbc
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

PDO_ODBC обращается к ODBC driver manager и конкретному драйверу БД; все три слоя должны совпадать по разрядности/окружению. Windows: php_pdo_odbc.dll и System DSN, доступный учётной записи веб-процесса. Unix варианты сборки: --with-pdo-odbc=unixODBC,/usr/local; ibm-db2,/path/to/client; generic,/prefix,libname,ldflags,cflags. Для DB2 нужны клиентские заголовки/библиотеки; исторический default каталог /home/db2inst1/sqllib относится к сборке, не к любому серверу.

Компонент DSNСмысл
odbc:CatalogNameИмя настроенного источника в ODBC manager или каталоге DB2.
odbc:DRIVER={...};...Полная строка подключения конкретного драйвера.
UID / PWDС PHP 8.4 каждое поле DSN отдельно перекрывает соответствующий аргумент конструктора; раньше наличие одного могло игнорировать оба.
Пустой passwordС PHP 8.4 пустая строка явно добавляет пустой PWD; null сохраняет отсутствие параметра.

PDO_ODBC_TYPE сообщает библиотеку: unixODBC/iODBC/generic и др., но не диалект SQL сервера. quote не поддерживается универсально: используйте prepare. Если manager умеет pooling, оставляйте кеширование этому слою вместо двойного PDO persistent. pdo_odbc.connection_pooling= strict (default), relaxed либо off/пусто; фактически настройка php.ini на весь процесс. relaxed может смешать состояние соединений разных приложений и не подходит общему серверу. pdo_odbc.db2_instance_name — устаревающая настройка DB2INSTANCE для Unix, INI_SYSTEM, на Windows не действует.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с ODBC: общий мост к установленному драйверу не устанавливалось.

Подключение: ODBC: общий мост к установленному драйверуПример для указанного окружения
<?php
$dsn = 'odbc:ShopDSN';
$db = new Pdo\Odbc($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
odbc

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: ODBC: общий мост к установленному драйверуПример для указанного окружения
<?php
$dsn = 'odbc:DRIVER={IBM DB2 ODBC DRIVER};HOSTNAME=db.example.test;PORT=50000;DATABASE=SHOP;PROTOCOL=TCPIP;';
$db = new Pdo\Odbc($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

Microsoft SQL Server и Azure SQL: настройка, DSN и границы переносимости

Задача: подключить PHP к Microsoft SQL Server и Azure SQL и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_sqlsrv
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

PDO_SQLSRV распространяется Microsoft отдельно: совместимая версия PHP, системный ODBC-драйвер Microsoft и само PHP-расширение. Windows DLL выбирают по версии PHP, TS/NTS и архитектуре, Linux/macOS используют PECL и системные зависимости. Страница PHP описывает семейство, но старое «SQL Server 2005+» не заменяет текущую матрицу поддерживаемого сервера/клиента Microsoft. SQLSRV procedural extension и PDO_SQLSRV — разные интерфейсы.

Компонент DSNСмысл
Server / DatabaseАдрес сервера, при необходимости instance/порт через запятую, и имя БД.
APP / WSIDИмя приложения и компьютера для диагностики.
LoginTimeoutОжидание соединения в секундах.
ConnectionPooling1/true включает пул, 0/false выключает; учитывайте возможности ОС/драйвера.
Encrypt / TrustServerCertificateШифрование и проверка сертификата. В примере шифрование включено, обход проверки отключён.
Failover_PartnerНастроенный партнёр зеркалирования, не произвольная резервная строка.
MultipleActiveResultSetsВключить/отключить MARS для нескольких активных результатов.
QuotedIdSQL-92 правила quoted identifiers или старые Transact-SQL.
TraceOn / TraceFileТрассировка ODBC и файл; может содержать чувствительные сведения.
TransactionIsolationSQLSRV_TXN_READ_UNCOMMITTED/READ_COMMITTED/REPEATABLE_READ/SNAPSHOT/SERIALIZABLE.

Безопасность TLS требует доверенной цепочки и имени сертификата сервера; TrustServerCertificate=1 обходил бы проверку. SQLSRV_ATTR_QUERY_TIMEOUT задаёт запрос в секундах, 0 без ограничения; это не LoginTimeout. SQLSRV_ATTR_DIRECT_QUERY выбирает непосредственное исполнение вместо подготовленного. SQLSRV_ENCODING_UTF8 — обычный default; SYSTEM использует кодовую страницу и может заменять непредставимые символы ?, BINARY сохраняет байты, DEFAULT наследует контекст. Точный набор опций/аутентификации проверяют в документации установленного Microsoft driver.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с Microsoft SQL Server и Azure SQL не устанавливалось.

Подключение: Microsoft SQL Server и Azure SQLПример для указанного окружения
<?php
$dsn = 'sqlsrv:Server=db.example.test,1433;Database=shop;Encrypt=1;TrustServerCertificate=0';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
sqlsrv

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: Microsoft SQL Server и Azure SQLПример для указанного окружения
<?php
$dsn = 'sqlsrv:Server=tenant.database.windows.net;Database=shop;Encrypt=1;TrustServerCertificate=0';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

FreeTDS: SQL Server и Sybase: настройка, DSN и границы переносимости

Задача: подключить PHP к FreeTDS: SQL Server и Sybase и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_dblib
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

PDO_DBLIB использует FreeTDS для SQL Server/Sybase. Современный Windows-проект должен выбирать PDO_SQLSRV либо PDO_ODBC: старый нативный DB-LIB Windows не поддерживается. Названия mssql: и sybase: в старом руководстве описывали сборки под Microsoft DB-LIB/Sybase ct-lib; для FreeTDS применяется dblib:.

Компонент DSNСмысл
hostСервер; default 127.0.0.1.
dbnameИмя базы.
charsetКлиентская кодировка.
appnameИмя приложения в серверной диагностике; исторические defaults PHP Generic DB-lib/PHP freetds.
secureИсторическое поле, не используется; не включает TLS.

С PHP 8.4 подкласс Pdo\Dblib содержит драйверные константы. ATTR_CONNECTION_TIMEOUT задаётся в опциях открытия, ATTR_QUERY_TIMEOUT — ожидание запроса (секунды); значения общих/драйверных timeout надо согласовать. ATTR_STRINGIFY_UNIQUEIDENTIFIER выбирает строковое представление uniqueidentifier; ATTR_VERSION — версия клиентской библиотеки, ATTR_TDS_VERSION — протокол; ATTR_SKIP_EMPTY_ROWSETS пропускает пустые наборы. ATTR_DATETIME_CONVERT=false сохраняет серверный формат даты, true использует пользовательский/локальный FreeTDS locales.conf. Формат текста даты не является часовым поясом.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с FreeTDS: SQL Server и Sybase не устанавливалось.

Подключение: FreeTDS: SQL Server и SybaseПример для указанного окружения
<?php
$dsn = 'dblib:host=db.example.test;dbname=shop;charset=UTF-8;appname=ShopWorker';
$db = new Pdo\Dblib($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
dblib

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: FreeTDS: SQL Server и SybaseПример для указанного окружения
<?php
$dsn = 'dblib:host=reporting.example.test;dbname=reports;charset=UTF-8;appname=ReportExport';
$db = new Pdo\Dblib($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

Firebird: настройка, DSN и границы переносимости

Задача: подключить PHP к Firebird и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_firebird
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

Сборка --with-pdo-firebird[=DIR]. Начиная с PHP 8.4 драйвер использует Firebird C++ API, требует C++ compiler и fbclient >=3.0. Сервер и клиентская библиотека — разные компоненты; версия API сборки доступна через статический getApiVersion.

Компонент DSNСмысл
dbnameЛокальный путь /data/SHOP.FDB либо host/port:/server/path/SHOP.FDB. При серверном подключении путь относится к серверу.
charsetКодировка соединения, например UTF8.
roleSQL-роль.
dialect1 либо 3, по умолчанию 3; параметр с PHP 7.4.

ATTR_DATE_FORMAT, ATTR_TIME_FORMAT, ATTR_TIMESTAMP_FORMAT меняют формат выдачи. TRANSACTION_ISOLATION_LEVEL принимает READ_COMMITTED (default), REPEATABLE_READ (Firebird snapshot), SERIALIZABLE (snapshot table stability). WRITABLE_TRANSACTION=true по умолчанию означает READ WRITE, false READ ONLY. Это настройки драйвера, не универсальные PDO-константы. Старые PDO::FB_ATTR_* устарели с 8.5: используйте Pdo\Firebird::*.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с Firebird не устанавливалось.

Подключение: FirebirdПример для указанного окружения
<?php
$dsn = 'firebird:dbname=db.example.test/3050:/data/SHOP.FDB;charset=UTF8;dialect=3';
$db = new Pdo\Firebird($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
firebird

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: FirebirdПример для указанного окружения
<?php
$dsn = 'firebird:dbname=/data/SHOP.FDB;charset=UTF8;dialect=3';
$db = new Pdo\Firebird($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

IBM Db2: настройка, DSN и границы переносимости

Задача: подключить PHP к IBM Db2 и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_ibm
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

PDO_IBM — PECL-расширение с IBM клиентом. Базовое руководство указывает DB2 Client >=9.1 и сборку --with-pdo-ibm=/path/to/sqllib[,shared], default из DB2DIR. Это исторический минимум исходного API, а совместимость современной Db2/IBM i/z/OS, PHP и лицензирования DB2 Connect проверяют по установленному клиенту IBM. Наличие Db2 на удалённом сервере не заменяет клиентские библиотеки на машине PHP.

Компонент DSNСмысл
ibm:DSN=NameИсточник из db2cli.ini или odbc.ini.
ibm:CatalogAliasКаталогизированная база клиента DB2.
DRIVER={IBM DB2 ODBC DRIVER}Полная IBM CLI строка без предварительного alias.
DATABASE / HOSTNAME / PORT / PROTOCOLИмя базы, адрес, TCP-порт и TCPIP.
UID / PWDПользователь и пароль внутри CLI-строки; предпочтительна защищённая конфигурация, не публичный исходник.

На IBM i pdo_ibm.i5_dbcs_alloc (default 0, INI_SYSTEM, с PDO_IBM 1.5.0) переключает увеличенные внутренние буферы при неверной оценке размера символов: 1 расходует существенно больше памяти, в документации до шести раз. pdo_ibm.i5_override_ccsid (default 0, INI_SYSTEM) задаёт ASCII CCSID преобразования из EBCDIC; 1208 выбирает UTF-8, 0 — кодовую страницу задания. Выбирайте кодировку по договору данных, не лечите обрезание строки случайным расширением всех буферов.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с IBM Db2 не устанавливалось.

Подключение: IBM Db2Пример для указанного окружения
<?php
$dsn = 'ibm:DSN=ShopDB2';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
ibm

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: IBM Db2Пример для указанного окружения
<?php
$dsn = 'ibm:DRIVER={IBM DB2 ODBC DRIVER};DATABASE=SHOP;HOSTNAME=db.example.test;PORT=50000;PROTOCOL=TCPIP;';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

IBM Informix: настройка, DSN и границы переносимости

Задача: подключить PHP к IBM Informix и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_informix
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

PDO_INFORMIX — PECL-расширение, требуется Informix Client SDK; исходное руководство указывает >=2.81 UC1. Сборка --with-pdo-informix=/path/to/SDK[,shared], по умолчанию INFORMIXDIR. Актуальная совместимость версии расширения, PHP и SDK должна проверяться для целевого окружения, а не по номеру исторического примера.

Компонент DSNСмысл
informix:DSN=NameИсточник из odbc.ini.
host / serviceСервер и имя сервиса/порт.
database / serverБаза и имя Informix server.
protocolНапример onsoctcp.
EnableScrollableCursors=1Разрешает прокручиваемые курсоры; эквивалент ENABLESCROLLABLECURSORS=1 в odbc.ini.

Scrollable cursor требует сразу двух уровней: разрешить его в строке/источнике ODBC и заказать ATTR_CURSOR => CURSOR_SCROLL при prepare. Без реальной потребности последовательное чтение проще. Поля Database, Servername, DB_LOCALE, OPTIMIZEAUTOCOMMIT и клиентский Driver в odbc.ini согласуют с SDK; пароли конфигурации не должны попадать в репозиторий/HTTP-диагностику.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с IBM Informix не устанавливалось.

Подключение: IBM InformixПример для указанного окружения
<?php
$dsn = 'informix:DSN=ShopInformix';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
informix

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: IBM InformixПример для указанного окружения
<?php
$dsn = 'informix:host=db.example.test;service=9088;database=shop;server=shop_server;protocol=onsoctcp;EnableScrollableCursors=1';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

Oracle: настройка, DSN и границы переносимости

Задача: подключить PHP к Oracle и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_oci
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

Если Oracle рядом с PHP, клиентские библиотеки обычно есть в установке; на другой машине нужен Oracle Instant Client и SDK для сборки. С PHP 8.4 PDO_OCI перенесён в PECL и не входит в дистрибутив PHP. Для старых PHP <8.4 --with-pdo-oci[=DIR] (default ORACLE_HOME) либо --with-pdo-oci=instantclient,prefix,version; это исторический способ, не команда установки текущего PECL-пакета.

Компонент DSNСмысл
dbname=AliasИмя из tnsnames.ora.
dbname=//host:port/serviceEasy Connect через Instant Client.
charsetКлиентская кодировка Oracle handle, например AL32UTF8.

PDO::OCI_ATTR_ACTION, OCI_ATTR_CLIENT_INFO, OCI_ATTR_CLIENT_IDENTIFIER, OCI_ATTR_MODULE помечают действие/клиента/идентификатор/модуль серверной сессии; доступны с PHP 7.2.16/7.3.3 в соответствующей ветке. Не используйте идентификатор как автоматическую авторизацию. Для BLOB вставка EMPTY_BLOB() RETURNING ... INTO требует транзакции: иначе implicit commit может сохранить пустой LOB до записи. DDL также может фиксировать работу. Для широкого Oracle API существует отдельное расширение OCI8.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с Oracle не устанавливалось.

Подключение: OracleПример для указанного окружения
<?php
$dsn = 'oci:dbname=//db.example.test:1521/SHOP;charset=AL32UTF8';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
oci

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: OracleПример для указанного окружения
<?php
$dsn = 'oci:dbname=SHOP_TNS;charset=AL32UTF8';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

CUBRID: настройка, DSN и границы переносимости

Задача: подключить PHP к CUBRID и получить данные через знакомые prepare → execute → fetch. Одинаковые методы облегчают работу, но SQL, типы, блокировки, кодировки и расширенные возможности остаются договором конкретной СУБД.

Что должно быть готово
  1. PHP загружает pdo_cubrid
  2. Клиентская библиотека/драйвер понимает DSN
  3. Сервер или локальный файл разрешает доступ
  4. PDOStatement возвращает строки PHP

PDO_CUBRID — PECL-расширение. Официальное руководство требует CUBRID DBMS на машине сборки PHP; --with-pdo-cubrid=/path/to/CUBRID[,shared], путь по умолчанию из CUBRID. Windows DLL не обещана руководством: проверяют пакет/сборку и его build-guide. Persistent-соединения описанной версией драйвера не поддерживаются.

Компонент DSNСмысл
hostСервер CUBRID.
portПорт брокера.
dbnameБаза.
Пользователь / парольПередаются отдельно от DSN в конструктор.

Драйвер поддерживает scrollable cursor через prepare options, timeout исполнения через setAttribute, несколько SQL-команд через ;, BLOB/CLOB как потоки и типы SET/MULTISET/SEQUENCE. Autocommit включён по умолчанию; beginTransaction временно выключает и commit/rollback восстанавливает, но ручное переключение autocommit может фиксировать ожидающую работу. Метаданные схемы доступны cubrid_schema; его таблица ниже объясняет поля. Для коллекций bindParam может получать массив, а пятый driverOptions задаёт тип элемента — это исключение CUBRID, не универсальное правило параметров PDO.

Как читать этот вариант. Контекстный пример: установите соответствующий драйвер/клиент, создайте доступную базу, задайте адрес и права. DB_USER/DB_PASSWORD приходят из защищённой конфигурации сервера. Здесь только lint; соединение с CUBRID не устанавливалось.

Подключение: CUBRIDПример для указанного окружения
<?php
$dsn = 'cubrid:host=db.example.test;port=33000;dbname=shop';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
cubrid

Как читать этот вариант. Только синтаксическая проверка. Таблицу products создают миграцией целевой СУБД, а не включают CREATE в каждый HTTP-запрос. Данные пользователя передаются маркером ?, строка подключения остаётся доверенной.

Другой способ адресации: CUBRIDПример для указанного окружения
<?php
$dsn = 'cubrid:host=reporting.example.test;port=33000;dbname=reports';
$db = new PDO($dsn, getenv('DB_USER'), getenv('DB_PASSWORD'));
$statement = $db->prepare('SELECT name FROM products WHERE id = ?');
$statement->execute([42]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row === false ? "Товар не найден\n" : $row['name'] . "\n";
Ожидаемый результат
Для схемы products(id,name): название товара 42 либо Товар не найден.

Дальше: PDO::prepare(), PDOStatement::fetch(), PDO::beginTransaction(). Для смены СУБД проверьте SQL/схему/ограничения отдельно: PDO унифицирует вызовы, а не все свойства хранилища.

Полный список драйверных констант и их назначение

Проверяйте имя драйвера и версию PHP до использования расширения. Числовые значения драйверных атрибутов могут пересекаться: константа MySQL, переданная SQLite, не становится одноимённой настройкой. С PHP 8.4 есть классы Pdo\Mysql, Pdo\Pgsql, Pdo\Sqlite, Pdo\Odbc, Pdo\Firebird, Pdo\Dblib; они наследуют общие методы PDO. Старые PDO::MYSQL_*, PGSQL_*, SQLITE_*, ODBC_*, FB_* и DBLIB_* соответствуют драйверным именам; алиасы, помеченные в PHP 8.5 deprecated, заменяйте именами соответствующего Pdo-класса.

Pdo\Mysql: константы

Имя после Pdo\Mysql::Для чего
ATTR_USE_BUFFERED_QUERYБуферизация результата на клиенте, default true. false требует дочитать/закрыть результат до следующего запроса.
ATTR_LOCAL_INFILEРазрешить LOAD DATA LOCAL INFILE при открытии. Не включать для недоверенного сервера/пути.
ATTR_LOCAL_INFILE_DIRECTORYРазрешённый каталог для LOCAL INFILE, PHP 8.1+; ограничение зависит от конфигурации LOCAL INFILE и клиентской библиотеки.
ATTR_INIT_COMMANDSQL при подключении и автоматическом повторном подключении, только constructor options.
ATTR_READ_DEFAULT_FILEЧитать настройки клиентской библиотеки из файла; libmysqlclient, недоступно mysqlnd.
ATTR_READ_DEFAULT_GROUPГруппа настроек из конфигурационного файла; libmysqlclient, не mysqlnd.
ATTR_COMPRESSСжатие соединения, constructor options; расходует CPU ради меньшего трафика.
ATTR_DIRECT_QUERYАлиас PDO::ATTR_EMULATE_PREPARES: direct=true включает эмуляцию.
ATTR_FOUND_ROWSПри UPDATE считать найденные строки, а не только изменённые; только при открытии.
ATTR_IGNORE_SPACEРазрешить пробел после имени SQL-функции; имена становятся reserved words, только при открытии.
ATTR_MAX_BUFFER_SIZEЛимит буфера, default 1 MiB, не поддерживается mysqlnd.
ATTR_MULTI_STATEMENTSfalse отключает multiple statement execution в prepare/query; constructor options.
ATTR_SERVER_PUBLIC_KEYПуть RSA public key для аутентификации sha256, constructor options. Это не CA для TLS.
ATTR_SSL_KEYФайл закрытого ключа клиента TLS, constructor options.
ATTR_SSL_CERTФайл сертификата клиента TLS, constructor options.
ATTR_SSL_CAФайл CA для доверия серверному сертификату.
ATTR_SSL_CAPATHКаталог доверенных CA.
ATTR_SSL_CIPHERРазрешённые шифры TLS.
ATTR_SSL_VERIFY_SERVER_CERTПроверять сертификат сервера; mysqlnd. false ослабляет доверие и не является исправлением сертификата.

Pdo\Sqlite: константы

Имя после Pdo\Sqlite::Для чего
DETERMINISTICФункция при одинаковом входе даёт одинаковый результат; оптимизатор вправе использовать обещание.
OPEN_READONLYОткрыть существующую базу/LOB для чтения.
OPEN_READWRITEЧтение/запись существующего файла или LOB.
OPEN_CREATEСоздать отсутствующий файл в сочетании с OPEN_READWRITE.
ATTR_OPEN_FLAGSФлаги открытия в constructor options; default READWRITE|CREATE.
ATTR_READONLY_STATEMENTgetAttribute statement: подготовленная команда не меняет непосредственно файл БД; не полная гарантия отсутствия эффектов callback.
ATTR_EXTENDED_RESULT_CODESРасширенные коды ошибки SQLite вместо только базового кода.
ATTR_BUSY_STATEMENT8.5: выполненный statement ещё имеет непрочитанную строку, только чтение.
ATTR_EXPLAIN_STATEMENT8.5: изменить explain-режим statement; libsqlite сборки >=3.43, иначе ValueError.
EXPLAIN_MODE_PREPARED8.5: обычное выполнение как подготовлено.
EXPLAIN_MODE_EXPLAIN8.5: вернуть opcodes виртуальной машины SQLite.
EXPLAIN_MODE_EXPLAIN_QUERY_PLAN8.5: вернуть план запроса.
ATTR_TRANSACTION_MODE8.5: режим будущего beginTransaction; не переопределяет уже начатую транзакцию.
TRANSACTION_MODE_DEFERRED8.5: default, фактический тип блокировки определяется дальнейшей работой.
TRANSACTION_MODE_IMMEDIATE8.5: сразу начать write transaction; возможен busy уже на begin.
TRANSACTION_MODE_EXCLUSIVE8.5: exclusive; в WAL отличается от rollback journal, где блокирует также других читателей.
OK8.5: authorizer разрешает действие.
DENY8.5: authorizer запрещает команду.
IGNORE8.5: READ получает NULL; для других действий смысл надо сверять с SQLite, не универсальный запрет.

Pdo\Pgsql: константы

Имя после Pdo\Pgsql::Для чего
ATTR_DISABLE_PREPARESОтправлять запрос и параметры одним сообщением, минуя отдельный серверный prepare; это не простая вставка пользовательского текста в SQL.
ATTR_RESULT_MEMORY_SIZEgetAttribute у statement: память текущего PGresult в байтах; только libpq >=12, PHP 8.4+.
PDO::ATTR_PREFETCHОбщий атрибут: с PHP 8.5 значение 0 включает single-row lazy mode, любое другое — буферизованный результат.
TRANSACTION_IDLEИсторическая константа состояния; API PDO её не использует, deprecated 8.5.
TRANSACTION_ACTIVEНе используется, deprecated 8.5.
TRANSACTION_INTRANSНе используется, deprecated 8.5.
TRANSACTION_INERRORНе используется, deprecated 8.5.
TRANSACTION_UNKNOWNНе используется, deprecated 8.5.

Pdo\Odbc: константы

Имя после Pdo\Odbc::Для чего
ATTR_USE_CURSOR_LIBRARYSQL_USE_IF_NEEDED (default), SQL_USE_DRIVER или SQL_USE_ODBC; выбирать в constructor options.
ATTR_ASSUME_UTF8Windows: true преобразует UTF-16 CHAR/VARCHAR/LONGVARCHAR в UTF-8 при чтении/записи. Default false оставляет преобразование драйверу.
SQL_USE_IF_NEEDEDПодключать cursor library при необходимости.
SQL_USE_DRIVERИспользовать только возможности драйвера, без cursor library.
SQL_USE_ODBCВсегда применять ODBC cursor library.

Pdo\Firebird: константы

Имя после Pdo\Firebird::Для чего
ATTR_DATE_FORMATФормат текстовой даты.
ATTR_TIME_FORMATФормат текстового времени.
ATTR_TIMESTAMP_FORMATФормат timestamp; изменение представления не меняет часовую зону.
TRANSACTION_ISOLATION_LEVELREAD_COMMITTED, REPEATABLE_READ или SERIALIZABLE.
READ_COMMITTEDИзоляция по умолчанию.
REPEATABLE_READFirebird snapshot.
SERIALIZABLEFirebird snapshot table stability.
WRITABLE_TRANSACTIONtrue (default) READ WRITE; false READ ONLY. Настройка будущих транзакций.

Pdo\Dblib: константы

Имя после Pdo\Dblib::Для чего
ATTR_CONNECTION_TIMEOUTОжидание соединения, секунды; constructor options.
ATTR_QUERY_TIMEOUTВремя ожидания запроса, секунды.
ATTR_STRINGIFY_UNIQUEIDENTIFIERВыдавать UNIQUEIDENTIFIER строкой, а не бинарным представлением.
ATTR_VERSIONВерсия клиентской библиотеки DB-LIB; только чтение.
ATTR_TDS_VERSIONВерсия используемого протокола TDS; только чтение.
ATTR_SKIP_EMPTY_ROWSETSПропускать пустые наборы результатов.
ATTR_DATETIME_CONVERTtrue форматирует datetime с учётом локали FreeTDS; false сохраняет формат сервера.

PDO_ODBC_TYPE — отдельная глобальная строковая константа типа использованной ODBC-библиотеки; она не название текущей СУБД. Для Oracle константы PDO::OCI_ATTR_ACTION, OCI_ATTR_CLIENT_INFO, OCI_ATTR_CLIENT_IDENTIFIER, OCI_ATTR_MODULE задают метки действия, клиента, идентификатора и модуля текущей сессии. Они доступны с PHP 7.2.16/7.3.3 в соответствующих ветках. Метка клиента помогает DBA, но не заменяет проверку прав.

PDO::SQLSRV_…Назначение
TXN_READ_UNCOMMITTED / TXN_READ_COMMITTEDУровни изоляции для DSN TransactionIsolation.
TXN_REPEATABLE_READ / TXN_SNAPSHOT / TXN_SERIALIZABLEПовторяемое чтение / snapshot / сериализуемость; сервер должен поддерживать выбранный режим.
ENCODING_BINARYПередавать байты без преобразования; bindParam, bindColumn, prepare и statement attributes.
ENCODING_SYSTEMСистемная 8-битная кодовая страница Windows; непредставимые символы заменяются ?.
ENCODING_UTF8UTF-8, default драйвера.
ENCODING_DEFAULTДля соединения SYSTEM, для подготовленного statement наследует encoding соединения.
ATTR_QUERY_TIMEOUTНеотрицательные секунды запроса, 0 без ограничения; connection/statement/prepare.
ATTR_DIRECT_QUERYПрямое исполнение вместо подготовки, connection/prepare.
Применять настройку на верной границе
  1. Проверить драйвер и PHP
  2. Constructor options для свойств открытия
  3. setAttribute для поддерживаемой текущей настройки
  4. Statement getAttribute для состояния результата

Как читать этот вариант. PHP 8.5. IMMEDIATE пытается получить право на запись при начале транзакции. Изолированный пример не моделирует двух писателей и не доказывает отсутствие блокировок в нагруженном сервисе.

Начать запись с выбранным режимом блокировкиСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->exec('CREATE TABLE stock (quantity INTEGER)');
$db->exec('INSERT INTO stock VALUES (2)');
$db->setAttribute(Pdo\Sqlite::ATTR_TRANSACTION_MODE, Pdo\Sqlite::TRANSACTION_MODE_IMMEDIATE);
$db->beginTransaction();
$db->exec('UPDATE stock SET quantity = quantity - 1 WHERE quantity > 0');
$db->commit();
echo $db->query('SELECT quantity FROM stock')->fetchColumn(), "\n";
Ожидаемый результат
1

Как читать этот вариант. Контекстный lint: нужен pdo_mysql, доступный сервер и MYSQL_DSN с charset=utf8mb4. FOUND_ROWS=false означает изменённые строки UPDATE. TLS для удалённого сервера настраивают согласно CA/клиентской библиотеке; этот фрагмент не доказывает шифрование.

Зафиксировать политику соединения в одном местеПример для указанного окружения
<?php
$db = new Pdo\Mysql(getenv('MYSQL_DSN'), getenv('DB_USER'), getenv('DB_PASSWORD'), [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
    Pdo\Mysql::ATTR_MULTI_STATEMENTS => false,
    Pdo\Mysql::ATTR_FOUND_ROWS => false,
]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
Ожидаемый результат
mysql

CUBRID: коллекции, схема и все флаги

Расширения специфичной СУБД помогают администратору/импорту, но снижают переносимость. SET — набор уникальных значений, MULTISET допускает повтор, SEQUENCE хранит порядок. Типы пятого аргумента bindParam: CHAR, STRING, NCHAR, VARNCHAR, BIT, VARBIT, NUMERIC, NUMBER, INT, SHORT, BIGINT, MONETARY, FLOAT, DOUBLE, DATE, TIME, DATETIME, TIMESTAMP. Для отсутствующего явного типа применяется char.

Как читать этот вариант. CUBRID-специфичная привязка массива; тип элемента по умолчанию char. Это не шаблон SQL IN (?) для других драйверов. Здесь lint без подключения.

Передать набор строк как CUBRID SETПример для указанного окружения
<?php
$db = new PDO(getenv('CUBRID_DSN'), getenv('DB_USER'), getenv('DB_PASSWORD'));
// Учебная таблица course_tags(values_set SET(VARCHAR)) создана заранее.
$s = $db->prepare('INSERT INTO course_tags VALUES (?)');
$tags = ['php', 'pdo'];
$s->bindParam(1, $tags, PDO::PARAM_NULL);
var_dump($s->execute());
Ожидаемый результат
bool(true)

Как читать этот вариант. Пятый аргумент драйвера определяет тип элемента коллекции. Пример соответствует контракту PDO_CUBRID и не выполнялся на сервере.

Явно задать тип элемента коллекцииПример для указанного окружения
<?php
$db = new PDO(getenv('CUBRID_DSN'), getenv('DB_USER'), getenv('DB_PASSWORD'));
// Учебная таблица course_ids(values_set SET(INT)) создана заранее.
$s = $db->prepare('INSERT INTO course_ids VALUES (?)');
$ids = [1, 2, 3];
$s->bindParam(1, $ids, 0, 0, 'int');
var_dump($s->execute());
Ожидаемый результат
bool(true)
PDO::CUBRID_…Назначение
ATTR_ISOLATION_LEVELУровень изоляции соединения.
ATTR_LOCK_TIMEOUTОжидание блокировок/транзакции в секундах согласно CUBRID.
ATTR_MAX_STRING_LENGTHТолько чтение: максимальная длина строковых/битовых типов через PDO.
PDO::…Уровень CUBRID
TRAN_COMMIT_CLASS_UNCOMMIT_INSTANCE1: возможны dirty/non-repeatable/phantom для строк, non-repeatable для таблицы.
TRAN_COMMIT_CLASS_COMMIT_INSTANCE2: без dirty, но возможны non-repeatable/phantom.
TRAN_REP_CLASS_UNCOMMIT_INSTANCE3: default CUBRID описанной версии; repeatable схема/таблица, но dirty/non-repeatable/phantom строки.
TRAN_REP_CLASS_COMMIT_INSTANCE4: без dirty, возможны non-repeatable/phantom строки.
TRAN_REP_CLASS_REP_INSTANCE5: без dirty/non-repeatable, возможны phantom.
TRAN_SERIALIZABLE6: сериализуемость, предотвращает перечисленные аномалии ценой конкурентности.

Каждое имя ниже дополняется префиксом PDO::CUBRID_SCH_ и передаётся PDO::cubrid_schema(). Результат — список строк с указанными полями, false — ошибка. Аргументы таблиц/полей зависят от вида запроса. NULL отличается от пустой строки; LIKE-шаблоны разрешены только в поддерживающих их видах, не произвольно.

Вид схемыПоля результата и смысл
TABLENAME, TYPE: 0 системная, 1 view, 2 обычная таблица.
VIEWNAME, TYPE=1.
QUERY_SPECQUERY_SPEC — SQL определения view.
ATTRIBUTE / TABLE_ATTRIBUTEATTR_NAME, DOMAIN, SCALE, PRECISION, INDEXED, NOT NULL, SHARED, UNIQUE, DEFAULT, ATTR_ORDER (с 1), CLASS_NAME, SOURCE_CLASS, IS_KEY.
METHOD / TABLE_METHODNAME, RET_DOMAIN, ARG_DOMAIN; метод экземпляра / класса таблицы CUBRID, не метод PHP-класса.
METHOD_FILEMETHOD_FILE — файл определения метода.
SUPER_TABLE / DIRECT_SUPER_TABLE / SUB_TABLECLASS_NAME, TYPE; все родители / непосредственный родитель / потомки.
CONSTRAINTTYPE: 0 unique, 1 index, 2 reverse unique, 3 reverse index; NAME, ATTR_NAME, NUM_PAGES, NUM_KEYS, PRIMARY_KEY, KEY_ORDER (с 1).
TRIGGERNAME, STATUS, EVENT, TARGET_CLASS, TARGET_ATTR, ACTION_TIME, ACTION, PRIORITY, CONDITION_TIME, CONDITION.
TABLE_PRIVILEGECLASS_NAME, PRIVILEGE, GRANTABLE.
COL_PRIVILEGEATTR_NAME, PRIVILEGE, GRANTABLE.
PRIMARY_KEYCLASS_NAME, ATTR_NAME, KEY_SEQ (с 1), KEY_NAME.
IMPORTED_KEYS / EXPORTED_KEYS / CROSS_REFERENCEPKTABLE_NAME, PKCOLUMN_NAME, FKTABLE_NAME, FKCOLUMN_NAME, KEY_SEQ, UPDATE_ACTION, DELETE_ACTION, FK_NAME, PK_NAME. Страница/пример разных версий также использует UPDATE_RULE/DELETE_RULE: проверьте фактические ключи версии драйвера.

getColumnMeta CUBRID имеет собственные поля: type, name, table, def (default), precision, scale, not_null, auto_increment, unique_key, multiple_key, primary_key, foreign_key, reverse_index, reverse_unique. Не считайте их универсальными полями всех PDO-драйверов. Потоковый LOB вставляют bindParam(PARAM_LOB), читают как resource; при HTTP-выдаче сначала проверяют права и MIME. Примеры потоков — раздел LOB.

Инструмент миграции читает схему
  1. Выбрать CUBRID_SCH_PRIMARY_KEY
  2. Получить CLASS_NAME, ATTR_NAME, KEY_SEQ
  3. Проверить ожидаемую схему
  4. Планировать изменение отдельно от чтения метаданных

Практика: каталог, скорость и границы памяти

Упражнение: выведите товары по ID порциями и не храните весь каталог в PHP. Перед кодом уже изучены переменная, массив, условие и цикл: порядок циклов. Измените размер порции и убедитесь, что порядок/состав остаются теми же на неизменной таблице. Затем удалите товар 2 — ключи не обязаны идти подряд, запрос id > last всё равно найдёт следующий.

Как читать этот вариант. Порция не больше двух строк, ORDER BY стабилен по уникальному id. do/while выполняет тело хотя бы раз; пустая порция завершает. При изменяющихся данных нужна договорённость о snapshot/верхней границе/добавлении новых ID, иначе это не снимок каталога на одну секунду.

Прочитать каталог порциями по последнему IDСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$lastId = 0;
$s = $db->prepare('SELECT id, name FROM products WHERE id > :last ORDER BY id LIMIT 2');
do {
    $s->bindValue(':last', $lastId, PDO::PARAM_INT);
    $s->execute();
    $batch = $s->fetchAll(PDO::FETCH_ASSOC);
    foreach ($batch as $row) {
        echo $row['id'], ':', $row['name'], "\n";
        $lastId = $row['id'];
    }
} while ($batch !== []);
Ожидаемый результат
1:Pen
2:Notebook
3:Box

Индекс по id делает поиск следующей порции полезным; большой OFFSET часто заставляет сервер пройти лишние строки. fetchAll на миллион строк расходует память полного массива; fetch в цикле уменьшает этот массив, но не всегда драйверный буфер. SELECT * тянет ненужные данные, запрос в каждом цикле создаёт N+1 сетевых обращений, постоянный connect расходует время установления сессии. Анализируйте EXPLAIN, число запросов и задержку сети, а не объявляйте любую PDO-функцию «медленной». Транзакции держат короткими; sleep и внешние HTTP-запросы внутри удерживают блокировки дольше.

Уменьшаем объём работы
  1. WHERE и индекс выбирают нужные строки
  2. SELECT выбирает нужные колонки
  3. Ограниченная порция задаёт верхний размер массива
  4. Обработка завершает порцию до следующей

Следующий шаг — заказ и транзакционная целостность, разделение ответственности приложения. Доступ к данным можно передать классу Repository, но создание класса само по себе не ускоряет SQL и не заменяет знание этих договоров.

Указатель всех методов PDO по объектам

Общие методы находятся на исходных страницах базы/транзакций, остальные карточки — в этой главе; ссылки ведут к точному объяснению и примерам. Алиасы помечены историческими, чтобы старый код можно было понять и перевести на актуальный API.

PDO

PDOStatement

Pdo\Sqlite

Pdo\Pgsql

Pdo\Mysql

Pdo\Firebird

pdo_drivers()

Частые затруднения из реальной разработки

  • Разбор ситуации: bindValue сохраняет значение, bindParam читает привязанную переменную при execute.
  • Разбор ситуации: Повторное связывание одной переменной в foreach даёт неожиданные одинаковые параметры; используйте bindValue для текущего значения.
  • Разбор ситуации: HY093: набор/ключи execute должны соответствовать маркерам; не передавайте весь POST в SQL.
  • Разбор ситуации: Плейсхолдер — значение, не имя колонки; идентификаторы выбирают из разрешённого списка.
  • Разбор ситуации: MySQL различает найденные и изменённые строки UPDATE; успех execute не равен rowCount=1.
  • Разбор ситуации: rowCount=0 при повторной записи тех же значений не означает сбой; lastInsertId не идентификатор обновлённой строки.
  • Разбор ситуации: Память занимает не только PHP-массив, но и буфер драйвера; большой экспорт планируют целиком.
  • Разбор ситуации: Чтобы узнать число строк, SELECT COUNT(*) удобнее и дешевле загрузки всех записей.
  • Разбор ситуации: fetch в цикле убирает полный массив PHP, но сам по себе не отключает клиентскую буферизацию.

В обсуждениях встречаются старые версии и ошибочные ответы. В этом руководстве причина ситуации сопоставлена с текущим контрактом PDO; код и пояснения написаны для последовательного обучения, а ограничения конкретного драйвера отмечены отдельно.

Функции и методы этой темы

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

PDO::connectСоздать соединение с драйверным подклассом, если он предоставлен расширением.

PHP 8.4+ · PDO; соответствующий драйвер

PDO::connect(string $dsn, ?string $username = null, #[SensitiveParameter] ?string $password = null, ?array $options = null): static

Открыть каталог через фабрику PHP 8.4+. Статический вызов выбирает драйверный подкласс Pdo\Sqlite. Обычные query и fetch работают так же; дополнительный смысл — доступ к специальным возможностям SQLite.

Данные и действие: PDO::connect
  1. PDO::connect('sqlite::memory:')
  2. Фабрика создаёт соединение, схема даёт известные данные. Метод нужен для драйверного API; имя класса само по себе ещё не является полезным результатом запроса.
  3. После выполнения: Перчатки — 15 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Открыть каталог через фабрику PHP 8.4+Самостоятельный пример
<?php
$db = PDO::connect('sqlite::memory:');
$db->exec(file_get_contents(__DIR__ . '/schema.sql'));
$statement = $db->query('SELECT name, stock FROM products WHERE id = 2');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Перчатки — 15 шт.

Фабрика создаёт соединение, схема даёт известные данные. Метод нужен для драйверного API; имя класса само по себе ещё не является полезным результатом запроса.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Перчатки15 шт.

Если требование изменится. Требуется PHP 8.4+. Для общего кода PHP 8.2 остаётся new PDO; при смене драйвера специальный API и SQL нужно пересмотреть.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Создать соединение с драйверным подклассом, если он предоставлен расширением.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$dsnИмя драйвера, двоеточие и параметры конкретной СУБД. Например sqlite::memory: либо mysql:host=127.0.0.1;dbname=shop;charset=utf8mb4.
$username / $passwordИмя и пароль либо null; отдельные драйверы не требуют их. Пароль имеет SensitiveParameter в сигнатуре, но это не защита от вашего собственного журнала/вывода.
$optionsМассив атрибут → значение, применяемых при соединении, либо null. Часть атрибутов задаётся только здесь.

new возвращает объект соединения. Любая ошибка подключения вызывает PDOException независимо от ERRMODE. Три формы DSN: полный driver:..., доверенный alias из pdo.dsn.NAME в php.ini (не .htaccess/httpd.conf), исторический uri: с файлом/URL DSN. uri: устарел с PHP 8.5 из-за риска внешнего источника: для нового кода используйте собственную конфигурацию и полный DSN. Передавать пользовательский DSN нельзя. PDO не переводит диалекты SQL и не добавляет отсутствующую поддержку БД. Фабрика существует с 8.4; возвращает подходящий Pdo\Sqlite/Mysql/Pgsql/Odbc/Dblib/Firebird либо обычный PDO, если подкласса у драйвера нет.

Путь данных
  1. PDO::connect читает sqlite: в DSN
  2. Создаёт Pdo\Sqlite с общими методами PDO
  3. createFunction добавляет действие, доступное именно SQLite

Как читать этот вариант. Статическая фабрика выбирает драйверный подкласс. new PDO продолжает создавать базовый PDO; наличие драйверного объекта не меняет смысл SQL.

Получить новый драйверный класс PHP 8.4+Самостоятельный пример
<?php
$db = PDO::connect('sqlite::memory:');
echo get_class($db), "\n";
echo $db->query('SELECT 7')->fetchColumn(), "\n";
Ожидаемый результат
Pdo\Sqlite
7

Как читать этот вариант. После PDO::connect доступен типизированный API Pdo\Sqlite. Это учебная функция с фиксированной прибавкой, а не расчёт налогов; callback исполняется PHP при выполнении SELECT.

Зарегистрировать небольшую SQL-функцию у полученного подклассаСамостоятельный пример
<?php
$db = PDO::connect('sqlite::memory:');
$db->createFunction('gross', function ($net) { return $net + 20; }, 1);
echo $db->query('SELECT gross(100)')->fetchColumn(), "\n";
Ожидаемый результат
120

Рядом: PDO::__construct(), Pdo\Sqlite::createFunction().

PDO::getAvailableDriversПолучить имена доступных в текущем процессе PDO-драйверов.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDO::getAvailableDrivers(): array

Выбрать понятное действие при отсутствующем драйвере. Получаем список имён драйверов именно текущего PHP. in_array ищет sqlite в этом списке; пустой список не означает, что сервер MySQL остановлен.

Данные и действие: PDO::getAvailableDrivers
  1. PDO::getAvailableDrivers()
  2. При наличии sqlite выполняется каталог, при отсутствии — понятное сообщение до попытки соединения. pdo_drivers() даёт тот же список в процедурной записи.
  3. После выполнения: Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Выбрать понятное действие при отсутствующем драйвереСамостоятельный пример
<?php
if (!in_array('sqlite', PDO::getAvailableDrivers(), true)) {
    exit("Каталог не открыт: включите pdo_sqlite в PHP этого процесса.\n");
}
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products WHERE id = 1');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Молоток — 8 шт.

При наличии sqlite выполняется каталог, при отсутствии — понятное сообщение до попытки соединения. pdo_drivers() даёт тот же список в процедурной записи.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Драйвер — только одна зависимость. Путь, права, адрес и учётные данные проверяются уже при подключении. Веб-PHP и терминал могут загружать разные ini.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить имена доступных в текущем процессе PDO-драйверов.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Возвращает массив строк вроде sqlite/mysql/pgsql; без драйверов пустой массив. Это возможность создать соединение, а не проверка доступности сервера или наличия таблиц.

Путь данных
  1. Текущий PHP перечисляет загруженные драйверы
  2. in_array проверяет именно sqlite
  3. Можно начинать локальный урок либо настроить расширение

Как читать этот вариант. Список содержит драйверы текущего PHP-процесса, а не установленного где-то сервера. PDO без нужного драйвера не соединится с БД.

Проверить SQLite перед началом учебного заданияСамостоятельный пример
<?php
$drivers = PDO::getAvailableDrivers();
echo in_array('sqlite', $drivers, true) ? "SQLite готов\n" : "Нужен pdo_sqlite\n";
Ожидаемый результат
SQLite готов

Как читать этот вариант. pdo_drivers — процедурный вариант той же операции. Пустой массив означает отсутствие загруженных PDO-драйверов; набор в веб-SAPI может отличаться от CLI.

Процедурное имя возвращает тот же списокСамостоятельный пример
<?php
var_dump(pdo_drivers() === PDO::getAvailableDrivers());
Ожидаемый результат
bool(true)

Рядом: PDO::__construct().

pdo_driversПолучить имена доступных в текущем процессе PDO-драйверов.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

pdo_drivers(): array

Выбрать понятное действие при отсутствующем драйвере. Получаем список имён драйверов именно текущего PHP. in_array ищет sqlite в этом списке; пустой список не означает, что сервер MySQL остановлен.

Данные и действие: pdo_drivers
  1. PDO::getAvailableDrivers()
  2. При наличии sqlite выполняется каталог, при отсутствии — понятное сообщение до попытки соединения. pdo_drivers() даёт тот же список в процедурной записи.
  3. После выполнения: Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Выбрать понятное действие при отсутствующем драйвереСамостоятельный пример
<?php
if (!in_array('sqlite', PDO::getAvailableDrivers(), true)) {
    exit("Каталог не открыт: включите pdo_sqlite в PHP этого процесса.\n");
}
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products WHERE id = 1');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Молоток — 8 шт.

При наличии sqlite выполняется каталог, при отсутствии — понятное сообщение до попытки соединения. pdo_drivers() даёт тот же список в процедурной записи.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Драйвер — только одна зависимость. Путь, права, адрес и учётные данные проверяются уже при подключении. Веб-PHP и терминал могут загружать разные ini.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить имена доступных в текущем процессе PDO-драйверов.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Возвращает массив строк вроде sqlite/mysql/pgsql; без драйверов пустой массив. Это возможность создать соединение, а не проверка доступности сервера или наличия таблиц.

Путь данных
  1. Текущий PHP перечисляет загруженные драйверы
  2. in_array проверяет именно sqlite
  3. Можно начинать локальный урок либо настроить расширение

Как читать этот вариант. Список содержит драйверы текущего PHP-процесса, а не установленного где-то сервера. PDO без нужного драйвера не соединится с БД.

Проверить SQLite перед началом учебного заданияСамостоятельный пример
<?php
$drivers = PDO::getAvailableDrivers();
echo in_array('sqlite', $drivers, true) ? "SQLite готов\n" : "Нужен pdo_sqlite\n";
Ожидаемый результат
SQLite готов

Как читать этот вариант. pdo_drivers — процедурный вариант той же операции. Пустой массив означает отсутствие загруженных PDO-драйверов; набор в веб-SAPI может отличаться от CLI.

Процедурное имя возвращает тот же списокСамостоятельный пример
<?php
var_dump(pdo_drivers() === PDO::getAvailableDrivers());
Ожидаемый результат
bool(true)

Рядом: PDO::__construct().

PDO::getAttributeПрочитать настройку соединения или сведения драйвера.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDO::getAttribute(int $attribute): mixed

Проверить нужный драйвер перед специальной операцией. Атрибут описывает соединение, а не колонку товара. Проверив драйвер, можно выбрать поддерживаемый SQL или отказаться от неподходящего пути.

Данные и действие: PDO::getAttribute
  1. $db->getAttribute(PDO::ATTR_DRIVER_NAME)
  2. Имя sqlite подтверждает именно используемый драйвер. Затем выполняется обычное чтение каталога.
  3. После выполнения: Перчатки — 15 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Проверить нужный драйвер перед специальной операциейСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$driver = $db->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($driver !== 'sqlite') { throw new RuntimeException('Этот урок рассчитан на SQLite'); }
$statement = $db->query('SELECT name, stock FROM products WHERE id = 2');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Перчатки — 15 шт.

Имя sqlite подтверждает именно используемый драйвер. Затем выполняется обычное чтение каталога.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Перчатки15 шт.

Если требование изменится. Не перебирайте все атрибуты вслепую: часть зависит от драйвера и может вызвать ошибку. Версия сервера, версия клиента и версия PHP — разные величины.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Прочитать настройку соединения или сведения драйвера.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$attributePDO::ATTR_*; набор зависит от драйвера. Общие: CASE, DEFAULT_FETCH_MODE, DRIVER_NAME, ERRMODE, ORACLE_NULLS, PERSISTENT, STATEMENT_CLASS, STRINGIFY_FETCHES.

Тип результата зависит от атрибута; по документации неуспех даёт null, неподдерживаемый атрибут может выбросить PDOException. С 8.4 читается STRINGIFY_FETCHES; MySQL/Firebird AUTOCOMMIT и MySQL EMULATE_PREPARES/DIRECT_QUERY возвращают bool вместо int. Нельзя переносить драйверный атрибут на другой драйвер.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Соединение содержит выбранный режим
  2. getAttribute читает его без нового запроса данных
  3. Приложение сверяет свой договор типов/ошибок

Как читать этот вариант. getAttribute относится к соединению. Одно имя атрибута не означает поддержку всеми драйверами; не перебирайте чужие константы без проверки драйвера.

Узнать драйвер и режим ошибокСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
var_dump($db->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION);
Ожидаемый результат
sqlite
bool(true)

Как читать этот вариант. Getter STRINGIFY_FETCHES поддержан с PHP 8.4. Эта опция меняет чтение результата, а не тип столбца БД; null остаётся null, если ORACLE_NULLS не требует преобразования.

Явно запросить строковую выдачу чиселСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
var_dump($db->getAttribute(PDO::ATTR_STRINGIFY_FETCHES));
var_dump($db->query('SELECT 12')->fetchColumn());
Ожидаемый результат
bool(true)
string(2) "12"

Рядом: PDO::setAttribute(), PDOStatement::getAttribute().

PDO::setAttributeНастроить выдачу и поведение соединения под договор приложения.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDO::setAttribute(int $attribute, mixed $value): bool

Выбрать именные ключи для строк каталога. Настройка задаёт форму последующих чтений по умолчанию. FETCH_ASSOC связывает поле name с ключом name; SQL и сохранённые строки она не меняет.

Данные и действие: PDO::setAttribute
  1. $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC)
  2. fetch без отдельного режима получает установленный режим соединения. Это устраняет случайную зависимость шаблона от числовых ключей.
  3. После выполнения: Перчатки — 15 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Выбрать именные ключи для строк каталогаСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$statement = $db->query('SELECT name, stock FROM products WHERE id = 2');
$row = $statement->fetch();
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Перчатки — 15 шт.

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

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Перчатки15 шт.

Если требование изменится. Некоторые настройки принимаются только при создании соединения. Не считайте любое false безобидным: неподдерживаемый атрибут нужно обработать, а режим ошибок задавать явно.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Настроить выдачу и поведение соединения под договор приложения.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$attributeИдентификатор атрибута PDO либо именно вашего драйвера.
$valueТип зависит от атрибута: enum-константа, bool, int либо массив для STATEMENT_CLASS.

true при успехе, false при неудаче; ошибки режима зависят от ERRMODE. Полная таблица атрибутов находится в разделе констант. TIMEOUT — секунды, но в SQLite это ожидание блокировки записи, в другом драйвере может быть соединение/чтение. STATEMENT_CLASS требует [имя, аргументы конструктора] и несовместим с persistent. ATTR_PERSISTENT задают при создании, не этим методом. EMULATE_PREPARES=false просит нативную подготовку, но поддержка и fallback зависят от драйвера.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. CASE_LOWER устанавливает договор ключей
  2. SELECT возвращает OrderID
  3. PHP получает ключ orderid со значением 42

Как читать этот вариант. CASE меняет ключи в PHP-результате, а не имена столбцов в схеме. Выбирайте один договор на границе проекта.

Согласовать регистр имён возвращаемых столбцовСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
$row = $db->query('SELECT 42 AS OrderID')->fetch(PDO::FETCH_ASSOC);
echo $row['orderid'], "\n";
Ожидаемый результат
42

Как читать этот вариант. Несмотря на название, ORACLE_NULLS доступен всем драйверам. Превращение пустого текста в null теряет исходное различие, поэтому его задают по реальной схеме данных.

Отличать NULL от пустой строки, когда это важноСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL);
var_dump($db->query("SELECT ''")->fetchColumn());
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING);
var_dump($db->query("SELECT ''")->fetchColumn());
Ожидаемый результат
string(0) ""
NULL

Рядом: PDO::getAttribute(), PDOStatement::setAttribute().

PDO::lastInsertIdПолучить созданный идентификатор или значение последовательности на данном соединении.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDO::lastInsertId(?string $name = null): string|false

Получить ссылку на только что добавленный товар. После INSERT с автоматически выбранным INTEGER PRIMARY KEY соединение знает последний выданный номер. Читать его нужно у того же соединения сразу после вставки.

Данные и действие: PDO::lastInsertId
  1. $db->lastInsertId()
  2. ID4 получен от базы, затем использован в SELECT. По нему приложение может сформировать ссылку /product?id=4.
  3. После выполнения: Товар #4: Отвёртка — 4 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Получить ссылку на только что добавленный товарСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->prepare('INSERT INTO products (name, stock) VALUES (:name, :stock)');
$statement->execute(['name'=>'Отвёртка', 'stock'=>4]);
$id = $db->lastInsertId();
$statement = $db->prepare('SELECT name, stock FROM products WHERE id = :id');
$statement->execute(['id'=>$id]);
$row = $statement->fetch();
echo 'Товар #', $id, ': ', $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Товар #4: Отвёртка — 4 шт.

ID4 получен от базы, затем использован в SELECT. По нему приложение может сформировать ссылку /product?id=4.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Товар #4: Отвёртка4 шт.

Если требование изменится. Не вычисляйте MAX(id)+1: параллельная вставка может дать чужой номер. Семантика имён sequence и пакетной вставки зависит от драйвера; номер вставки не является номером обновлённой строки.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить созданный идентификатор или значение последовательности на данном соединении.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$nameНеобязательное имя последовательности, например для PostgreSQL; смысл задаёт драйвер.

Возвращает строку либо false/ошибку. Возможность/смысл различаются: БД может не иметь auto increment/sequence; неподдерживаемая операция — SQLSTATE IM001. Не делайте предположение о последнем ID каждой строки многострочного INSERT и о переносимости между драйверами; когда СУБД поддерживает RETURNING, результат запроса обычно точнее связан с вставкой.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. INSERT создаёт заказ 1
  2. lastInsertId на том же соединении читает строку "1"
  3. Этот ID передаётся параметром в таблицу lines

Как читать этот вариант. Возврат — строка, даже когда ID выглядит числом. Получайте ID на том же соединении непосредственно после нужного INSERT; не заменяйте MAX(id), который может прочитать чужую запись.

Связать строку заказа с новым идентификаторомСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY, label TEXT)');
$db->exec("INSERT INTO orders (label) VALUES ('First')");
$id = $db->lastInsertId();
var_dump($id);
Ожидаемый результат
string(1) "1"

Как читать этот вариант. Две связанные записи созданы одной транзакцией; это не универсальное правило получения ID для всех драйверов. PostgreSQL часто удобнее INSERT ... RETURNING, а sequence-name имеет собственный смысл.

Использовать ID заказа при добавлении строки составаСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY)');
$db->exec('CREATE TABLE lines (order_id INTEGER, sku TEXT)');
$db->beginTransaction();
$db->exec('INSERT INTO orders DEFAULT VALUES');
$id = $db->lastInsertId();
$statement = $db->prepare('INSERT INTO lines VALUES (?, ?)');
$statement->execute([$id, 'PEN']);
$db->commit();
echo $db->query('SELECT order_id || char(58) || sku FROM lines')->fetchColumn(), "\n";
Ожидаемый результат
1:PEN

Рядом: PDO::exec(), PDOStatement::execute().

PDO::quoteПолучить строковый SQL-литерал для редкого случая ручной сборки доверенного запроса.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDO::quote(string $string, int $type = PDO::PARAM_STR): string|false

Прочитать старый код с апострофом без потери данных. quote возвращает готовый SQL-литерал вместе с кавычками по правилам драйвера. Здесь это нужно для понимания старого SQL; новый ввод обычно проще передавать через prepare.

Данные и действие: PDO::quote
  1. $db->quote($name)
  2. Апостроф сохраняется в названии. quote обрабатывает только литерал значения; число 2 и имена таблицы/колонок здесь заданы автором.
  3. После выполнения: Кисть O'Reilly — 2 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Прочитать старый код с апострофом без потери данныхСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$name = "Кисть O'Reilly";
$quoted = $db->quote($name);
if ($quoted === false) { throw new RuntimeException('Драйвер не поддерживает quote'); }
$db->exec('INSERT INTO products (name, stock) VALUES (' . $quoted . ', 2)');
$statement = $db->query('SELECT name, stock FROM products WHERE id = 4');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Кисть O'Reilly — 2 шт.

Апостроф сохраняется в названии. quote обрабатывает только литерал значения; число 2 и имена таблицы/колонок здесь заданы автором.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Кисть O'Reilly2 шт.

Если требование изменится. Не добавляйте вторые кавычки вокруг результата quote и не экранируйте так идентификаторы. Для HTML это значение всё ещё требует htmlspecialchars.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить строковый SQL-литерал для редкого случая ручной сборки доверенного запроса.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$stringСтроковое значение для цитирования, без самостоятельных SQL-кавычек.
$typeПодсказка PARAM_* для особого цитирования, например PARAM_LOB, если драйвер поддерживает.

Возвращает строку с кавычками и нужным драйверу экранированием, false при отсутствии поддержки (в частности ODBC). Корректная кодировка соединения должна быть задана на сервере/в DSN. Предпочитайте параметры: quote не защищает произвольную структуру SQL и не делает идентификатор безопасным. SQLite PHP 8.5 сообщает об ошибке NUL вместо прежнего молчаливого обрезания.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. O'Brien — значение PHP
  2. quote создаёт SQL-литерал 'O''Brien'
  3. Подготовленный запрос обычно устраняет необходимость этого ручного шага

Как читать этот вариант. В результат уже входят внешние SQL-кавычки. Это цитирование строкового значения, не имени таблицы и не шаблона LIKE. Для входных данных обычнее prepare/execute.

Увидеть SQL-литерал со внутренней кавычкойСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
echo $db->quote("O'Brien"), "\n";
Ожидаемый результат
'O''Brien'

Как читать этот вариант. До 8.5 SQLite quote мог молча обрезать строку по NUL; теперь сообщение зависит от ERRMODE. Для двоичного значения нужен подходящий параметр LOB, а не ручная текстовая склейка.

SQLite PHP 8.5 отклоняет NUL при quoteСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
try { $db->quote("a\0b"); } catch (PDOException $error) { echo "NUL нельзя цитировать как текст\n"; }
Ожидаемый результат
NUL нельзя цитировать как текст

Рядом: PDO::prepare(), PDOStatement::bindValue().

PDOStatement::bindColumnСвязать столбец результата с переменной PHP, которую будет обновлять чтение.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::bindColumn(string|int $column, mixed &$var, int $type = PDO::PARAM_STR, int $maxLength = 0, mixed $driverOptions = null): bool

Читать строки в заранее названные переменные. bindColumn связывает выходную колонку с PHP-переменной. FETCH_BOUND при каждом fetch записывает текущие значения в эти переменные.

Данные и действие: PDOStatement::bindColumn
  1. $statement->bindColumn('name', $name)
  2. Во время каждого прохода $name и $stock получают значения следующей строки. Привязка колонок задаёт выход; bindValue и bindParam задают входные параметры SQL.
  3. После выполнения: Молоток — 8 шт. · Перчатки — 15 шт. · Кисть — 0 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
while (...)Повторяет блок, пока условие истинно. В чтении результата проверка конца связана с конкретным методом: false или null указаны в его контракте.
Читать строки в заранее названные переменныеСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products ORDER BY id');
$statement->bindColumn('name', $name);
$statement->bindColumn('stock', $stock, PDO::PARAM_INT);
while ($statement->fetch(PDO::FETCH_BOUND)) {
    echo $name, ' — ', $stock, " шт.\n";
}
Ожидаемый результат
Молоток — 8 шт.
Перчатки — 15 шт.
Кисть — 0 шт.

Во время каждого прохода $name и $stock получают значения следующей строки. Привязка колонок задаёт выход; bindValue и bindParam задают входные параметры SQL.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.
Перчатки15 шт.
Кисть0 шт.

Если требование изменится. Если структура строки меняется, именные массивы часто проще сопровождать. Для LOB проверьте, отдаёт ли конкретный драйвер поток или строку, и завершите чтение до перехода дальше.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

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

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$columnНомер с 1 либо точное имя с регистром, как его вернул драйвер.
&$varПеременная для очередного прочитанного значения.
$typeТип PARAM_* результата.
$maxLengthПодсказка предварительного выделения памяти.
$driverOptionsОпции конкретного драйвера.

true/false; привязка сама строку не читает. Обычно переносимый порядок execute → bindColumn → fetch, потому что до выполнения метаданных может не быть. Исключение: PostgreSQL PARAM_LOB нужно привязать до execute, чтобы получить поток вместо целочисленного OID. Каждый fetch/fetchAll обновляет связанные переменные; это не массив истории всех значений.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. SELECT формирует name=Pen,price=120
  2. bindColumn соединяет name → $name, price → $price
  3. fetch переносит одну строку
  4. Следующий fetch заменит переменные

Как читать этот вариант. Связывание результата отличается от связывания входа. fetch обновляет $name и $price. При FETCH_BOUND сам возврат true/false служит признаком наличия строки.

Прочитать столбцы в две отдельные переменныеСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT name, price FROM products WHERE id = 1');
$statement->bindColumn(1, $name, PDO::PARAM_STR);
$statement->bindColumn('price', $price, PDO::PARAM_INT);
if ($statement->fetch(PDO::FETCH_BOUND)) { echo $name, ':', $price, "\n"; }
Ожидаемый результат
Pen:120

Как читать этот вариант. Переменная $price перезаписывается на каждом fetch. Для простой суммы SQL SUM(price) обычно избавляет от переноса всех цен; цикл уместен, когда на строку нужна собственная PHP-логика.

Построчно посчитать сумму без массива всех строкСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT price FROM products ORDER BY id');
$statement->bindColumn(1, $price, PDO::PARAM_INT);
$total = 0;
while ($statement->fetch(PDO::FETCH_BOUND)) { $total += $price; }
echo $total, "\n";
Ожидаемый результат
670

Рядом: PDOStatement::fetch(), PDOStatement::bindParam().

PDOStatement::fetchObjectПрочитать одну строку как stdClass либо заданный класс представления.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::fetchObject(?string $class = "stdClass", array $constructorArgs = []): object|false

Получить строку с полями объекта. Без имени пользовательского класса создаётся stdClass. Колонка name становится свойством $product->name; объект соединения и объект товара имеют разные роли.

Данные и действие: PDOStatement::fetchObject
  1. $statement->fetchObject()
  2. Стрелка при чтении свойства не использует скобки. Строка базы превращена в контейнер полей; это ещё не объект с бизнес-правилами склада.
  3. После выполнения: Молоток — 8 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Получить строку с полями объектаСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products WHERE id = 1');
$product = $statement->fetchObject();
if ($product === false) { exit("Товар не найден\n"); }
echo $product->name, ' — ', $product->stock, " шт.\n";
Ожидаемый результат
Молоток — 8 шт.

Стрелка при чтении свойства не использует скобки. Строка базы превращена в контейнер полей; это ещё не объект с бизнес-правилами склада.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. При заполнении пользовательского класса учитывайте порядок установки свойств и вызова конструктора, readonly и типы. Для строгой модели часто яснее fetch массива и явный конструктор.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Прочитать одну строку как stdClass либо заданный класс представления.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$classИмя создаваемого класса; по умолчанию stdClass, null также выбирает stdClass.
$constructorArgsАргументы конструктора, отдельно от значений столбцов; правила вызова PHP должны выполняться.

Объект или false при конце/неудаче. Сначала присваиваются свойства из колонок, затем вызывается конструктор; он может перезаписать их. Для порядка «конструктор → свойства» нужен setFetchMode(CLASS | PROPS_LATE). Типы свойств и ошибки конструктора остаются правилами PHP. Не выбирайте имя произвольного класса из внешних данных.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. SQL name=Notebook заполняет свойство
  2. fetchObject создаёт ProductView
  3. Конструктор отдельно получает RUB
  4. Возвращается объект с name и currency

Как читать этот вариант. Без имени класса создаётся stdClass. Стрелка читает свойство объекта, квадратные скобки массива здесь не подходят; при отсутствии строки проверяют === false.

Получить объект с именованными свойствамиСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$product = $db->query('SELECT name, price FROM products WHERE id = 1')->fetchObject();
echo $product->name, ':', $product->price, "\n";
Ожидаемый результат
Pen:120

Как читать этот вариант. name приходит из SQL-свойства, RUB — из массива аргументов конструктора. Это два независимых канала. Сложный объект с инвариантами лучше создавать явно из проверенного массива, а не обходить его конструктор гидратацией.

Передать отдельный аргумент конструктораСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
class ProductView {
    public string $name;
    public function __construct(public string $currency) {}
}
$statement = $db->query('SELECT name FROM products WHERE id = 2');
$product = $statement->fetchObject(ProductView::class, ['RUB']);
echo $product->name, ':', $product->currency, "\n";
Ожидаемый результат
Notebook:RUB

Рядом: PDOStatement::fetch(), PDOStatement::setFetchMode().

PDOStatement::setFetchModeВыбрать форму строк по умолчанию для данного результата.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::setFetchMode(int $mode, mixed ...$args): true

Настроить представление только одного результата. Настройка относится к одному statement. Она не меняет режим других запросов того же соединения.

Данные и действие: PDOStatement::setFetchMode
  1. $statement->setFetchMode(PDO::FETCH_ASSOC)
  2. foreach получает строки в заранее выбранной форме. В карточке ниже разобраны COLUMN, CLASS, INTO и остальные режимы с их дополнительными аргументами.
  3. После выполнения: Молоток — 8 шт. · Перчатки — 15 шт. · Кисть — 0 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Настроить представление только одного результатаСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products ORDER BY id');
$statement->setFetchMode(PDO::FETCH_ASSOC);
foreach ($statement as $product) {
    echo $product['name'], ' — ', $product['stock'], " шт.\n";
}
Ожидаемый результат
Молоток — 8 шт.
Перчатки — 15 шт.
Кисть — 0 шт.

foreach получает строки в заранее выбранной форме. В карточке ниже разобраны COLUMN, CLASS, INTO и остальные режимы с их дополнительными аргументами.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.
Перчатки15 шт.
Кисть0 шт.

Если требование изменится. Когда требуется нестандартная форма одного результата, настройка statement локальнее глобального атрибута соединения. Режим чтения не меняет число запросов к базе.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

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

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$modeПодходящий FETCH_*.
$argsCOLUMN: colno; CLASS: class и ?constructorArgs; INTO: существующий object. Передаются позиционно.

true (с 8.4 тип возврата уточнён с bool). Неверное сочетание аргументов/режима вызывает ошибку. С 8.5 менять режим внутри текущего fetch/fetchObject/fetchAll запрещено Error. С 8.5 constructorArgs использует правила call_user_func_array: строковые ключи — имена параметров, ссылочные параметры требуют ссылочных элементов [&$value], автоматического оборачивания больше нет. FETCH_INTO обновляет один существующий объект; хранить его повторно как отдельные снимки без клонирования нельзя.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. statement хранит FETCH_COLUMN,1
  2. foreach вызывает очередное чтение
  3. Каждая строка отдаёт только name
  4. Другие statement сохраняют свои режимы

Как читать этот вариант. Режим принадлежит конкретному statement. Другие запросы этого соединения его не наследуют; их общий default меняют атрибутом соединения.

Настроить короткую выдачу для foreachСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT id, name FROM products ORDER BY id');
$statement->setFetchMode(PDO::FETCH_COLUMN, 1);
foreach ($statement as $name) { echo $name, "\n"; }
Ожидаемый результат
Pen
Notebook
Box

Как читать этот вариант. При CLASS конструктор идёт после колонок и перезаписывает label. С PROPS_LATE порядок обратный. Модель нужна, чтобы запись из БД случайно не обходила правила вашего доменного объекта.

Увидеть, кто последним записывает свойствоСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
class LabelView {
    public string $label;
    public function __construct() { $this->label = 'constructor'; }
}
$statement = $db->query("SELECT 'database' AS label");
$statement->setFetchMode(PDO::FETCH_CLASS, LabelView::class);
echo $statement->fetch()->label, "\n";
$statement->execute();
$statement->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, LabelView::class);
echo $statement->fetch()->label, "\n";
Ожидаемый результат
constructor
database

Рядом: PDO::setAttribute(), PDOStatement::fetchAll(), PDOStatement::fetchObject().

PDOStatement::getIteratorПередать чтение строк инструментам работы с итераторами.

PHP 8.0+ · PDO; соответствующий драйвер

PDOStatement::getIterator(): Iterator

Передать строки универсальному циклу. Итератор выдаёт последовательность строк, не собирая отдельный массив fetchAll. foreach умеет обращаться к нему по одному элементу.

Данные и действие: PDOStatement::getIterator
  1. $statement->getIterator()
  2. Вместо ручного вызова fetch цикл получает строку через итератор. На практике можно написать foreach ($statement as $row) с тем же смыслом.
  3. После выполнения: Молоток — 8 шт. · Перчатки — 15 шт. · Кисть — 0 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Передать строки универсальному циклуСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products ORDER BY id');
$iterator = $statement->getIterator();
foreach ($iterator as $row) {
    echo $row['name'], ' — ', $row['stock'], " шт.\n";
}
Ожидаемый результат
Молоток — 8 шт.
Перчатки — 15 шт.
Кисть — 0 шт.

Вместо ручного вызова fetch цикл получает строку через итератор. На практике можно написать foreach ($statement as $row) с тем же смыслом.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.
Перчатки15 шт.
Кисть0 шт.

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

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Передать чтение строк инструментам работы с итераторами.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Возвращает Iterator, связанный с текущим результатом; это реализация IteratorAggregate в PHP 8. Официальная страница содержит только сигнатуру: практическое поведение примеров сверено с PHP 8.5 и реализацией PDO. Последовательный курсор не является массивом произвольного доступа; повторный проход не следует считать перемоткой SQL. Не перемешивайте fetch и обход разных итераторов одного statement без ясного владения позицией.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. statement владеет текущими строками
  2. getIterator предоставляет интерфейс обхода
  3. LimitIterator останавливает потребление после двух
  4. closeCursor освобождает остаток

Как читать этот вариант. Это тот же поток строк statement, а не независимая копия. Обычно foreach ($statement ...) короче; явный Iterator нужен коду, который принимает именно итератор.

Получить итератор результата явноСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT name FROM products ORDER BY id');
$statement->setFetchMode(PDO::FETCH_ASSOC);
$iterator = $statement->getIterator();
foreach ($iterator as $row) { echo $row['name'], "\n"; }
Ожидаемый результат
Pen
Notebook
Box

Как читать этот вариант. LimitIterator останавливает PHP-обход после двух значений, но не переписывает SQL и не гарантирует экономию серверного буфера. Для ограничения самого запроса используйте SQL LIMIT/драйверный аналог.

Передать результат обёртке итератораСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT name FROM products ORDER BY id');
$statement->setFetchMode(PDO::FETCH_COLUMN, 0);
$iterator = new LimitIterator($statement->getIterator(), 0, 2);
foreach ($iterator as $name) { echo $name, "\n"; }
$statement->closeCursor();
Ожидаемый результат
Pen
Notebook

Рядом: PDOStatement::fetch(), PDOStatement::closeCursor().

PDO::errorCodeПолучить SQLSTATE последней операции соединения.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDO::errorCode(): ?string

Показать человеку понятный отказ сохранения. SQLSTATE описывает класс отказа, а не число найденных строк. Для этого диагностического урока выбран ERRMODE_SILENT: после отказа читаем состояние того объекта, на котором выполнялась команда.

Данные и действие: PDO::errorCode
  1. $db->errorCode()
  2. Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.
  3. После выполнения: Товар с таким номером уже есть: новая запись не сохранена. · Молоток — 8 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Показать человеку понятный отказ сохраненияСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec("INSERT INTO products VALUES (1, 'Дубликат', 1)");
$diagnostic = $db->errorCode();
$state = $diagnostic;
if ($state === '23000') {
    echo "Товар с таким номером уже есть: новая запись не сохранена.\n";
}
$statement = $db->query('SELECT name, stock FROM products WHERE id = 1');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Товар с таким номером уже есть: новая запись не сохранена.
Молоток — 8 шт.

Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. В обычном приложении удобнее ERRMODE_EXCEPTION и catch. errorInfo содержит технические сведения драйвера; SQL, пути и внутренние данные не показывают посетителю. Состояние соединения не заменяет диагностику конкретного statement.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить SQLSTATE последней операции соединения.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

SQLSTATE — пять букв/цифр: первые две обозначают класс, следующие три подкласс; 00000 — успех, 01 — предупреждение, IM — ошибка реализации PDO/ODBC. До операции возможно null. Ошибка execute у statement не обязана отражаться в $db: спрашивайте именно statement.

Путь данных
  1. $db выполняет команду
  2. Операция возвращает false в SILENT
  3. errorCode даёт краткую категорию
  4. Следующая операция может заменить эту диагностику

Как читать этот вариант. Пример специально использует SILENT и строго проверяет возврат. SQLSTATE — строка из пяти знаков; конкретные коды драйвера и сообщения не являются универсальными между БД.

Прочитать SQLSTATE у объекта, где случился отказСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$ok = $db->exec('INSERT INTO missing_table VALUES (1)');
var_dump($ok);
echo $db->errorCode(), "\n";
Ожидаемый результат
bool(false)
HY000

Как читать этот вариант. После успешной новой операции состояние обновилось. Нужную диагностику сохраняют сразу, прежде чем делать ещё один запрос; 00000 соответствует PDO::ERR_NONE.

Не принимать старую ошибку за текущуюСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$ok = $db->exec('INSERT INTO missing_table VALUES (1)');
$db->exec('CREATE TABLE ready (id INTEGER)');
echo $db->errorCode(), "\n";
Ожидаемый результат
00000

Рядом: PDO::errorInfo().

PDO::errorInfoПолучить подробности SQL-ошибки для технической диагностики.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDO::errorInfo(): array

Показать человеку понятный отказ сохранения. SQLSTATE описывает класс отказа, а не число найденных строк. Для этого диагностического урока выбран ERRMODE_SILENT: после отказа читаем состояние того объекта, на котором выполнялась команда.

Данные и действие: PDO::errorInfo
  1. $db->errorInfo()
  2. Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.
  3. После выполнения: Товар с таким номером уже есть: новая запись не сохранена. · Молоток — 8 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Показать человеку понятный отказ сохраненияСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec("INSERT INTO products VALUES (1, 'Дубликат', 1)");
$diagnostic = $db->errorInfo();
$state = $diagnostic[0];
if ($state === '23000') {
    echo "Товар с таким номером уже есть: новая запись не сохранена.\n";
}
$statement = $db->query('SELECT name, stock FROM products WHERE id = 1');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Товар с таким номером уже есть: новая запись не сохранена.
Молоток — 8 шт.

Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. В обычном приложении удобнее ERRMODE_EXCEPTION и catch. errorInfo содержит технические сведения драйвера; SQL, пути и внутренние данные не показывают посетителю. Состояние соединения не заменяет диагностику конкретного statement.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить подробности SQL-ошибки для технической диагностики.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Массив минимум [SQLSTATE, driverCode, driverMessage]; без ошибки драйвера элементы после 0 могут быть null. Тип/содержание полей драйвера зависят от расширения. Читать нужно у объекта, который выполнял проблемную операцию, сразу после неё. Не отдавайте SQL и сырое сообщение через публичную форму/API; человеку нужен понятный отказ и идентификатор обращения.

Путь данных
  1. Ошибка INSERT → SQLSTATE и драйверный код
  2. errorInfo собирает техническую структуру
  3. Журнал получает только разрешённые данные
  4. Посетитель видит понятное сообщение

Как читать этот вариант. Элемент 0 — SQLSTATE, 1 — код конкретного драйвера, 2 — его сообщение. Здесь проверяется форма, а не нестабильный текст SQLite; SQL/имена/данные могут быть чувствительными.

Разделить общий код и сообщение драйвераСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$ok = $db->exec('INSERT INTO missing_table VALUES (1)');
$info = $db->errorInfo();
echo $info[0], "\n";
var_dump(is_int($info[1]), is_string($info[2]));
Ожидаемый результат
HY000
bool(true)
bool(true)

Как читать этот вариант. Успешный SQLSTATE не требует показа посетителю всей диагностической структуры. Используйте результат операции как основной договор, errorInfo — для разбора отказа.

Проверить диагностику после успешной операцииСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec('CREATE TABLE ready (id INTEGER)');
$info = $db->errorInfo();
echo $info[0], "\n";
Ожидаемый результат
00000

Рядом: PDO::errorCode().

PDOStatement::errorCodeПолучить SQLSTATE последней операции данного statement.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::errorCode(): ?string

Показать человеку понятный отказ сохранения. SQLSTATE описывает класс отказа, а не число найденных строк. Для этого диагностического урока выбран ERRMODE_SILENT: после отказа читаем состояние того объекта, на котором выполнялась команда.

Данные и действие: PDOStatement::errorCode
  1. $statement->errorCode()
  2. Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.
  3. После выполнения: Товар с таким номером уже есть: новая запись не сохранена. · Молоток — 8 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Показать человеку понятный отказ сохраненияСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$statement = $db->prepare('INSERT INTO products (id, name, stock) VALUES (1, :name, 1)');
$statement->execute(['name'=>'Дубликат']);
$diagnostic = $statement->errorCode();
$state = $diagnostic;
if ($state === '23000') {
    echo "Товар с таким номером уже есть: новая запись не сохранена.\n";
}
$statement = $db->query('SELECT name, stock FROM products WHERE id = 1');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Товар с таким номером уже есть: новая запись не сохранена.
Молоток — 8 шт.

Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. В обычном приложении удобнее ERRMODE_EXCEPTION и catch. errorInfo содержит технические сведения драйвера; SQL, пути и внутренние данные не показывают посетителю. Состояние соединения не заменяет диагностику конкретного statement.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить SQLSTATE последней операции данного statement.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

SQLSTATE — пять букв/цифр: первые две обозначают класс, следующие три подкласс; 00000 — успех, 01 — предупреждение, IM — ошибка реализации PDO/ODBC. До операции возможно null. Соединение и другие команды имеют собственную диагностику. После исключения можно читать errorInfo самого исключения.

Путь данных
  1. $statement выполняет команду
  2. Операция возвращает false в SILENT
  3. errorCode даёт краткую категорию
  4. Следующая операция может заменить эту диагностику

Как читать этот вариант. Пример специально использует SILENT и строго проверяет возврат. SQLSTATE — строка из пяти знаков; конкретные коды драйвера и сообщения не являются универсальными между БД.

Прочитать SQLSTATE у объекта, где случился отказСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY)');
$db->exec('INSERT INTO orders VALUES (1)');
$statement = $db->prepare('INSERT INTO orders VALUES (?)');
$ok = $statement->execute([1]);
var_dump($ok);
echo $statement->errorCode(), "\n";
Ожидаемый результат
bool(false)
23000

Как читать этот вариант. После успешной новой операции состояние обновилось. Нужную диагностику сохраняют сразу, прежде чем делать ещё один запрос; 00000 соответствует PDO::ERR_NONE.

Не принимать старую ошибку за текущуюСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY)');
$db->exec('INSERT INTO orders VALUES (1)');
$statement = $db->prepare('INSERT INTO orders VALUES (?)');
$ok = $statement->execute([1]);
$statement->closeCursor();
$statement->execute([2]);
echo $statement->errorCode(), "\n";
Ожидаемый результат
00000

Рядом: PDOStatement::errorInfo().

PDOStatement::errorInfoПолучить подробности SQL-ошибки для технической диагностики.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::errorInfo(): array

Показать человеку понятный отказ сохранения. SQLSTATE описывает класс отказа, а не число найденных строк. Для этого диагностического урока выбран ERRMODE_SILENT: после отказа читаем состояние того объекта, на котором выполнялась команда.

Данные и действие: PDOStatement::errorInfo
  1. $statement->errorInfo()
  2. Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.
  3. После выполнения: Товар с таким номером уже есть: новая запись не сохранена. · Молоток — 8 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Показать человеку понятный отказ сохраненияСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$statement = $db->prepare('INSERT INTO products (id, name, stock) VALUES (1, :name, 1)');
$statement->execute(['name'=>'Дубликат']);
$diagnostic = $statement->errorInfo();
$state = $diagnostic[0];
if ($state === '23000') {
    echo "Товар с таким номером уже есть: новая запись не сохранена.\n";
}
$statement = $db->query('SELECT name, stock FROM products WHERE id = 1');
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Товар с таким номером уже есть: новая запись не сохранена.
Молоток — 8 шт.

Попытка повторить первичный ключ 1 отклоняется. После сообщения перечитываем исходный товар и видим, что его название и остаток не заменены.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. В обычном приложении удобнее ERRMODE_EXCEPTION и catch. errorInfo содержит технические сведения драйвера; SQL, пути и внутренние данные не показывают посетителю. Состояние соединения не заменяет диагностику конкретного statement.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить подробности SQL-ошибки для технической диагностики.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Массив минимум [SQLSTATE, driverCode, driverMessage]; без ошибки драйвера элементы после 0 могут быть null. Тип/содержание полей драйвера зависят от расширения. Читать нужно у объекта, который выполнял проблемную операцию, сразу после неё. Не отдавайте SQL и сырое сообщение через публичную форму/API; человеку нужен понятный отказ и идентификатор обращения.

Путь данных
  1. Ошибка INSERT → SQLSTATE и драйверный код
  2. errorInfo собирает техническую структуру
  3. Журнал получает только разрешённые данные
  4. Посетитель видит понятное сообщение

Как читать этот вариант. Элемент 0 — SQLSTATE, 1 — код конкретного драйвера, 2 — его сообщение. Здесь проверяется форма, а не нестабильный текст SQLite; SQL/имена/данные могут быть чувствительными.

Разделить общий код и сообщение драйвераСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY)');
$db->exec('INSERT INTO orders VALUES (1)');
$statement = $db->prepare('INSERT INTO orders VALUES (?)');
$ok = $statement->execute([1]);
$info = $statement->errorInfo();
echo $info[0], "\n";
var_dump(is_int($info[1]), is_string($info[2]));
Ожидаемый результат
23000
bool(true)
bool(true)

Как читать этот вариант. Успешный SQLSTATE не требует показа посетителю всей диагностической структуры. Используйте результат операции как основной договор, errorInfo — для разбора отказа.

Проверить диагностику после успешной операцииСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY)');
$db->exec('INSERT INTO orders VALUES (1)');
$statement = $db->prepare('INSERT INTO orders VALUES (?)');
$statement->closeCursor();
$statement->execute([2]);
$info = $statement->errorInfo();
echo $info[0], "\n";
Ожидаемый результат
00000

Рядом: PDOStatement::errorCode().

PDOStatement::columnCountУзнать, сколько столбцов имеет текущий набор результата.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::columnCount(): int

Проверить форму данных перед экспортом. Метод считает колонки ответа. Он не говорит, сколько товаров вернулось. Здесь ожидаются name и stock.

Данные и действие: PDOStatement::columnCount
  1. $statement->columnCount()
  2. Контракт двух колонок проверен до позиционного чтения. Номер 0 соответствует name,1 — stock; показанный простой разделитель годится для этих известных данных.
  3. После выполнения: Товар;Остаток · Молоток;8 · Перчатки;15 · Кисть;0

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
while (...)Повторяет блок, пока условие истинно. В чтении результата проверка конца связана с конкретным методом: false или null указаны в его контракте.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Проверить форму данных перед экспортомСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products ORDER BY id');
if ($statement->columnCount() !== 2) { throw new RuntimeException('Неожиданные колонки экспорта'); }
echo "Товар;Остаток\n";
while (($row = $statement->fetch(PDO::FETCH_NUM)) !== false) {
    echo $row[0], ';', $row[1], "\n";
}
Ожидаемый результат
Товар;Остаток
Молоток;8
Перчатки;15
Кисть;0

Контракт двух колонок проверен до позиционного чтения. Номер 0 соответствует name,1 — stock; показанный простой разделитель годится для этих известных данных.

Если требование изменится. Для произвольного текста экспортируйте через fputcsv, иначе разделитель или перенос внутри имени сломает файл. Даже пустой SELECT обычно имеет колонки; rowCount отвечает на другой вопрос.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Узнать, сколько столбцов имеет текущий набор результата.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Число столбцов, в том числе у пустого результата; 0 если набора нет. После query доступно сразу, после prepare — надёжно только после execute. Это не число строк и не число параметров SQL.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. SELECT id,name задаёт два столбца
  2. WHERE может найти ноль строк
  3. columnCount остаётся 2
  4. fetch возвращает false

Как читать этот вариант. Число колонок описывает форму результата, не количество строк. Даже без найденных товаров запрос объявляет id и name.

Пустой результат всё ещё имеет столбцыСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT id, name FROM products WHERE id = 99');
echo $statement->columnCount(), "\n";
var_dump($statement->fetch(PDO::FETCH_ASSOC));
Ожидаемый результат
2
bool(false)

Как читать этот вариант. После prepare метаданные ещё не гарантированы. После execute можно строить подписи экспорта и читать колонки, но не определять всю бизнес-схему только по результату.

Сначала выполнить подготовленный SELECTСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->prepare('SELECT name, price FROM products WHERE id = ?');
$statement->execute([1]);
echo $statement->columnCount(), "\n";
Ожидаемый результат
2

Рядом: PDOStatement::getColumnMeta(), PDOStatement::rowCount().

PDOStatement::getColumnMetaПолучить метаданные конкретной колонки текущей выдачи.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::getColumnMeta(int $column): array|false

Получить заголовки выгрузки из SELECT. Метаданные описывают поле результата. Номер 0 означает первую колонку; AS меняет её имя для читателя и PHP.

Данные и действие: PDOStatement::getColumnMeta
  1. $statement->getColumnMeta(0)
  2. Имя берём из описания колонки, значение — из строки. Так универсальная выгрузка не путает заголовки с данными.
  3. После выполнения: product;available · Молоток;8

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Получить заголовки выгрузки из SELECTСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name AS product, stock AS available FROM products WHERE id = 1');
$first = $statement->getColumnMeta(0);
$second = $statement->getColumnMeta(1);
if ($first === false || $second === false) { throw new RuntimeException('Метаданные недоступны'); }
echo $first['name'], ';', $second['name'], "\n";
$row = $statement->fetch(PDO::FETCH_NUM);
echo $row[0], ';', $row[1], "\n";
Ожидаемый результат
product;available
Молоток;8

Имя берём из описания колонки, значение — из строки. Так универсальная выгрузка не путает заголовки с данными.

Если требование изменится. Набор метаданных и поддержка метода зависят от драйвера. Не стройте проверку бизнес-типов только на native_type; приложение должно знать собственный контракт.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить метаданные конкретной колонки текущей выдачи.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$columnНомер столбца с 0.

Массив или false, если столбца/результата нет. Поля: native_type — внутреннее представление, driver:decl_type — объявленный SQL-тип (не для выражений), flags, name, table, len, precision, pdo_type (PARAM_*). len часто -1, precision часто 0. API необязателен для драйверов, хотя документированные PDO-драйверы реализуют его. Не строите миграции схемы из неполных метаданных SELECT.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Результат SELECT объявляет product_name
  2. getColumnMeta(0) читает описание
  3. Экспорт получает имя колонки
  4. Значение самой строки читается fetch

Как читать этот вариант. Номер метаданных начинается с 0. SQL-псевдоним становится именем результата; показывать его пользователю напрямую можно только если это подходящая подпись.

Получить подпись столбца для экспортаСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT name AS product_name, price FROM products');
$meta = $statement->getColumnMeta(0);
echo $meta['name'], "\n";
Ожидаемый результат
product_name

Как читать этот вариант. У выражения может не быть driver:decl_type/table. Даже физические метаданные различаются по драйверу и версии; проверяйте существование ключей.

Не считать вычисленную колонку физическим столбцом таблицыСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price INTEGER NOT NULL)');
$db->exec("INSERT INTO products VALUES (1, 'Pen', 120), (2, 'Notebook', 350), (3, 'Box', 200)");
$statement = $db->query('SELECT price * 2 AS double_price FROM products');
$meta = $statement->getColumnMeta(0);
echo $meta['name'], "\n";
echo $meta['sqlite:decl_type'] ?? 'Нет объявленного типа', "\n";
Ожидаемый результат
double_price
Нет объявленного типа

Рядом: PDOStatement::columnCount(), PDOStatement::fetch().

PDOStatement::debugDumpParamsПосмотреть SQL-шаблон и существующие привязки во время локальной отладки.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::debugDumpParams(): ?bool

Проверить привязку параметра в локальной диагностике. Метод печатает технический дамп, а не возвращает его строкой. Буфер ob_start временно собирает вывод, ob_get_clean забирает строку и закрывает буфер.

Данные и действие: PDOStatement::debugDumpParams
  1. $statement->debugDumpParams()
  2. Проверяем только известный маркер и затем выполняем запрос. Сам дамп можно изучить локально; он не подменяет выполнение или правильность данных.
  3. После выполнения: Маркер :id присутствует в диагностике · Перчатки — 15 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Проверить привязку параметра в локальной диагностикеСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->prepare('SELECT name, stock FROM products WHERE id = :id');
$statement->bindValue(':id', 2, PDO::PARAM_INT);
ob_start();
$statement->debugDumpParams();
$diagnostic = ob_get_clean();
if (str_contains($diagnostic, ':id')) { echo "Маркер :id присутствует в диагностике\n"; }
$statement->execute();
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Маркер :id присутствует в диагностике
Перчатки — 15 шт.

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

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Перчатки15 шт.

Если требование изменится. Не отправляйте дамп посетителю и не сохраняйте секреты в открытом журнале. Форма дампа и раскрытие SQL зависят от драйвера/эмуляции, поэтому это диагностический инструмент, не API разбора SQL.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Посмотреть SQL-шаблон и существующие привязки во время локальной отладки.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Печатает SQL, число Params, имя/позицию/тип param_type и is_param; позиция может быть -1, если драйвер её не сообщает. Возврат null при нормальной работе либо false при ошибке. Только текущие связанные параметры, не лишние переданные значения. При эмуляции с 7.2 возможен sent SQL со значениями. Для программного анализа стабильнее собственный безопасный журнал структуры: формат дампа предназначен человеку.

Путь данных
  1. Statement содержит SELECT :id и привязку 42
  2. debugDumpParams пишет обычный вывод
  3. Буфер перехватывает текст
  4. Программа проверяет наличие параметра без публикации дампа

Как читать этот вариант. debugDumpParams печатает напрямую и не возвращает строку. ob_start перехватывает вывод, ob_get_clean забирает строку и закрывает буфер. В примере не печатается потенциально чувствительный дамп.

Перехватить технический вывод вместо показа посетителюСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->prepare('SELECT :id');
$statement->bindValue(':id', 42, PDO::PARAM_INT);
ob_start();
$result = $statement->debugDumpParams();
$dump = ob_get_clean();
var_dump($result, str_contains($dump, 'Params:  1'));
Ожидаемый результат
NULL
bool(true)

Как читать этот вариант. Нативный режим не обязан показывать SQL с подставленными значениями. С PHP 7.2 при эмуляции дамп может содержать полный sent SQL и секретные данные; не помещайте его в общий журнал запросов автоматически.

Проверить наличие шаблона в локальном дампеСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->prepare('SELECT :name');
$statement->bindValue(':name', 'sample');
ob_start();
$statement->debugDumpParams();
$dump = ob_get_clean();
echo str_contains($dump, 'SELECT :name') ? "Шаблон найден\n" : "Шаблон не найден\n";
Ожидаемый результат
Шаблон найден

Рядом: PDOStatement::bindValue().

Pdo\Sqlite::createFunctionДобавить в SQLite скалярную функцию, реализованную PHP-кодом.

PHP 8.4+ · PDO; соответствующий драйвер

Pdo\Sqlite::createFunction(string $function_name, callable $callback, int $num_args = -1, int $flags = 0): bool

Рассчитать текст наличия при чтении каталога. Регистрируем правило в соединении до SQL, который его использует. function задаёт тело callback; return возвращает результат базе. Для старого PDO соответствующий метод имеет префикс sqlite.

Данные и действие: Pdo\Sqlite::createFunction
  1. $db->createFunction('stock_label', $callback, 1)
  2. SQL передаёт stock0 в PHP callback; return отдаёт текст обратно SQL под именем availability. Один параметр функции указан числом 1.
  3. После выполнения: Кисть: Нет в наличии

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Рассчитать текст наличия при чтении каталогаСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->createFunction('stock_label', function ($stock) {
    return $stock > 0 ? $stock . ' шт.' : 'Нет в наличии';
}, 1);
$row = $db->query('SELECT name, stock_label(stock) AS availability FROM products WHERE id = 3')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ': ', $row['availability'], "\n";
Ожидаемый результат
Кисть: Нет в наличии

SQL передаёт stock0 в PHP callback; return отдаёт текст обратно SQL под именем availability. Один параметр функции указан числом 1.

Если требование изменится. Callback исполняется для строк запроса и может стоить дорого. Он существует только у данного соединения. Не делайте внутри повторный запрос к той же базе или внешнюю сеть; обычные выражения CASE часто проще.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Добавить в SQLite скалярную функцию, реализованную PHP-кодом.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$function_nameИмя функции в SQL; выбирает разработчик, не посетитель.
$callbackПолучает аргументы SQL и возвращает понимаемое SQLite скалярное значение/null.
$num_argsФиксированное число аргументов; -1 разрешает переменное.
$flags0 либо DETERMINISTIC. Современная константа Pdo\Sqlite::DETERMINISTIC; старое PDO::SQLITE_DETERMINISTIC устарело с 8.5.

true/false при регистрации. Можно переопределить встроенную SQL-функцию, но это меняет поведение только данного соединения и усложняет переносимость. SQL может вызывать callback многократно; не помещайте туда оплату/отправку сообщений. Доступно через драйверный подкласс с 8.4.

Путь данных
  1. createFunction регистрирует with_fee
  2. SQL вызывает with_fee(100)
  3. PHP получает 100 и возвращает 130
  4. fetchColumn получает SQL-результат 130

Как читать этот вариант. createFunction связывает имя SQL с PHP callback на этом соединении. В SELECT значение 100 становится аргументом callback, 130 возвращается в вычисление SQL; это не встроенная функция всех баз SQLite.

Вызвать PHP-правило из SQLСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createFunction('with_fee', fn ($price) => $price + 30, 1);
echo $db->query('SELECT with_fee(100)')->fetchColumn(), "\n";
Ожидаемый результат
130

Как читать этот вариант. Флаг DETERMINISTIC обещает один результат для одинаковых входов в пределах SQL-операции. Callback с часами, случайностью или внешним запросом такого обещания не выполняет. На больших выборках каждый PHP-вызов добавляет работу, поэтому встроенное SQL-выражение часто проще.

Собрать подпись из двух столбцовСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createFunction('item_label', fn ($sku, $name) => $sku . ': ' . $name, 2, Pdo\Sqlite::DETERMINISTIC);
echo $db->query("SELECT item_label('PEN-1', 'Pen')")->fetchColumn(), "\n";
Ожидаемый результат
PEN-1: Pen

Рядом: PDO::connect(), Pdo\Sqlite::createAggregate().

PDO::sqliteCreateFunctionДобавить в SQLite скалярную функцию, реализованную PHP-кодом.

PHP 5.1+; устарело с PHP 8.5 · PDO; соответствующий драйвер

PDO::sqliteCreateFunction(string $function_name, callable $callback, int $num_args = -1, int $flags = 0): bool

Рассчитать текст наличия при чтении каталога. Регистрируем правило в соединении до SQL, который его использует. function задаёт тело callback; return возвращает результат базе. Для старого PDO соответствующий метод имеет префикс sqlite.

Данные и действие: PDO::sqliteCreateFunction
  1. $db->createFunction('stock_label', $callback, 1)
  2. SQL передаёт stock0 в PHP callback; return отдаёт текст обратно SQL под именем availability. Один параметр функции указан числом 1.
  3. После выполнения: Кисть: Нет в наличии

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Рассчитать текст наличия при чтении каталогаСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->createFunction('stock_label', function ($stock) {
    return $stock > 0 ? $stock . ' шт.' : 'Нет в наличии';
}, 1);
$row = $db->query('SELECT name, stock_label(stock) AS availability FROM products WHERE id = 3')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ': ', $row['availability'], "\n";
Ожидаемый результат
Кисть: Нет в наличии

SQL передаёт stock0 в PHP callback; return отдаёт текст обратно SQL под именем availability. Один параметр функции указан числом 1.

Если требование изменится. Callback исполняется для строк запроса и может стоить дорого. Он существует только у данного соединения. Не делайте внутри повторный запрос к той же базе или внешнюю сеть; обычные выражения CASE часто проще.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Добавить в SQLite скалярную функцию, реализованную PHP-кодом.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$function_nameИмя функции в SQL; выбирает разработчик, не посетитель.
$callbackПолучает аргументы SQL и возвращает понимаемое SQLite скалярное значение/null.
$num_argsФиксированное число аргументов; -1 разрешает переменное.
$flags0 либо DETERMINISTIC. Современная константа Pdo\Sqlite::DETERMINISTIC; старое PDO::SQLITE_DETERMINISTIC устарело с 8.5.

true/false при регистрации. Можно переопределить встроенную SQL-функцию, но это меняет поведение только данного соединения и усложняет переносимость. SQL может вызывать callback многократно; не помещайте туда оплату/отправку сообщений. Старый метод — alias, с 8.5 deprecated; миграция: новый драйверный объект и короткое имя.

Путь данных
  1. createFunction регистрирует with_fee
  2. SQL вызывает with_fee(100)
  3. PHP получает 100 и возвращает 130
  4. fetchColumn получает SQL-результат 130

Как читать этот вариант. Историческое имя требует pdo_sqlite и базовый PDO. Пример приведён для миграции и только проверяется на синтаксис: современный код использует Pdo\Sqlite::createFunction.

Старое имя в существующем проектеПример для указанного окружения
<?php
$db = new PDO('sqlite::memory:');
$db->sqliteCreateFunction('with_fee', fn ($price) => $price + 30, 1);
echo $db->query('SELECT with_fee(100)')->fetchColumn();
Ожидаемый результат
На PHP до 8.5: 130; в 8.5 также предупреждение устаревания.

Как читать этот вариант. Флаг DETERMINISTIC обещает один результат для одинаковых входов в пределах SQL-операции. Callback с часами, случайностью или внешним запросом такого обещания не выполняет. На больших выборках каждый PHP-вызов добавляет работу, поэтому встроенное SQL-выражение часто проще.

Собрать подпись из двух столбцовСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createFunction('item_label', fn ($sku, $name) => $sku . ': ' . $name, 2, Pdo\Sqlite::DETERMINISTIC);
echo $db->query("SELECT item_label('PEN-1', 'Pen')")->fetchColumn(), "\n";
Ожидаемый результат
PEN-1: Pen

Рядом: PDO::connect(), Pdo\Sqlite::createAggregate().

Pdo\Sqlite::createAggregateВычислить собственный итог по нескольким строкам SQLite.

PHP 8.4+ · PDO; соответствующий драйвер

Pdo\Sqlite::createAggregate(string $name, callable $step, callable $finalize, int $numArgs = -1): bool

Собрать итог остатков в собственном агрегате. Регистрируем правило в соединении до SQL, который его использует. function задаёт тело callback; return возвращает результат базе. Для старого PDO соответствующий метод имеет префикс sqlite.

Данные и действие: Pdo\Sqlite::createAggregate
  1. $db->createAggregate('stock_total', $step, $final, 1)
  2. Шаг получает предыдущую сумму и stock очередного товара:0+8,8+15,23+0. Итоговый callback возвращает 23. В обычном запросе это проще делает SUM(stock); пример объясняет устройство собственного агрегата.
  3. После выполнения: Всего на складе: 23 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Собрать итог остатков в собственном агрегатеСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->createAggregate('stock_total',
    function ($sum, $rowNumber, $stock) { return ($sum ?? 0) + $stock; },
    function ($sum, $rowCount) { return $sum ?? 0; }, 1);
$row = $db->query('SELECT stock_total(stock) AS total FROM products')->fetch(PDO::FETCH_ASSOC);
echo 'Всего на складе: ', $row['total'], " шт.\n";
Ожидаемый результат
Всего на складе: 23 шт.

Шаг получает предыдущую сумму и stock очередного товара:0+8,8+15,23+0. Итоговый callback возвращает 23. В обычном запросе это проще делает SUM(stock); пример объясняет устройство собственного агрегата.

Если требование изменится. Состояние передаётся возвращаемым значением callback, а не изменением случайной внешней переменной. Определите исход пустой группы и NULL; не держите все строки в массиве ради накопления одного итога.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Вычислить собственный итог по нескольким строкам SQLite.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$nameИмя агрегата в SQL.
$stepcallback(context, rownumber, value, ...values): mixed; исходный context=null, возврат станет следующим context.
$finalizecallback(context, rowcount): mixed; получает последнее состояние и число строк, возвращает SQL-значение.
$numArgsЧисло SQL-аргументов; -1 переменное.

true/false. Состояние накапливают в возвращаемом context, а не рассчитывают на изменение копии параметра без return. finalize должен вернуть скаляр/null, не PHP-массив. Возможны пользовательские агрегаты и GROUP BY; встроенные SUM/AVG дешевле и понятнее, если делают нужное.

Путь данных
  1. Строка 120 × 2 → context 240
  2. Строка 350 × 1 → context 590
  3. finalize получает 590 и count 2
  4. SQL возвращает итог 590

Как читать этот вариант. step получает контекст предыдущего шага, номер строки и два SQL-аргумента. Возвращённые 240 переходят в следующий context, затем получается 590; finalize превращает последнее состояние в итог. Обычный SUM(price*quantity) здесь проще: пример объясняет устройство, которое пригодится для действительно собственного агрегата.

Накопить сумму взвешенных единицСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createAggregate('weighted_sum',
    fn ($context, $rowNumber, $price, $quantity) => ($context ?? 0) + $price * $quantity,
    fn ($context, $rowCount) => $context ?? 0,
    2
);
echo $db->query('SELECT weighted_sum(price, quantity) FROM (SELECT 120 AS price, 2 AS quantity UNION ALL SELECT 350, 1)')->fetchColumn(), "\n";
Ожидаемый результат
590

Как читать этот вариант. Пустая выборка оставляет context=null. finalize явно выбирает итог 0. Это бизнес-решение: среднее по пустому набору, например, логичнее вернуть null, а не делить на ноль.

Предусмотреть отсутствие входных строкСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createAggregate('total_units', fn ($sum, $row, $value) => ($sum ?? 0) + $value, fn ($sum, $count) => $sum ?? 0, 1);
echo $db->query('SELECT total_units(value) FROM (SELECT 1 AS value) WHERE 0')->fetchColumn(), "\n";
Ожидаемый результат
0

Рядом: Pdo\Sqlite::createFunction().

PDO::sqliteCreateAggregateВычислить собственный итог по нескольким строкам SQLite.

PHP 5.1+; устарело с PHP 8.5 · PDO; соответствующий драйвер

PDO::sqliteCreateAggregate(string $name, callable $step, callable $finalize, int $numArgs = -1): bool

Собрать итог остатков в собственном агрегате. Регистрируем правило в соединении до SQL, который его использует. function задаёт тело callback; return возвращает результат базе. Для старого PDO соответствующий метод имеет префикс sqlite.

Данные и действие: PDO::sqliteCreateAggregate
  1. $db->createAggregate('stock_total', $step, $final, 1)
  2. Шаг получает предыдущую сумму и stock очередного товара:0+8,8+15,23+0. Итоговый callback возвращает 23. В обычном запросе это проще делает SUM(stock); пример объясняет устройство собственного агрегата.
  3. После выполнения: Всего на складе: 23 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Собрать итог остатков в собственном агрегатеСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->createAggregate('stock_total',
    function ($sum, $rowNumber, $stock) { return ($sum ?? 0) + $stock; },
    function ($sum, $rowCount) { return $sum ?? 0; }, 1);
$row = $db->query('SELECT stock_total(stock) AS total FROM products')->fetch(PDO::FETCH_ASSOC);
echo 'Всего на складе: ', $row['total'], " шт.\n";
Ожидаемый результат
Всего на складе: 23 шт.

Шаг получает предыдущую сумму и stock очередного товара:0+8,8+15,23+0. Итоговый callback возвращает 23. В обычном запросе это проще делает SUM(stock); пример объясняет устройство собственного агрегата.

Если требование изменится. Состояние передаётся возвращаемым значением callback, а не изменением случайной внешней переменной. Определите исход пустой группы и NULL; не держите все строки в массиве ради накопления одного итога.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Вычислить собственный итог по нескольким строкам SQLite.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$nameИмя агрегата в SQL.
$stepcallback(context, rownumber, value, ...values): mixed; исходный context=null, возврат станет следующим context.
$finalizecallback(context, rowcount): mixed; получает последнее состояние и число строк, возвращает SQL-значение.
$numArgsЧисло SQL-аргументов; -1 переменное.

true/false. Состояние накапливают в возвращаемом context, а не рассчитывают на изменение копии параметра без return. finalize должен вернуть скаляр/null, не PHP-массив. Возможны пользовательские агрегаты и GROUP BY; встроенные SUM/AVG дешевле и понятнее, если делают нужное. Старое имя alias устарело с 8.5; оба современных примера показывают целевой API миграции.

Путь данных
  1. Строка 120 × 2 → context 240
  2. Строка 350 × 1 → context 590
  3. finalize получает 590 и count 2
  4. SQL возвращает итог 590

Как читать этот вариант. step получает контекст предыдущего шага, номер строки и два SQL-аргумента. Возвращённые 240 переходят в следующий context, затем получается 590; finalize превращает последнее состояние в итог. Обычный SUM(price*quantity) здесь проще: пример объясняет устройство, которое пригодится для действительно собственного агрегата.

Накопить сумму взвешенных единицСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createAggregate('weighted_sum',
    fn ($context, $rowNumber, $price, $quantity) => ($context ?? 0) + $price * $quantity,
    fn ($context, $rowCount) => $context ?? 0,
    2
);
echo $db->query('SELECT weighted_sum(price, quantity) FROM (SELECT 120 AS price, 2 AS quantity UNION ALL SELECT 350, 1)')->fetchColumn(), "\n";
Ожидаемый результат
590

Как читать этот вариант. Пустая выборка оставляет context=null. finalize явно выбирает итог 0. Это бизнес-решение: среднее по пустому набору, например, логичнее вернуть null, а не делить на ноль.

Предусмотреть отсутствие входных строкСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createAggregate('total_units', fn ($sum, $row, $value) => ($sum ?? 0) + $value, fn ($sum, $count) => $sum ?? 0, 1);
echo $db->query('SELECT total_units(value) FROM (SELECT 1 AS value) WHERE 0')->fetchColumn(), "\n";
Ожидаемый результат
0

Рядом: Pdo\Sqlite::createFunction().

Pdo\Sqlite::createCollationЗадать собственное сравнение строк для COLLATE в SQLite.

PHP 8.4+ · PDO; соответствующий драйвер

Pdo\Sqlite::createCollation(string $name, callable $callback): bool

Упорядочить номера полок так, как их читает человек. Регистрируем правило в соединении до SQL, который его использует. function задаёт тело callback; return возвращает результат базе. Для старого PDO соответствующий метод имеет префикс sqlite.

Данные и действие: Pdo\Sqlite::createCollation
  1. $db->createCollation('shelf_order', $compare)
  2. SQLite передаёт две строки правилу сравнения. strnatcmp сравнивает числовые части; знак результата задаёт порядок. Без этого правила обычный текстовый порядок поместил быA10 доA2.
  3. После выполнения: A1 · A2 · A10

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Упорядочить номера полок так, как их читает человекСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->exec('CREATE TABLE shelves (label TEXT NOT NULL)');
$db->exec("INSERT INTO shelves VALUES ('A10'), ('A2'), ('A1')");
$db->createCollation('shelf_order', function ($left, $right) { return strnatcmp($left, $right); });
$statement = $db->query('SELECT label FROM shelves ORDER BY label COLLATE shelf_order');
foreach ($statement as $row) { echo $row['label'], "\n"; }
Ожидаемый результат
A1
A2
A10

SQLite передаёт две строки правилу сравнения. strnatcmp сравнивает числовые части; знак результата задаёт порядок. Без этого правила обычный текстовый порядок поместил быA10 доA2.

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

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Задать собственное сравнение строк для COLLATE в SQLite.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$nameИмя правила сортировки в SQL.
$callbackfunction(string $a, string $b): int; отрицательное/0/положительное, лучше -1/0/1.

true/false. С PHP 8.4 нецелый возврат callback вызывает TypeError вместо прежнего приведения. Callback может переопределить существующее правило; смена смысла collation у индексированных данных требует согласованной перестройки индекса. Встроенная сортировка не вызывает PHP на каждое сравнение; своё правило выбирают ради нужной семантики.

Путь данных
  1. SQLite сравнивает item10 и item2
  2. Вызывает natural_sku(a,b)
  3. Callback сообщает порядок
  4. ORDER BY выдаёт item2,item10

Как читать этот вариант. Обычное текстовое сравнение ставит item10 раньше item2. Callback сравнивает строки естественным порядком, <=> 0 нормализует результат в -1/0/1.

Упорядочить артикула с числовой частьюСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createCollation('natural_sku', fn (string $a, string $b): int => strnatcmp($a, $b) <=> 0);
$rows = $db->query("SELECT sku FROM (SELECT 'item10' AS sku UNION ALL SELECT 'item2') ORDER BY sku COLLATE natural_sku")->fetchAll(PDO::FETCH_COLUMN);
echo implode(', ', $rows), "\n";
Ожидаемый результат
item2, item10

Как читать этот вариант. Здесь метки ASCII, strlen считает байты. Для человеческих Unicode-названий нужны согласованные правила Unicode/локали, например Collator. Компаратор обязан быть последовательным, иначе сортировка/индексы ненадёжны.

Сначала короткая метка, затем алфавит при равенствеСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createCollation('label_length', function (string $a, string $b): int {
    return (strlen($a) <=> strlen($b)) ?: (strcmp($a, $b) <=> 0);
});
echo implode(', ', $db->query("SELECT label FROM (SELECT 'box' AS label UNION ALL SELECT 'a' UNION ALL SELECT 'pen') ORDER BY label COLLATE label_length")->fetchAll(PDO::FETCH_COLUMN)), "\n";
Ожидаемый результат
a, box, pen

Рядом: Pdo\Sqlite::createFunction().

PDO::sqliteCreateCollationЗадать собственное сравнение строк для COLLATE в SQLite.

PHP 5.3.11+; устарело с PHP 8.5 · PDO; соответствующий драйвер

PDO::sqliteCreateCollation(string $name, callable $callback): bool

Упорядочить номера полок так, как их читает человек. Регистрируем правило в соединении до SQL, который его использует. function задаёт тело callback; return возвращает результат базе. Для старого PDO соответствующий метод имеет префикс sqlite.

Данные и действие: PDO::sqliteCreateCollation
  1. $db->createCollation('shelf_order', $compare)
  2. SQLite передаёт две строки правилу сравнения. strnatcmp сравнивает числовые части; знак результата задаёт порядок. Без этого правила обычный текстовый порядок поместил быA10 доA2.
  3. После выполнения: A1 · A2 · A10

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Упорядочить номера полок так, как их читает человекСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->exec('CREATE TABLE shelves (label TEXT NOT NULL)');
$db->exec("INSERT INTO shelves VALUES ('A10'), ('A2'), ('A1')");
$db->createCollation('shelf_order', function ($left, $right) { return strnatcmp($left, $right); });
$statement = $db->query('SELECT label FROM shelves ORDER BY label COLLATE shelf_order');
foreach ($statement as $row) { echo $row['label'], "\n"; }
Ожидаемый результат
A1
A2
A10

SQLite передаёт две строки правилу сравнения. strnatcmp сравнивает числовые части; знак результата задаёт порядок. Без этого правила обычный текстовый порядок поместил быA10 доA2.

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

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Задать собственное сравнение строк для COLLATE в SQLite.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$nameИмя правила сортировки в SQL.
$callbackfunction(string $a, string $b): int; отрицательное/0/положительное, лучше -1/0/1.

true/false. С PHP 8.4 нецелый возврат callback вызывает TypeError вместо прежнего приведения. Callback может переопределить существующее правило; смена смысла collation у индексированных данных требует согласованной перестройки индекса. Встроенная сортировка не вызывает PHP на каждое сравнение; своё правило выбирают ради нужной семантики. Старое имя — deprecated alias с 8.5; примеры показывают замену.

Путь данных
  1. SQLite сравнивает item10 и item2
  2. Вызывает natural_sku(a,b)
  3. Callback сообщает порядок
  4. ORDER BY выдаёт item2,item10

Как читать этот вариант. Обычное текстовое сравнение ставит item10 раньше item2. Callback сравнивает строки естественным порядком, <=> 0 нормализует результат в -1/0/1.

Упорядочить артикула с числовой частьюСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createCollation('natural_sku', fn (string $a, string $b): int => strnatcmp($a, $b) <=> 0);
$rows = $db->query("SELECT sku FROM (SELECT 'item10' AS sku UNION ALL SELECT 'item2') ORDER BY sku COLLATE natural_sku")->fetchAll(PDO::FETCH_COLUMN);
echo implode(', ', $rows), "\n";
Ожидаемый результат
item2, item10

Как читать этот вариант. Здесь метки ASCII, strlen считает байты. Для человеческих Unicode-названий нужны согласованные правила Unicode/локали, например Collator. Компаратор обязан быть последовательным, иначе сортировка/индексы ненадёжны.

Сначала короткая метка, затем алфавит при равенствеСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->createCollation('label_length', function (string $a, string $b): int {
    return (strlen($a) <=> strlen($b)) ?: (strcmp($a, $b) <=> 0);
});
echo implode(', ', $db->query("SELECT label FROM (SELECT 'box' AS label UNION ALL SELECT 'a' UNION ALL SELECT 'pen') ORDER BY label COLLATE label_length")->fetchAll(PDO::FETCH_COLUMN)), "\n";
Ожидаемый результат
a, box, pen

Рядом: Pdo\Sqlite::createFunction().

Pdo\Sqlite::openBlobПолучить поток к конкретному BLOB SQLite для чтения или изменения по частям.

PHP 8.4+ · PDO; соответствующий драйвер

Pdo\Sqlite::openBlob(string $table, string $column, int $rowid, ?string $dbname = "main", int $flags = Pdo\Sqlite::OPEN_READONLY): resource|false

Прочитать содержимое квитанции потоком. BLOB хранит байты. Имя таблицы, колонки и rowid1 указывают конкретное вложение. Поток читается через stream_get_contents и обязательно закрывается.

Данные и действие: Pdo\Sqlite::openBlob
  1. $db->openBlob('receipts', 'body', 1, 'main')
  2. В схеме X'...' задаёт известные байты UTF-8/ASCII-квитанции. Вывод содержит сам текст вложения, а не true или размер файла.
  3. После выполнения: RECEIPT #1

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Прочитать содержимое квитанции потокомСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$db->exec('CREATE TABLE receipts (id INTEGER PRIMARY KEY, body BLOB NOT NULL)');
$db->exec("INSERT INTO receipts VALUES (1, X'524543454950542023310A')");
$stream = $db->openBlob('receipts', 'body', 1, 'main');
if ($stream === false) { throw new RuntimeException('Квитанция недоступна'); }
echo stream_get_contents($stream);
fclose($stream);
Ожидаемый результат
RECEIPT #1

В схеме X'...' задаёт известные байты UTF-8/ASCII-квитанции. Вывод содержит сам текст вложения, а не true или размер файла.

Если требование изменится. Не отдавайте вложение по произвольному rowid без проверки прав. Запись в openBlob имеет фиксированный размер и ограничения схемы; для изменения длины обновляют BLOB через SQL. PDO-подкласс требует PHP 8.4+.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить поток к конкретному BLOB SQLite для чтения или изменения по частям.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$table / $columnСуществующая таблица и двоичное поле; имена задаются конфигурацией приложения.
$rowidSQLite rowid нужной записи, не произвольный текстовый primary key.
$dbnameИмя подключённой базы, обычно main; передавайте явное имя.
$flagsOPEN_READONLY по умолчанию; OPEN_READWRITE для изменения. OPEN_CREATE не создаёт строку/BLOB.

Поток либо false; ошибка открытия в PHP 8.5.11 сопровождается E_WARNING независимо от режима SQL-ошибок. Размер уже задан: попытка записи за пределы вызывает предупреждение/ошибку потока. Запись разрешена не для каждой SQLite-колонки/таблицы: indexed/PRIMARY KEY/UNIQUE и дочерний foreign key при включённой проверке имеют ограничения; WITHOUT ROWID не подходит. Изменение строки другим UPDATE/DELETE делает открытый blob handle просроченным; для изменения размера сначала меняют значение в SQL, затем открывают новый поток. После работы fclose до завершения связанных операций. Официальная карточка неполная: договор дополнен исходником PHP и SQLite incremental BLOB API, два сценария выполнены локально.

Путь данных
  1. Строка 1 хранит BLOB ABCDE
  2. openBlob создаёт поток к полю body
  3. fread(3) передаёт PHP байты ABC
  4. fclose освобождает дескриптор

Как читать этот вариант. Поток указывает на BLOB существующей строки с rowid=1. fread прочитал три байта, не потребовав fetchAll всей таблицы. Хранилище данных остаётся SQLite.

Прочитать часть двоичного поля потокомСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->exec('CREATE TABLE documents (id INTEGER PRIMARY KEY, body BLOB)');
$db->exec("INSERT INTO documents VALUES (1, X'4142434445')");
$stream = $db->openBlob('documents', 'body', 1);
echo fread($stream, 3), "\n";
fclose($stream);
Ожидаемый результат
ABC

Как читать этот вариант. zeroblob выделил размер. Поток BLOB позволяет менять байты в существующих границах, а не увеличивать поле как обычный файл; для другого размера нужен SQL UPDATE/новое значение.

Записать в заранее выделенные пять байтовСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->exec('CREATE TABLE documents (id INTEGER PRIMARY KEY, body BLOB)');
$db->exec('INSERT INTO documents VALUES (1, zeroblob(5))');
$stream = $db->openBlob('documents', 'body', 1, 'main', Pdo\Sqlite::OPEN_READWRITE);
fwrite($stream, 'HELLO');
fclose($stream);
echo $db->query('SELECT hex(body) FROM documents')->fetchColumn(), "\n";
Ожидаемый результат
48454C4C4F

Рядом: PDOStatement::bindColumn().

Pdo\Sqlite::loadExtensionПодключить установленное доверенное нативное расширение SQLite, когда его возможностей нет в базовой сборке.

PHP 8.4+; зависит от сборки · PDO; соответствующий драйвер

Pdo\Sqlite::loadExtension(string $name): void

Объяснить отказ, если нужная библиотека отчёта не установлена. Загружается нативная библиотека SQLite, установленная администратором для конкретной сборки. Путь приходит из доверенной конфигурации, никогда из формы.

Данные и действие: Pdo\Sqlite::loadExtension
  1. $db->loadExtension($library)
  2. Архив не содержит стороннего бинарника: выполняется только явная ветка отсутствия зависимости. Успешная загрузка не проверялась и не заявляется.
  3. После выполнения: Расширенный отчёт недоступен: библиотека не установлена

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Объяснить отказ, если нужная библиотека отчёта не установленаСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$library = __DIR__ . '/native/report-extension';
if (!is_file($library)) {
    echo "Расширенный отчёт недоступен: библиотека не установлена\n";
} else {
    $db->loadExtension($library);
    echo "Библиотека отчёта подключена\n";
}
Ожидаемый результат
Расширенный отчёт недоступен: библиотека не установлена

Архив не содержит стороннего бинарника: выполняется только явная ветка отсутствия зависимости. Успешная загрузка не проверялась и не заявляется.

Если требование изменится. Разрешённый каталог/ini, совместимость ОС, разрядности и запрет загрузки в конкретной сборке проверяют отдельно. PHP callback createFunction часто достаточен для небольшого собственного вычисления и не требует бинарной библиотеки.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Подключить установленное доверенное нативное расширение SQLite, когда его возможностей нет в базовой сборке.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$nameПуть к совместимой с ОС/архитектурой SQLite-библиотеке. Не строка SQL и не имя PHP-расширения.

Возврата нет. Пустой путь ValueError, недоступная/неподходящая библиотека PDOException; ограничения сборки и многопоточного веб-SAPI также возможны. PHP 8.5.11 временно разрешает загрузку через C API и после отключает, не открывая SQL load_extension(). Не передавайте путь из запроса посетителя. Примеры проверяют отказы; успешная загрузка отдельного стороннего бинарника здесь не заявлена.

Путь данных
  1. Администратор устанавливает доверенную библиотеку
  2. Приложение выбирает фиксированный путь
  3. loadExtension подключает нативные функции SQLite
  4. SQL затем использует предоставленный API

Как читать этот вариант. Ничего не загружается: показана проверка аргумента. Возможность метода зависит от сборки PDO_SQLITE_OMIT_LOAD_EXTENSION; на такой сборке метода может не быть.

Отклонить пустое имя нативного расширенияСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
try { $db->loadExtension(''); } catch (ValueError $error) { echo "Нужно имя файла\n"; }
Ожидаемый результат
Нужно имя файла

Как читать этот вариант. Файл заведомо отсутствует в изолированном каталоге. В рабочем проекте разрешённый абсолютный путь приходит из конфигурации развёртывания; это загрузка нативного кода в процесс, не установка Composer-пакета.

Обработать отсутствующую библиотеку без SQL-запросаСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
try { $db->loadExtension(__DIR__ . '/missing-extension-library'); } catch (PDOException $error) { echo "Библиотека недоступна\n"; }
Ожидаемый результат
Библиотека недоступна

Рядом: Pdo\Sqlite::createFunction().

Pdo\Sqlite::setAuthorizerОграничить действия SQL при подготовке команд SQLite.

PHP 8.5+ · PDO; соответствующий драйвер

Pdo\Sqlite::setAuthorizer(?callable $callback): void

Разрешить учебному отчёту только чтение products. SQLite вызывает правило при подготовке операций SQL. В этом узком правиле разрешены SELECT и READ таблицы products; всё остальное получает DENY.

Данные и действие: Pdo\Sqlite::setAuthorizer
  1. $db->setAuthorizer($callback)
  2. Чтение успешно, удаление отклонено ещё до изменения строк. Для PDO используются числовые коды действий SQLite21/20 с собственными понятными именами; OK/DENY — результаты проверки.
  3. После выполнения: Молоток — 8 шт. · Отчёт не имеет права удалять товары

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
try / catch / finallytry содержит действие, catch обрабатывает отказ, finally выполняет освобождение ресурсов и при успехе, и при исключении.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Разрешить учебному отчёту только чтение productsСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
const SQLITE_SELECT_ACTION = 21;
const SQLITE_READ_ACTION = 20;
$db->setAuthorizer(function ($action, $table = null) {
    if ($action === SQLITE_SELECT_ACTION) { return Pdo\Sqlite::OK; }
    if ($action === SQLITE_READ_ACTION && $table === 'products') { return Pdo\Sqlite::OK; }
    return Pdo\Sqlite::DENY;
});
$row = $db->query('SELECT name, stock FROM products WHERE id = 1')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
try { $db->exec('DELETE FROM products'); }
catch (Exception $error) { echo "Отчёт не имеет права удалять товары\n"; }
$db->setAuthorizer(null);
Ожидаемый результат
Молоток — 8 шт.
Отчёт не имеет права удалять товары

Чтение успешно, удаление отклонено ещё до изменения строк. Для PDO используются числовые коды действий SQLite21/20 с собственными понятными именами; OK/DENY — результаты проверки.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Это механизм ограничения операций, а не готовая песочница произвольного SQL. Отдельно нужны лимиты работы, памяти, доступных функций и ресурсов. Callback не должен менять это же соединение.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Ограничить действия SQL при подготовке команд SQLite.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$callbackcallback(int action, ?string arg1, ?string arg2, ?string database, ?string triggerOrView): int; смысл arg1/arg2 зависит от кода SQLite. null снимает авторизатор.

На соединении один callback, новая установка заменяет старую. Он вызывается при подготовке и переподготовке, не обязательно на каждой строке/каждом execute. Вернуть OK — разрешить, DENY — отказ команды, IGNORE для чтения — заменить поле null; для DELETE у SQLite другой смысл IGNORE, поэтому не считайте универсальным запретом. Callback не должен менять то же соединение. Не-int даёт TypeError, другой int ValueError при подготовке; метод установки возвращает void. Имена объектов SQLite могут приходить в разном регистре: сравнивайте их без учёта регистра. Коды действий определены SQLite, а константы OK/DENY/IGNORE принадлежат Pdo\Sqlite.

Путь данных
  1. SQL готовится к чтению customers.secret
  2. SQLite спрашивает authorizer(action20,customers,secret)
  3. IGNORE заменяет чтение на NULL
  4. PHP получает Anna и null

Как читать этот вариант. 11 — документированный код действия SQLITE_DROP_TABLE. Это небольшой пример одного запрета, не готовая безопасная консоль для произвольного SQL: отдельно нужны полный список разрешений, ограничения времени/размера/файлов и прав процесса.

Запретить DROP TABLE в учебной SQL-консолиСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->exec('CREATE TABLE notes (id INTEGER)');
const SQLITE_DROP_TABLE_ACTION = 11;
$db->setAuthorizer(fn ($action, $a, $b, $database, $trigger) => $action === SQLITE_DROP_TABLE_ACTION ? Pdo\Sqlite::DENY : Pdo\Sqlite::OK);
try { $db->exec('DROP TABLE notes'); } catch (PDOException $error) { echo "Удаление запрещено\n"; }
$db->setAuthorizer(null);
echo $db->query('SELECT COUNT(*) FROM notes')->fetchColumn(), "\n";
Ожидаемый результат
Удаление запрещено
0

Как читать этот вариант. Для READ код 20 и аргументы table/column определяют доступ к полю. IGNORE подменяет конкретное чтение null. Авторизация приложения по пользователям/строкам — отдельный уровень: callback не знает автоматически, кто открыл страницу.

Заменить закрытую колонку на SQL NULLСамостоятельный пример
<?php
$db = new Pdo\Sqlite('sqlite::memory:');
$db->exec('CREATE TABLE customers (name TEXT, secret TEXT)');
$db->exec("INSERT INTO customers VALUES ('Anna', 'private')");
const SQLITE_READ_ACTION = 20;
$db->setAuthorizer(fn ($action, $table, $column, $database, $trigger) => $action === SQLITE_READ_ACTION && strcasecmp($table ?? '', 'customers') === 0 && strcasecmp($column ?? '', 'secret') === 0 ? Pdo\Sqlite::IGNORE : Pdo\Sqlite::OK);
$row = $db->query('SELECT name, secret FROM customers')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], "\n";
var_dump($row['secret']);
Ожидаемый результат
Anna
NULL

Рядом: PDO::prepare().

PDOStatement::getAttributeПрочитать драйверную характеристику команды и её результата.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::getAttribute(int $name): mixed

Перед просмотром понять, изменяет ли команда базу. Это драйверный атрибут SQLite для PHP 8.5+. Он описывает подготовленную команду, а не права пользователя и не содержимое результата.

Данные и действие: PDOStatement::getAttribute
  1. $statement->getAttribute(Pdo\Sqlite::ATTR_READONLY_STATEMENT)
  2. Перед выполнением проверена ожидаемая характеристика SELECT. Затем читается реальный товар, а не только булев статус.
  3. После выполнения: Молоток — 8 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Перед просмотром понять, изменяет ли команда базуСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->prepare('SELECT name, stock FROM products WHERE id = 1');
$readOnly = $statement->getAttribute(Pdo\Sqlite::ATTR_READONLY_STATEMENT);
if (!$readOnly) { throw new RuntimeException('Ожидалась команда чтения'); }
$statement->execute();
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Молоток — 8 шт.

Перед выполнением проверена ожидаемая характеристика SELECT. Затем читается реальный товар, а не только булев статус.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Требуется PHP 8.5 и поддержка конкретного атрибута. Это не песочница для SQL посетителя: права, ограничения запроса и authorizer решают другие задачи.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Прочитать драйверную характеристику команды и её результата.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$nameПоддерживаемый атрибут statement именно этого драйвера.

Тип зависит от атрибута; общих универсальных атрибутов у statement нет. Firebird/ODBC ATTR_CURSOR_NAME — имя курсора; PostgreSQL Pdo\Pgsql::ATTR_RESULT_MEMORY_SIZE с 8.4 — байты памяти результата. SQLite имеет READONLY_STATEMENT, BUSY_STATEMENT (8.5), EXPLAIN_STATEMENT (8.5). Неподдерживаемый атрибут сообщает ошибку драйвера; PDO::ATTR_ERRMODE и другие настройки соединения читают у $db, не здесь.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. prepare создаёт SQLite statement SELECT1
  2. getAttribute спрашивает READONLY_STATEMENT
  3. Драйвер отвечает true
  4. Настройки соединения остаются отдельными

Как читать этот вариант. Это свойство подготовленной SQL-команды. Оно не заменяет авторизацию приложения и не означает отсутствие работы или чтения данных; API специфичен SQLite.

Проверить, является ли SQLite statement читающимСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->prepare('SELECT 1');
var_dump($statement->getAttribute(Pdo\Sqlite::ATTR_READONLY_STATEMENT));
Ожидаемый результат
bool(true)

Как читать этот вариант. Атрибут PHP 8.5 показывает, что statement исполнен и ещё имеет ожидающие строки. Это состояние конкретной команды, не общий уровень нагрузки базы.

Увидеть незавершённый результат SQLiteСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->query('SELECT 1 UNION ALL SELECT 2');
var_dump($statement->getAttribute(Pdo\Sqlite::ATTR_BUSY_STATEMENT));
$statement->closeCursor();
var_dump($statement->getAttribute(Pdo\Sqlite::ATTR_BUSY_STATEMENT));
Ожидаемый результат
bool(true)
bool(false)

Рядом: PDO::getAttribute(), PDOStatement::setAttribute().

PDOStatement::setAttributeИзменить драйверную настройку конкретного statement.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::setAttribute(int $attribute, mixed $value): bool

Переключиться с плана запроса обратно к данным. В PHP 8.5 SQLite позволяет менять режим объяснения statement. План описывает выполнение, режим PREPARED возвращает обычные строки товара.

Данные и действие: PDOStatement::setAttribute
  1. $statement->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, ...)
  2. Первый результат содержит detail с описанием поиска. После закрытия курсора и смены режима обратно SELECT возвращает name и stock. Проверка SEARCH демонстрационная: текст плана не является стабильным протоколом. План и данные не следует обрабатывать одним и тем же шаблоном колонок.
  3. После выполнения: Поиск по ключу · Молоток — 8 шт.

В архиве catalog.php открывает отдельную учебную базу и выполняет schema.sql: 1 — Молоток, 8 шт.; 2 — Перчатки, 15 шт.; 3 — Кисть, 0 шт. База находится в памяти и начинает работу с этих данных при каждом запуске. Распакуйте все файлы вместе и запустите php example.php. Полная подготовка и схема.

Запись в этом примереКак читать
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Переключиться с плана запроса обратно к даннымСамостоятельный пример
<?php
require __DIR__ . '/catalog.php';
$statement = $db->prepare('SELECT name, stock FROM products WHERE id = 1');
$statement->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN);
$statement->execute();
$plan = $statement->fetch(PDO::FETCH_ASSOC);
echo str_contains($plan['detail'], 'SEARCH') ? "Поиск по ключу\n" : "Проверьте план чтения\n";
$statement->closeCursor();
$statement->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_PREPARED);
$statement->execute();
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Поиск по ключу
Молоток — 8 шт.

Первый результат содержит detail с описанием поиска. После закрытия курсора и смены режима обратно SELECT возвращает name и stock. Проверка SEARCH демонстрационная: текст плана не является стабильным протоколом. План и данные не следует обрабатывать одним и тем же шаблоном колонок.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Атрибуты statement не равны атрибутам соединения и не обязаны поддерживаться другим драйвером. Режим EXPLAIN полезен для диагностики индекса, но не обещает ускорения сам по себе.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Изменить драйверную настройку конкретного statement.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$attributeНапример ATTR_CURSOR_NAME для Firebird/ODBC, SQLite ATTR_EXPLAIN_STATEMENT с 8.5.
$valueИмя курсора либо поддерживаемое драйвером значение нужного типа.

true/false. В PHP 8.5 слишком длинное имя Firebird-курсора вызывает ValueError. SQLite EXPLAIN требует libsqlite >=3.43.0, иначе ValueError; доступные режимы PREPARED/EXPLAIN/EXPLAIN_QUERY_PLAN. Методы не устанавливают общие параметры соединения: ERRMODE, AUTOCOMMIT и прочие задают через PDO::setAttribute. Имя курсора применяют к WHERE CURRENT OF только в поддерживающей это СУБД.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Подготовлен SELECT товара
  2. Атрибут переключает statement в QUERY_PLAN
  3. execute выдаёт описание маршрута поиска
  4. PREPARED возвращает обычные данные

Как читать этот вариант. PHP 8.5 и libsqlite не старше 3.43.0. План описывает способ выполнения, не найденный товар; текст detail зависит от SQLite и не фиксируется здесь как стабильная строка.

Попросить SQLite вернуть план вместо данныхСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT)');
$statement = $db->prepare('SELECT name FROM products WHERE id = 1');
$statement->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN);
$statement->execute();
$row = $statement->fetch(PDO::FETCH_ASSOC);
var_dump(isset($row['detail']));
Ожидаемый результат
bool(true)

Как читать этот вариант. PREPARED возвращает исполнение исходного SQL. EXPLAIN выдаёт инструкции виртуальной машины, QUERY_PLAN — высокоуровневый план; это различные диагностические результаты.

Вернуть команду из режима объяснения к даннымСамостоятельный пример
<?php
$db = new PDO('sqlite::memory:', null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->prepare('SELECT 42 AS answer');
$statement->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN);
$statement->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_PREPARED);
$statement->execute();
echo $statement->fetchColumn(), "\n";
Ожидаемый результат
42

Рядом: PDOStatement::getAttribute(), PDO::setAttribute().

PDOStatement::nextRowsetПерейти к следующему набору строк, возвращённому процедурой или составной командой.

PHP 5.1+; примеры PHP 8.2+ · PDO; соответствующий драйвер

PDOStatement::nextRowset(): bool

Прочитать два разных ответа одной доверенной команды. Каждый набор имеет свои строки и колонки. После чтения первого набора nextRowset переключает statement на следующий; это не следующая строка того же набора.

Данные и действие: PDOStatement::nextRowset
  1. $statement->nextRowset()
  2. Первый SELECT возвращает карточки товаров, второй — одну агрегированную строку. Пример использует PDO MySQL и фиксированный списокSQL; драйвер SQLite этот API не поддерживает.
  3. После выполнения: Молоток — 8 шт. · Перчатки — 15 шт. · Кисть — 0 шт. · Всего позиций: 3

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Прочитать два разных ответа одной доверенной командыПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query('SELECT name, stock FROM products ORDER BY id; SELECT COUNT(*) AS total FROM products');
foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) { echo $row['name'], ' — ', $row['stock'], " шт.\n"; }
if (!$statement->nextRowset()) { throw new RuntimeException('Итоговый набор отсутствует'); }
echo 'Всего позиций: ', $statement->fetchColumn(), "\n";
$statement->closeCursor();
Ожидаемый результат
Молоток — 8 шт.
Перчатки — 15 шт.
Кисть — 0 шт.
Всего позиций: 3

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Первый SELECT возвращает карточки товаров, второй — одну агрегированную строку. Пример использует PDO MySQL и фиксированный списокSQL; драйвер SQLite этот API не поддерживает.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.
Перчатки15 шт.
Кисть0 шт.

Если требование изменится. Никогда не склеивайте multi-statements из ввода. Возможность зависит от драйвера/флагов; процедура может отдавать ещё и завершающий пустой статус. До нового запроса обработайте/освободите все наборы.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Перейти к следующему набору строк, возвращённому процедурой или составной командой.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

true при переходе, false при отсутствии следующего/неудаче (ERRMODE может выбросить исключение). Каждый набор может иметь собственные колонки; заново проверяйте columnCount/метаданные. Это следующий result set, не следующая строка и не следующая страница SQL LIMIT. Поддержка зависит от сервера/драйвера; SQLite не превращает пакет SQL в такой переносимый API.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Процедура возвращает список заказов
  2. fetch читает строки первого набора
  3. nextRowset открывает второй набор итогов
  4. После последнего false и closeCursor

Как читать этот вариант. Это контекст MySQL и доверенный фиксированный SQL. Локально выполнена только проверка синтаксиса, сервера MySQL нет. Возможность multiple statements задаётся драйвером; не включайте её ради пользовательской склейки SQL.

Прочитать два результата одной MySQL-командыПример для указанного окружения
<?php
$db = new PDO(getenv('MYSQL_DSN'), getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->query("SELECT 'orders' AS label; SELECT 'totals' AS label");
echo $statement->fetchColumn(), "\n";
if ($statement->nextRowset()) { echo $statement->fetchColumn(), "\n"; }
$statement->closeCursor();
Ожидаемый результат
При PDO_MYSQL с разрешёнными multiple statements: orders
totals

Как читать этот вариант. Требуются установленная процедура, pdo_mysql, сервер и согласованная схема; пример только lint. У разных наборов может быть разная форма. Потребление/закрытие всех наборов предотвращает ошибки следующей команды на занятом соединении.

Обработать наборы процедуры, пропуская ответы без колонокПример для указанного окружения
<?php
$db = new PDO(getenv('MYSQL_DSN'), getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$statement = $db->prepare('CALL report_orders(?)');
$statement->execute([42]);
try {
    do {
        if ($statement->columnCount() > 0) {
            while (($row = $statement->fetch(PDO::FETCH_ASSOC)) !== false) {
                echo json_encode($row, JSON_THROW_ON_ERROR), "\n";
            }
        }
    } while ($statement->nextRowset());
} finally { $statement->closeCursor(); }
Ожидаемый результат
Строки каждого набора процедуры report_orders для клиента 42, по JSON на строку.

Рядом: PDOStatement::fetch(), PDOStatement::columnCount(), PDOStatement::closeCursor().

Pdo\Pgsql::copyFromArrayБыстро передать пакет записей PostgreSQL через протокол COPY.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::copyFromArray(string $tableName, array|Traversable $rows, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): bool

Импортировать две новые позиции и прочитать их обратно. COPY передаёт сразу набор строк. Поля следуют в порядке id,name,stock; разделитель | выбран явно. SQL NULL обозначался бы специальным маркером, а не пустым текстом.

Данные и действие: Pdo\Pgsql::copyFromArray
  1. $db->copyFromArray('products', ..., '|', '\\N', 'id,name,stock')
  2. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.
  3. После выполнения: Отвёртка — 4 шт. · Рулетка — 6 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Импортировать две новые позиции и прочитать их обратноПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$lines = ['4|Отвёртка|4', '5|Рулетка|6'];
$db->copyFromArray('products', $lines, '|', '\\N', 'id,name,stock');
$statement = $db->query('SELECT name, stock FROM products WHERE id >= 4 ORDER BY id');
foreach ($statement as $row) { echo $row['name'], ' — ', $row['stock'], " шт.\n"; }
Ожидаемый результат
Отвёртка — 4 шт.
Рулетка — 6 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Отвёртка4 шт.
Рулетка6 шт.

Если требование изменится. Нужны PostgreSQL/pdo_pgsql и PHP8.4 для подкласса; старое PDO-имя приведено в контракте ниже. COPY text — не произвольный CSV: разделители, переводы строк, backslash и NULL требуют согласованного формата. Ошибочный пакет обрабатывайте транзакцией.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Быстро передать пакет записей PostgreSQL через протокол COPY.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$rowsМассив строк формата PostgreSQL COPY text; с PHP 8.5 также Traversable. Это не массив ассоциативных записей.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

true/false; SQL и I/O ошибки подчиняются ERRMODE. COPY text — отдельный формат: строку с табуляцией нельзя безопасно получить обычным implode, а CSV-кавычки не являются его экранированием. Для небольшого импорта параметризованный INSERT проще; при большом объёме COPY сокращает накладные расходы отдельных команд. Валидацию и транзакцию импорта продумывают отдельно.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. PHP даёт строку 1<TAB>Pen
  2. COPY делит её на id и name
  3. PostgreSQL добавляет запись
  4. Следующая строка может поступить из Generator

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Временная таблица относится к учебному соединению. Поля фиксированные и не содержат спецсимволов COPY; для внешнего текста требуется кодирование обратного слеша, табуляций, переводов строк и NULL по формату COPY.

Загрузить две простые строки справочникаПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
$db->copyFromArray('import_items', ["1\tPen", "2\tBox"]);
echo $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn(), "\n";
Ожидаемый результат
2

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Generator не собирает полный PHP-массив всех строк. Это уменьшает один источник затрат памяти, но не освобождает от ограничений БД и обработки ошибки загрузки. В PHP 8.4 нужен массив, Traversable добавлен в 8.5.

Отдавать строки импорта постепенно в PHP 8.5Пример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
function importRows(): Generator {
    yield "1\tPen";
    yield "2\tBox";
}
$db->copyFromArray('import_items', importRows());
echo $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn(), "\n";
Ожидаемый результат
2

Рядом: PDO::prepare().

PDO::pgsqlCopyFromArrayБыстро передать пакет записей PostgreSQL через протокол COPY. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlCopyFromArray(string $tableName, array|Traversable $rows, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): bool

Импортировать две новые позиции и прочитать их обратно. COPY передаёт сразу набор строк. Поля следуют в порядке id,name,stock; разделитель | выбран явно. SQL NULL обозначался бы специальным маркером, а не пустым текстом.

Данные и действие: PDO::pgsqlCopyFromArray
  1. $db->copyFromArray('products', ..., '|', '\\N', 'id,name,stock')
  2. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.
  3. После выполнения: Отвёртка — 4 шт. · Рулетка — 6 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Импортировать две новые позиции и прочитать их обратноПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$lines = ['4|Отвёртка|4', '5|Рулетка|6'];
$db->copyFromArray('products', $lines, '|', '\\N', 'id,name,stock');
$statement = $db->query('SELECT name, stock FROM products WHERE id >= 4 ORDER BY id');
foreach ($statement as $row) { echo $row['name'], ' — ', $row['stock'], " шт.\n"; }
Ожидаемый результат
Отвёртка — 4 шт.
Рулетка — 6 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Отвёртка4 шт.
Рулетка6 шт.

Если требование изменится. Нужны PostgreSQL/pdo_pgsql и PHP8.4 для подкласса; старое PDO-имя приведено в контракте ниже. COPY text — не произвольный CSV: разделители, переводы строк, backslash и NULL требуют согласованного формата. Ошибочный пакет обрабатывайте транзакцией.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Быстро передать пакет записей PostgreSQL через протокол COPY. Историческое имя.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$rowsМассив строк формата PostgreSQL COPY text; с PHP 8.5 также Traversable. Это не массив ассоциативных записей.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

true/false; SQL и I/O ошибки подчиняются ERRMODE. COPY text — отдельный формат: строку с табуляцией нельзя безопасно получить обычным implode, а CSV-кавычки не являются его экранированием. Для небольшого импорта параметризованный INSERT проще; при большом объёме COPY сокращает накладные расходы отдельных команд. Валидацию и транзакцию импорта продумывают отдельно. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте copyFromArray; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. PHP даёт строку 1<TAB>Pen
  2. COPY делит её на id и name
  3. PostgreSQL добавляет запись
  4. Следующая строка может поступить из Generator

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Временная таблица относится к учебному соединению. Поля фиксированные и не содержат спецсимволов COPY; для внешнего текста требуется кодирование обратного слеша, табуляций, переводов строк и NULL по формату COPY.

Загрузить две простые строки справочникаПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
$db->copyFromArray('import_items', ["1\tPen", "2\tBox"]);
echo $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn(), "\n";
Ожидаемый результат
2

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Generator не собирает полный PHP-массив всех строк. Это уменьшает один источник затрат памяти, но не освобождает от ограничений БД и обработки ошибки загрузки. В PHP 8.4 нужен массив, Traversable добавлен в 8.5.

Отдавать строки импорта постепенно в PHP 8.5Пример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
function importRows(): Generator {
    yield "1\tPen";
    yield "2\tBox";
}
$db->copyFromArray('import_items', importRows());
echo $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn(), "\n";
Ожидаемый результат
2

Рядом: Pdo\Pgsql::copyFromArray(), PDO::prepare().

Pdo\Pgsql::copyFromFileЗагрузить подготовленный локальный файл в таблицу PostgreSQL.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::copyFromFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): bool

Импортировать две новые позиции и прочитать их обратно. COPY передаёт сразу набор строк. Поля следуют в порядке id,name,stock; разделитель | выбран явно. SQL NULL обозначался бы специальным маркером, а не пустым текстом.

Данные и действие: Pdo\Pgsql::copyFromFile
  1. $db->copyFromFile('products', ..., '|', '\\N', 'id,name,stock')
  2. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.
  3. После выполнения: Отвёртка — 4 шт. · Рулетка — 6 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Импортировать две новые позиции и прочитать их обратноПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$file = __DIR__ . '/incoming.txt';
$db->copyFromFile('products', $file, '|', '\\N', 'id,name,stock');
$statement = $db->query('SELECT name, stock FROM products WHERE id >= 4 ORDER BY id');
foreach ($statement as $row) { echo $row['name'], ' — ', $row['stock'], " шт.\n"; }
Ожидаемый результат
Отвёртка — 4 шт.
Рулетка — 6 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Отвёртка4 шт.
Рулетка6 шт.

Если требование изменится. Нужны PostgreSQL/pdo_pgsql и PHP8.4 для подкласса; старое PDO-имя приведено в контракте ниже. COPY text — не произвольный CSV: разделители, переводы строк, backslash и NULL требуют согласованного формата. Ошибочный пакет обрабатывайте транзакцией.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Загрузить подготовленный локальный файл в таблицу PostgreSQL.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$filenameПуть к файлу, который читает PHP-процесс, не серверный путь PostgreSQL.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

true/false. Недоступный для чтения файл сообщает ошибку через ERRMODE, при EXCEPTION — PDOException. Источник должен уже соответствовать COPY text; CSV/XLSX/JSON сначала преобразуют с правильным кодированием. Имена таблицы/колонок задают доверенно, файл с персональными данными удаляют по политике проекта после обработки.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. PHP открывает import.tsv
  2. Драйвер передаёт содержимое по COPY
  3. Сервер разбирает две колонки
  4. Транзакция подтверждает согласованный пакет

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Путь принадлежит процессу приложения. Это не SQL COPY FROM filename, которому требовался бы файл на машине сервера. Для реального импорта выбирайте свой временный каталог и лимит размера файла.

Импортировать подготовленный файл COPY textПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
$path = __DIR__ . '/import.tsv';
file_put_contents($path, "1\tPen\n2\tBox\n");
$db->copyFromFile('import_items', $path);
echo $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn(), "\n";
Ожидаемый результат
2

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Пример показывает общую границу транзакции. Один счётчик не проверяет содержимое: боевой импорт дополнительно проверяет ключи, типы, связи, дубли и допустимые значения.

Подтвердить файл только вместе с проверкой количестваПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
file_put_contents(__DIR__ . '/batch.tsv', "1\tPen\n");
$db->beginTransaction();
try {
    $db->copyFromFile('import_items', __DIR__ . '/batch.tsv');
    $count = (int) $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn();
    if ($count !== 1) { throw new RuntimeException('Неполный пакет'); }
    $db->commit();
    echo "Пакет принят\n";
} catch (Throwable $error) {
    if ($db->inTransaction()) { $db->rollBack(); }
    throw $error;
}
Ожидаемый результат
Пакет принят

Рядом: Pdo\Pgsql::copyFromArray(), Pdo\Pgsql::copyToFile().

PDO::pgsqlCopyFromFileЗагрузить подготовленный локальный файл в таблицу PostgreSQL. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlCopyFromFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): bool

Импортировать две новые позиции и прочитать их обратно. COPY передаёт сразу набор строк. Поля следуют в порядке id,name,stock; разделитель | выбран явно. SQL NULL обозначался бы специальным маркером, а не пустым текстом.

Данные и действие: PDO::pgsqlCopyFromFile
  1. $db->copyFromFile('products', ..., '|', '\\N', 'id,name,stock')
  2. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.
  3. После выполнения: Отвёртка — 4 шт. · Рулетка — 6 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Импортировать две новые позиции и прочитать их обратноПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$file = __DIR__ . '/incoming.txt';
$db->copyFromFile('products', $file, '|', '\\N', 'id,name,stock');
$statement = $db->query('SELECT name, stock FROM products WHERE id >= 4 ORDER BY id');
foreach ($statement as $row) { echo $row['name'], ' — ', $row['stock'], " шт.\n"; }
Ожидаемый результат
Отвёртка — 4 шт.
Рулетка — 6 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Входные строки4 и5 заданы в коде или файле incoming.txt архива. После COPY SELECT выбирает именно эти записи, поэтому результат проверяет импорт содержимого.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Отвёртка4 шт.
Рулетка6 шт.

Если требование изменится. Нужны PostgreSQL/pdo_pgsql и PHP8.4 для подкласса; старое PDO-имя приведено в контракте ниже. COPY text — не произвольный CSV: разделители, переводы строк, backslash и NULL требуют согласованного формата. Ошибочный пакет обрабатывайте транзакцией.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

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

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$filenameПуть к файлу, который читает PHP-процесс, не серверный путь PostgreSQL.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

true/false. Недоступный для чтения файл сообщает ошибку через ERRMODE, при EXCEPTION — PDOException. Источник должен уже соответствовать COPY text; CSV/XLSX/JSON сначала преобразуют с правильным кодированием. Имена таблицы/колонок задают доверенно, файл с персональными данными удаляют по политике проекта после обработки. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте copyFromFile; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. PHP открывает import.tsv
  2. Драйвер передаёт содержимое по COPY
  3. Сервер разбирает две колонки
  4. Транзакция подтверждает согласованный пакет

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Путь принадлежит процессу приложения. Это не SQL COPY FROM filename, которому требовался бы файл на машине сервера. Для реального импорта выбирайте свой временный каталог и лимит размера файла.

Импортировать подготовленный файл COPY textПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
$path = __DIR__ . '/import.tsv';
file_put_contents($path, "1\tPen\n2\tBox\n");
$db->copyFromFile('import_items', $path);
echo $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn(), "\n";
Ожидаемый результат
2

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Пример показывает общую границу транзакции. Один счётчик не проверяет содержимое: боевой импорт дополнительно проверяет ключи, типы, связи, дубли и допустимые значения.

Подтвердить файл только вместе с проверкой количестваПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE import_items (id integer, name text)');
file_put_contents(__DIR__ . '/batch.tsv', "1\tPen\n");
$db->beginTransaction();
try {
    $db->copyFromFile('import_items', __DIR__ . '/batch.tsv');
    $count = (int) $db->query('SELECT COUNT(*) FROM import_items')->fetchColumn();
    if ($count !== 1) { throw new RuntimeException('Неполный пакет'); }
    $db->commit();
    echo "Пакет принят\n";
} catch (Throwable $error) {
    if ($db->inTransaction()) { $db->rollBack(); }
    throw $error;
}
Ожидаемый результат
Пакет принят

Рядом: Pdo\Pgsql::copyFromFile(), Pdo\Pgsql::copyFromArray(), Pdo\Pgsql::copyToFile().

Pdo\Pgsql::copyToArrayВыгрузить таблицу как массив строк PostgreSQL COPY text.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::copyToArray(string $tableName, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): array|false

Получить передаваемую выгрузку каталога. Экспортируется содержимое таблицы с выбранными полями. COPY не гарантирует желаемую сортировку строк; для точного учебного сравнения сортируем полученные строки в PHP.

Данные и действие: Pdo\Pgsql::copyToArray
  1. $db->copyToArray(...)
  2. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.
  3. После выполнения: Кисть|0 · Молоток|8 · Перчатки|15

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
Получить передаваемую выгрузку каталогаПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$lines = $db->copyToArray('products', '|', '\\N', 'name,stock');
if ($lines === false) { throw new RuntimeException('Выгрузка не получена'); }
$lines = array_map('rtrim', $lines);
sort($lines, SORT_STRING);
foreach ($lines as $line) { echo $line, "\n"; }
Ожидаемый результат
Кисть|0
Молоток|8
Перчатки|15

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.

Если требование изменится. copyToArray держит весь набор в памяти. Для большого экспорта выбирайте файловый/потоковый процесс; для фильтра и ORDER BY часто удобнее SELECT и построчная запись fputcsv. Не выдавайте путь назначения из ввода посетителя.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Выгрузить таблицу как массив строк PostgreSQL COPY text.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

Массив строк либо false. Весь экспорт хранится в памяти PHP; для большого объёма copyToFile или последовательное чтение SELECT удобнее. Разделитель и маркер NULL должны совпадать у импортёра; формат не становится CSV от смены разделителя на запятую.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Таблица отдаёт выбранные поля
  2. COPY кодирует строку 1<TAB>Pen
  3. PHP получает массив строк
  4. Для больших объёмов выбирается файл

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Массив содержит строки COPY text, а не [id=>1,name=>Pen]. При декодировании учитывают backslash-экранирование, а не просто explode для произвольных данных.

Получить строки экспортного форматаПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen')");
$rows = $db->copyToArray('export_items');
echo count($rows), "\n";
echo rtrim($rows[0], "\r\n"), "\n";
Ожидаемый результат
1
1	Pen

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. fields ограничивает состав экспорта. Это удобнее и безопаснее, чем выгрузить все колонки и надеяться удалить закрытое поле потом. Порядок строк без явного SQL ORDER BY не гарантирован.

Экспортировать только публичные поляПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text, internal_note text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen', 'private')");
$rows = $db->copyToArray('export_items', "\t", '\N', 'id,name');
echo rtrim($rows[0], "\r\n"), "\n";
Ожидаемый результат
1	Pen

Рядом: Pdo\Pgsql::copyToFile(), PDOStatement::fetch().

PDO::pgsqlCopyToArrayВыгрузить таблицу как массив строк PostgreSQL COPY text. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlCopyToArray(string $tableName, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): array|false

Получить передаваемую выгрузку каталога. Экспортируется содержимое таблицы с выбранными полями. COPY не гарантирует желаемую сортировку строк; для точного учебного сравнения сортируем полученные строки в PHP.

Данные и действие: PDO::pgsqlCopyToArray
  1. $db->copyToArray(...)
  2. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.
  3. После выполнения: Кисть|0 · Молоток|8 · Перчатки|15

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
Получить передаваемую выгрузку каталогаПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$lines = $db->copyToArray('products', '|', '\\N', 'name,stock');
if ($lines === false) { throw new RuntimeException('Выгрузка не получена'); }
$lines = array_map('rtrim', $lines);
sort($lines, SORT_STRING);
foreach ($lines as $line) { echo $line, "\n"; }
Ожидаемый результат
Кисть|0
Молоток|8
Перчатки|15

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.

Если требование изменится. copyToArray держит весь набор в памяти. Для большого экспорта выбирайте файловый/потоковый процесс; для фильтра и ORDER BY часто удобнее SELECT и построчная запись fputcsv. Не выдавайте путь назначения из ввода посетителя.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Выгрузить таблицу как массив строк PostgreSQL COPY text. Историческое имя.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

Массив строк либо false. Весь экспорт хранится в памяти PHP; для большого объёма copyToFile или последовательное чтение SELECT удобнее. Разделитель и маркер NULL должны совпадать у импортёра; формат не становится CSV от смены разделителя на запятую. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте copyToArray; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Таблица отдаёт выбранные поля
  2. COPY кодирует строку 1<TAB>Pen
  3. PHP получает массив строк
  4. Для больших объёмов выбирается файл

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Массив содержит строки COPY text, а не [id=>1,name=>Pen]. При декодировании учитывают backslash-экранирование, а не просто explode для произвольных данных.

Получить строки экспортного форматаПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen')");
$rows = $db->copyToArray('export_items');
echo count($rows), "\n";
echo rtrim($rows[0], "\r\n"), "\n";
Ожидаемый результат
1
1	Pen

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. fields ограничивает состав экспорта. Это удобнее и безопаснее, чем выгрузить все колонки и надеяться удалить закрытое поле потом. Порядок строк без явного SQL ORDER BY не гарантирован.

Экспортировать только публичные поляПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text, internal_note text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen', 'private')");
$rows = $db->copyToArray('export_items', "\t", '\N', 'id,name');
echo rtrim($rows[0], "\r\n"), "\n";
Ожидаемый результат
1	Pen

Рядом: Pdo\Pgsql::copyToArray(), Pdo\Pgsql::copyToFile(), PDOStatement::fetch().

Pdo\Pgsql::copyToFileЭкспортировать COPY text в локальный файл без массива всех строк.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::copyToFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): bool

Получить передаваемую выгрузку каталога. Экспортируется содержимое таблицы с выбранными полями. COPY не гарантирует желаемую сортировку строк; для точного учебного сравнения сортируем полученные строки в PHP.

Данные и действие: Pdo\Pgsql::copyToFile
  1. $db->copyToFile(...)
  2. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.
  3. После выполнения: Кисть|0 · Молоток|8 · Перчатки|15

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
Получить передаваемую выгрузку каталогаПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$file = __DIR__ . '/catalog-export.txt';
$db->copyToFile('products', $file, '|', '\\N', 'name,stock');
$lines = file($file, FILE_IGNORE_NEW_LINES);
if ($lines === false) { throw new RuntimeException('Выгрузка не получена'); }
$lines = array_map('rtrim', $lines);
sort($lines, SORT_STRING);
foreach ($lines as $line) { echo $line, "\n"; }
Ожидаемый результат
Кисть|0
Молоток|8
Перчатки|15

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.

Если требование изменится. copyToArray держит весь набор в памяти. Для большого экспорта выбирайте файловый/потоковый процесс; для фильтра и ORDER BY часто удобнее SELECT и построчная запись fputcsv. Не выдавайте путь назначения из ввода посетителя.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Экспортировать COPY text в локальный файл без массива всех строк.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$filenameПуть к файлу, который читает PHP-процесс, не серверный путь PostgreSQL.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

true/false. Ошибка открытия/записи файла проходит через ERRMODE. Успешное создание не проверяет чужой последующий импорт. Размер, права, место на диске, закрытые колонки и срок хранения — часть экспортной задачи; при отказе частичный файл не следует считать готовым.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. COPY передаёт строки драйверу
  2. PHP пишет export.part
  3. Только успешный результат переименовывается
  4. Получатель читает завершённый файл

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Нужны права записи каталога PHP. Создание файла и его выдача пользователю — разные шаги; для веб-выдачи сначала проверяют доступ к выгрузке.

Сохранить экспорт на стороне PHPПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen')");
$path = __DIR__ . '/export.tsv';
$db->copyToFile('export_items', $path);
echo rtrim(file_get_contents($path), "\r\n"), "\n";
Ожидаемый результат
1	Pen

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Соседний временный файл помогает не отдавать незавершённый результат под финальным именем. В рабочем каталоге нужны уникальные имена, политика существующего файла и учёт семантики rename ОС/файловой системы.

Переименовать завершённый экспортПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen')");
$temp = __DIR__ . '/export.part';
$ready = __DIR__ . '/export.tsv';
if (!$db->copyToFile('export_items', $temp)) { throw new RuntimeException('Экспорт не завершён'); }
if (!rename($temp, $ready)) { throw new RuntimeException('Не удалось опубликовать файл'); }
echo "Файл готов\n";
Ожидаемый результат
Файл готов

Рядом: Pdo\Pgsql::copyToArray(), Pdo\Pgsql::copyFromFile().

PDO::pgsqlCopyToFileЭкспортировать COPY text в локальный файл без массива всех строк. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlCopyToFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\N", ?string $fields = null): bool

Получить передаваемую выгрузку каталога. Экспортируется содержимое таблицы с выбранными полями. COPY не гарантирует желаемую сортировку строк; для точного учебного сравнения сортируем полученные строки в PHP.

Данные и действие: PDO::pgsqlCopyToFile
  1. $db->copyToFile(...)
  2. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.
  3. После выполнения: Кисть|0 · Молоток|8 · Перчатки|15

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
Получить передаваемую выгрузку каталогаПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$file = __DIR__ . '/catalog-export.txt';
$db->copyToFile('products', $file, '|', '\\N', 'name,stock');
$lines = file($file, FILE_IGNORE_NEW_LINES);
if ($lines === false) { throw new RuntimeException('Выгрузка не получена'); }
$lines = array_map('rtrim', $lines);
sort($lines, SORT_STRING);
foreach ($lines as $line) { echo $line, "\n"; }
Ожидаемый результат
Кисть|0
Молоток|8
Перчатки|15

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Полезный результат — три строки данных. В файловом варианте catalog-export.txt находится рядом с example.php; в массивном — строки находятся в $lines.

Если требование изменится. copyToArray держит весь набор в памяти. Для большого экспорта выбирайте файловый/потоковый процесс; для фильтра и ORDER BY часто удобнее SELECT и построчная запись fputcsv. Не выдавайте путь назначения из ввода посетителя.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Экспортировать COPY text в локальный файл без массива всех строк. Историческое имя.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$tableNameДоверенное имя таблицы/SQL-объекта COPY, не произвольный ввод пользователя.
$filenameПуть к файлу, который читает PHP-процесс, не серверный путь PostgreSQL.
$separatorРазделитель полей, обычно табуляция; ограничения COPY относятся и к нему.
$nullAsПредставление SQL NULL, обычно последовательность \N; не путать с пустой строкой.
$fieldsСтрока списка целевых колонок либо null для всех в порядке таблицы; задаётся программой.

true/false. Ошибка открытия/записи файла проходит через ERRMODE. Успешное создание не проверяет чужой последующий импорт. Размер, права, место на диске, закрытые колонки и срок хранения — часть экспортной задачи; при отказе частичный файл не следует считать готовым. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте copyToFile; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. COPY передаёт строки драйверу
  2. PHP пишет export.part
  3. Только успешный результат переименовывается
  4. Получатель читает завершённый файл

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Нужны права записи каталога PHP. Создание файла и его выдача пользователю — разные шаги; для веб-выдачи сначала проверяют доступ к выгрузке.

Сохранить экспорт на стороне PHPПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen')");
$path = __DIR__ . '/export.tsv';
$db->copyToFile('export_items', $path);
echo rtrim(file_get_contents($path), "\r\n"), "\n";
Ожидаемый результат
1	Pen

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Соседний временный файл помогает не отдавать незавершённый результат под финальным именем. В рабочем каталоге нужны уникальные имена, политика существующего файла и учёт семантики rename ОС/файловой системы.

Переименовать завершённый экспортПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('CREATE TEMP TABLE export_items (id integer, name text)');
$db->exec("INSERT INTO export_items VALUES (1, 'Pen')");
$temp = __DIR__ . '/export.part';
$ready = __DIR__ . '/export.tsv';
if (!$db->copyToFile('export_items', $temp)) { throw new RuntimeException('Экспорт не завершён'); }
if (!rename($temp, $ready)) { throw new RuntimeException('Не удалось опубликовать файл'); }
echo "Файл готов\n";
Ожидаемый результат
Файл готов

Рядом: Pdo\Pgsql::copyToFile(), Pdo\Pgsql::copyToArray(), Pdo\Pgsql::copyFromFile().

Pdo\Pgsql::escapeIdentifierЗаписать PostgreSQL-идентификатор с правильными кавычками и регистром.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::escapeIdentifier(string $input): string

Безопасно выбрать одну разрешённую колонку отчёта. Идентификатор — имя колонки, а не значение. Его нельзя заменить обычным маркером :name; сначала проверяем собственный разрешённый список, затем применяем правила цитирования PostgreSQL.

Данные и действие: Pdo\Pgsql::escapeIdentifier
  1. $db->escapeIdentifier($column)
  2. Разрешённое имя name становится синтаксически корректным идентификатором. Значения фильтра в реальном отчёте всё равно передаются отдельными параметрами.
  3. После выполнения: Молоток

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Безопасно выбрать одну разрешённую колонку отчётаПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$column = 'name';
if (!in_array($column, ['name', 'stock'], true)) { throw new InvalidArgumentException('Неизвестная колонка'); }
$quoted = $db->escapeIdentifier($column);
$statement = $db->query('SELECT ' . $quoted . ' FROM products WHERE id = 1');
echo $statement->fetchColumn(), "\n";
Ожидаемый результат
Молоток

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Разрешённое имя name становится синтаксически корректным идентификатором. Значения фильтра в реальном отчёте всё равно передаются отдельными параметрами.

Если требование изменится. Правильные кавычки не дают права читать секретную колонку. Разрешённый список отражает продуктовый контракт; quote предназначен для значений, а escapeIdentifier — для имён.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Записать PostgreSQL-идентификатор с правильными кавычками и регистром.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$inputОдна часть имени таблицы, столбца или функции, не значение и не произвольный SQL.

Возвращает цитированную строку. Это не проверка существования/разрешения объекта; список допустимых имён остаётся у приложения. Для строковых значений нужны параметры, не этот метод. Внутренние кавычки экранируются по синтаксису PostgreSQL.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Пользователь выбирает ключ name из списка
  2. Программа разрешает именно эту колонку
  3. escapeIdentifier создаёт "name"
  4. SQL получает идентификатор, значения остаются параметрами

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Allowlist определяет, какую колонку разрешено выбирать; escapeIdentifier обеспечивает SQL-запись имени. Эти задачи дополняют друг друга. Маркер :column не подставляет идентификатор.

Цитировать разрешённое имя колонкиПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$allowed = ['name', 'price'];
$column = 'name';
if (!in_array($column, $allowed, true)) { throw new InvalidArgumentException('Неизвестная колонка'); }
echo $db->escapeIdentifier($column), "\n";
Ожидаемый результат
"name"

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Цитирование reports.Order Export целиком создало бы одно имя с точкой внутри. Структуру квалифицированного идентификатора строит программа, отдельные части цитируются отдельно.

Раздельно цитировать схему и таблицуПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$schema = $db->escapeIdentifier('reports');
$table = $db->escapeIdentifier('Order Export');
echo $schema . '.' . $table, "\n";
Ожидаемый результат
"reports"."Order Export"

Рядом: PDO::prepare(), PDO::quote().

Pdo\Pgsql::getNotifyПолучить ожидающее асинхронное уведомление PostgreSQL.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::getNotify(int $fetchMode = PDO::FETCH_DEFAULT, int $timeoutMilliseconds = 0): array|false

Получить сигнал об изменении каталога. LISTEN подписывает соединение на канал, NOTIFY отправляет короткий сигнал. getNotify получает уведомление; данные товара потом читают отдельным SELECT.

Данные и действие: Pdo\Pgsql::getNotify
  1. $db->getNotify(PDO::FETCH_ASSOC, 1000)
  2. Для самостоятельной проверки одно соединение получает собственный сигнал; в сервисе писатель и слушатель обычно разные процессы.1000 — предел ожидания в миллисекундах.
  3. После выполнения: Изменился товар #1 · Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Получить сигнал об изменении каталогаПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$db->exec('LISTEN catalog_changed');
$statement = $db->prepare("SELECT pg_notify('catalog_changed', :payload)");
$statement->execute(['payload'=>'1']);
$statement->closeCursor();
$notice = $db->getNotify(PDO::FETCH_ASSOC, 1000);
if ($notice === false) { throw new RuntimeException('За время ожидания сигнал не пришёл'); }
echo 'Изменился товар #', $notice['payload'], "\n";
$statement = $db->prepare('SELECT name, stock FROM products WHERE id = :id');
$statement->execute(['id'=>$notice['payload']]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
$db->exec('UNLISTEN catalog_changed');
Ожидаемый результат
Изменился товар #1
Молоток — 8 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Для самостоятельной проверки одно соединение получает собственный сигнал; в сервисе писатель и слушатель обычно разные процессы.1000 — предел ожидания в миллисекундах.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. LISTEN/NOTIFY не является долговечной очередью. После обрыва соединения сигнал можно потерять; храните фактические изменения в базе и умейте перечитать состояние. Полезная нагрузка требует проверки, как любой внешний ввод.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить ожидающее асинхронное уведомление PostgreSQL.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$fetchModeDEFAULT/BOTH/ASSOC/NUM; другие режимы ValueError.
$timeoutMillisecondsМиллисекунды ожидания, 0 без ожидания; отрицательное ValueError, выше signed32-bit вызывает warning и ограничение максимумом.

Массив одной нотификации либо false, когда нет. ASSOC содержит message (имя канала), pid отправляющего серверного процесса, payload при непустой нагрузке; NUM использует 0/1/2. Проверяйте ?? для необязательного payload. Долгое ожидание лучше отдельному worker, а не каждому HTTP-ответу.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. LISTEN подписывает соединение
  2. Другой участник NOTIFY передаёт канал и 42
  3. getNotify читает одну нотификацию
  4. Приложение перечитывает заказ 42

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. LISTEN регистрирует соединение на канале. timeout 0 не заставляет веб-запрос ждать. Уведомление не появляется только потому, что изменилась таблица: другая сторона должна выполнить NOTIFY/pg_notify.

Проверить уведомление без ожиданияПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('LISTEN order_events');
$notice = $db->getNotify(PDO::FETCH_ASSOC, 0);
echo $notice === false ? "Пока нет события\n" : $notice['message'] . "\n";
Ожидаемый результат
При отсутствии новых уведомлений: Пока нет события

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Учебное соединение уведомляет собственный канал. У транзакционных LISTEN/NOTIFY момент доставки связан с commit; для рабочих событий сигнал используют как повод перечитать данные. LISTEN/NOTIFY не заменяет надёжную очередь с подтверждением и хранением.

Передать короткий сигнал и прочитать егоПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('LISTEN order_events');
$db->query("SELECT pg_notify('order_events', '42')")->closeCursor();
$notice = $db->getNotify(PDO::FETCH_ASSOC, 1000);
if ($notice !== false) { echo $notice['message'], ':', ($notice['payload'] ?? ''), "\n"; }
Ожидаемый результат
order_events:42

Рядом: Pdo\Pgsql::getPid().

PDO::pgsqlGetNotifyПолучить ожидающее асинхронное уведомление PostgreSQL. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlGetNotify(int $fetchMode = PDO::FETCH_DEFAULT, int $timeoutMilliseconds = 0): array|false

Получить сигнал об изменении каталога. LISTEN подписывает соединение на канал, NOTIFY отправляет короткий сигнал. getNotify получает уведомление; данные товара потом читают отдельным SELECT.

Данные и действие: PDO::pgsqlGetNotify
  1. $db->getNotify(PDO::FETCH_ASSOC, 1000)
  2. Для самостоятельной проверки одно соединение получает собственный сигнал; в сервисе писатель и слушатель обычно разные процессы.1000 — предел ожидания в миллисекундах.
  3. После выполнения: Изменился товар #1 · Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Получить сигнал об изменении каталогаПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$db->exec('LISTEN catalog_changed');
$statement = $db->prepare("SELECT pg_notify('catalog_changed', :payload)");
$statement->execute(['payload'=>'1']);
$statement->closeCursor();
$notice = $db->getNotify(PDO::FETCH_ASSOC, 1000);
if ($notice === false) { throw new RuntimeException('За время ожидания сигнал не пришёл'); }
echo 'Изменился товар #', $notice['payload'], "\n";
$statement = $db->prepare('SELECT name, stock FROM products WHERE id = :id');
$statement->execute(['id'=>$notice['payload']]);
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
$db->exec('UNLISTEN catalog_changed');
Ожидаемый результат
Изменился товар #1
Молоток — 8 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Для самостоятельной проверки одно соединение получает собственный сигнал; в сервисе писатель и слушатель обычно разные процессы.1000 — предел ожидания в миллисекундах.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. LISTEN/NOTIFY не является долговечной очередью. После обрыва соединения сигнал можно потерять; храните фактические изменения в базе и умейте перечитать состояние. Полезная нагрузка требует проверки, как любой внешний ввод.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получить ожидающее асинхронное уведомление PostgreSQL. Историческое имя.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$fetchModeDEFAULT/BOTH/ASSOC/NUM; другие режимы ValueError.
$timeoutMillisecondsМиллисекунды ожидания, 0 без ожидания; отрицательное ValueError, выше signed32-bit вызывает warning и ограничение максимумом.

Массив одной нотификации либо false, когда нет. ASSOC содержит message (имя канала), pid отправляющего серверного процесса, payload при непустой нагрузке; NUM использует 0/1/2. Проверяйте ?? для необязательного payload. Долгое ожидание лучше отдельному worker, а не каждому HTTP-ответу. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте getNotify; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. LISTEN подписывает соединение
  2. Другой участник NOTIFY передаёт канал и 42
  3. getNotify читает одну нотификацию
  4. Приложение перечитывает заказ 42

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. LISTEN регистрирует соединение на канале. timeout 0 не заставляет веб-запрос ждать. Уведомление не появляется только потому, что изменилась таблица: другая сторона должна выполнить NOTIFY/pg_notify.

Проверить уведомление без ожиданияПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('LISTEN order_events');
$notice = $db->getNotify(PDO::FETCH_ASSOC, 0);
echo $notice === false ? "Пока нет события\n" : $notice['message'] . "\n";
Ожидаемый результат
При отсутствии новых уведомлений: Пока нет события

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Учебное соединение уведомляет собственный канал. У транзакционных LISTEN/NOTIFY момент доставки связан с commit; для рабочих событий сигнал используют как повод перечитать данные. LISTEN/NOTIFY не заменяет надёжную очередь с подтверждением и хранением.

Передать короткий сигнал и прочитать егоПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->exec('LISTEN order_events');
$db->query("SELECT pg_notify('order_events', '42')")->closeCursor();
$notice = $db->getNotify(PDO::FETCH_ASSOC, 1000);
if ($notice !== false) { echo $notice['message'], ':', ($notice['payload'] ?? ''), "\n"; }
Ожидаемый результат
order_events:42

Рядом: Pdo\Pgsql::getNotify(), Pdo\Pgsql::getPid().

Pdo\Pgsql::getPidУзнать PID серверного процесса, обслуживающего соединение PostgreSQL.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::getPid(): int

Связать диагностическое сообщение с серверным соединением. Возвращается идентификатор backend-процесса PostgreSQL, обслуживающего это соединение. Это не ID товара и не PID PHP.

Данные и действие: Pdo\Pgsql::getPid
  1. $db->getPid()
  2. Сравнение с pg_backend_pid связывает PHP-объект с серверной сессией. В закрытом журнале можно записать фактический PID для поиска долгого запроса.
  3. После выполнения: Диагностика относится к текущему соединению каталога · Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Связать диагностическое сообщение с серверным соединениемПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$pid = $db->getPid();
$reported = (int) $db->query('SELECT pg_backend_pid()')->fetchColumn();
if ($pid !== $reported) { throw new RuntimeException('Неверная связь диагностического соединения'); }
echo "Диагностика относится к текущему соединению каталога\n";
$row = $db->query('SELECT name, stock FROM products WHERE id = 1')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Диагностика относится к текущему соединению каталога
Молоток — 8 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Сравнение с pg_backend_pid связывает PHP-объект с серверной сессией. В закрытом журнале можно записать фактический PID для поиска долгого запроса.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Число меняется между подключениями. Не используйте его как постоянный ключ пользователя и не завершайте чужие процессы по переданному посетителем PID.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Узнать PID серверного процесса, обслуживающего соединение PostgreSQL.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Целое число PID на машине сервера. Это диагностическая привязка текущего соединения, не PID PHP и не разрешение завершать процесс. Для журнала дополняют временем/идентификатором запроса.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. PHP соединён с сервером
  2. Backend имеет собственный PID
  3. getPid даёт номер
  4. DBA сопоставляет его с pg_stat_activity

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. PID относится к серверу PostgreSQL, не к PHP-процессу. Он помогает DBA найти сессию в pg_stat_activity при диагностике блокировок.

Связать журнал приложения с backend PostgreSQLПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$pid = $db->getPid();
echo 'backend=', $pid, "\n";
Ожидаемый результат
backend=<целочисленный PID процесса PostgreSQL>

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Оба пути показывают backend одного соединения. Не считайте PID вечным идентификатором задачи: после переподключения он может измениться и позднее переиспользоваться.

Сверить идентификатор с SQL-функцией PostgreSQLПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
var_dump($db->getPid() === (int) $db->query('SELECT pg_backend_pid()')->fetchColumn());
Ожидаемый результат
bool(true)

Рядом: Pdo\Pgsql::getNotify().

PDO::pgsqlGetPidУзнать PID серверного процесса, обслуживающего соединение PostgreSQL. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlGetPid(): int

Связать диагностическое сообщение с серверным соединением. Возвращается идентификатор backend-процесса PostgreSQL, обслуживающего это соединение. Это не ID товара и не PID PHP.

Данные и действие: PDO::pgsqlGetPid
  1. $db->getPid()
  2. Сравнение с pg_backend_pid связывает PHP-объект с серверной сессией. В закрытом журнале можно записать фактический PID для поиска долгого запроса.
  3. После выполнения: Диагностика относится к текущему соединению каталога · Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Связать диагностическое сообщение с серверным соединениемПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$pid = $db->getPid();
$reported = (int) $db->query('SELECT pg_backend_pid()')->fetchColumn();
if ($pid !== $reported) { throw new RuntimeException('Неверная связь диагностического соединения'); }
echo "Диагностика относится к текущему соединению каталога\n";
$row = $db->query('SELECT name, stock FROM products WHERE id = 1')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Диагностика относится к текущему соединению каталога
Молоток — 8 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Сравнение с pg_backend_pid связывает PHP-объект с серверной сессией. В закрытом журнале можно записать фактический PID для поиска долгого запроса.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Число меняется между подключениями. Не используйте его как постоянный ключ пользователя и не завершайте чужие процессы по переданному посетителем PID.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Узнать PID серверного процесса, обслуживающего соединение PostgreSQL. Историческое имя.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Целое число PID на машине сервера. Это диагностическая привязка текущего соединения, не PID PHP и не разрешение завершать процесс. Для журнала дополняют временем/идентификатором запроса. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте getPid; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. PHP соединён с сервером
  2. Backend имеет собственный PID
  3. getPid даёт номер
  4. DBA сопоставляет его с pg_stat_activity

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. PID относится к серверу PostgreSQL, не к PHP-процессу. Он помогает DBA найти сессию в pg_stat_activity при диагностике блокировок.

Связать журнал приложения с backend PostgreSQLПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$pid = $db->getPid();
echo 'backend=', $pid, "\n";
Ожидаемый результат
backend=<целочисленный PID процесса PostgreSQL>

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Оба пути показывают backend одного соединения. Не считайте PID вечным идентификатором задачи: после переподключения он может измениться и позднее переиспользоваться.

Сверить идентификатор с SQL-функцией PostgreSQLПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
var_dump($db->getPid() === (int) $db->query('SELECT pg_backend_pid()')->fetchColumn());
Ожидаемый результат
bool(true)

Рядом: Pdo\Pgsql::getPid(), Pdo\Pgsql::getNotify().

Pdo\Pgsql::lobCreateСоздать PostgreSQL large object и получить его OID.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::lobCreate(): string|false

Сохранить и прочитать отдельное вложение PostgreSQL. Large object имеет OID и отдельный срок жизни. Внутри транзакции создаём объект, открываем поток, пишем квитанцию и читаем её обратно; после учебного чтения удаляем именно свой OID.

Данные и действие: Pdo\Pgsql::lobCreate
  1. lobCreate → lobOpen → fwrite/fread → fclose → lobUnlink
  2. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.
  3. После выполнения: Квитанция заказа #1

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
try / catch / finallytry содержит действие, catch обрабатывает отказ, finally выполняет освобождение ресурсов и при успехе, и при исключении.
Сохранить и прочитать отдельное вложение PostgreSQLПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$db->beginTransaction();
try {
    $oid = $db->lobCreate();
    $stream = $db->lobOpen($oid, 'w');
    if ($stream === false) { throw new RuntimeException('Вложение не открыто'); }
    fwrite($stream, "Квитанция заказа #1\n");
    fclose($stream);
    $stream = $db->lobOpen($oid, 'r');
    if ($stream === false) { throw new RuntimeException('Вложение не прочитано'); }
    echo stream_get_contents($stream);
    fclose($stream);
    if (!$db->lobUnlink($oid)) { throw new RuntimeException('Учебное вложение не удалено'); }
    $db->commit();
} catch (Throwable $error) {
    if ($db->inTransaction()) { $db->rollBack(); }
    throw $error;
}
Ожидаемый результат
Квитанция заказа #1

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.

Если требование изменится. LOB API работает в транзакции; закрывайте потоки до её конца. В настоящем сервисе сохраните OID в записи с проверкой прав и удаляйте его по политике хранения. Обычная bytea-колонка проще для небольших вложений.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Создать PostgreSQL large object и получить его OID.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Строка OID либо false. Все операции large object требуют транзакции. Объект живёт отдельно от ссылающихся строк до lobUnlink; удаление последней ссылки без очистки оставляет мусор. В современной PostgreSQL есть владелец и ACL large objects; старую фразу PHP-страницы «no access controls» нельзя применять к текущему серверу. bytea часто проще: хранит значение в строке и обслуживает его жизненный цикл.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. lobCreate создаёт отдельный LOB
  2. OID — адресная ссылка, не содержимое
  3. lobOpen даёт поток
  4. commit подтверждает, rollback отменяет

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Создание, поточные операции и удаление находятся внутри транзакции. Учебный объект удаляется, чтобы пример не оставлял потерянные OID. В приложении OID сохраняют как ссылку, а жизненным циклом управляют явно.

Создать, записать и зафиксировать большой объектПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
try {
    $oid = $db->lobCreate();
    if ($oid === false) { throw new RuntimeException('LOB не создан'); }
    $stream = $db->lobOpen($oid, 'w');
    if ($stream === false) { throw new RuntimeException('LOB не открыт'); }
    fwrite($stream, 'Receipt 42');
    fclose($stream);
    $db->lobUnlink($oid);
    $db->commit();
    echo "Учебный LOB обработан и удалён\n";
} catch (Throwable $error) { if ($db->inTransaction()) { $db->rollBack(); } throw $error; }
Ожидаемый результат
Учебный LOB обработан и удалён

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Rollback отменяет создание в этой транзакции. Удаление строки со ссылкой на ранее подтверждённый OID само по себе не удаляет большой объект.

Отменить создание при отказе бизнес-действияПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
$oid = $db->lobCreate();
if ($oid === false) { throw new RuntimeException('Не создано'); }
$db->rollBack();
echo "Создание отменено\n";
Ожидаемый результат
Создание отменено

Рядом: Pdo\Pgsql::lobOpen(), Pdo\Pgsql::lobUnlink().

PDO::pgsqlLOBCreateСоздать PostgreSQL large object и получить его OID. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlLOBCreate(): string|false

Сохранить и прочитать отдельное вложение PostgreSQL. Large object имеет OID и отдельный срок жизни. Внутри транзакции создаём объект, открываем поток, пишем квитанцию и читаем её обратно; после учебного чтения удаляем именно свой OID.

Данные и действие: PDO::pgsqlLOBCreate
  1. lobCreate → lobOpen → fwrite/fread → fclose → lobUnlink
  2. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.
  3. После выполнения: Квитанция заказа #1

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
try / catch / finallytry содержит действие, catch обрабатывает отказ, finally выполняет освобождение ресурсов и при успехе, и при исключении.
Сохранить и прочитать отдельное вложение PostgreSQLПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$db->beginTransaction();
try {
    $oid = $db->lobCreate();
    $stream = $db->lobOpen($oid, 'w');
    if ($stream === false) { throw new RuntimeException('Вложение не открыто'); }
    fwrite($stream, "Квитанция заказа #1\n");
    fclose($stream);
    $stream = $db->lobOpen($oid, 'r');
    if ($stream === false) { throw new RuntimeException('Вложение не прочитано'); }
    echo stream_get_contents($stream);
    fclose($stream);
    if (!$db->lobUnlink($oid)) { throw new RuntimeException('Учебное вложение не удалено'); }
    $db->commit();
} catch (Throwable $error) {
    if ($db->inTransaction()) { $db->rollBack(); }
    throw $error;
}
Ожидаемый результат
Квитанция заказа #1

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.

Если требование изменится. LOB API работает в транзакции; закрывайте потоки до её конца. В настоящем сервисе сохраните OID в записи с проверкой прав и удаляйте его по политике хранения. Обычная bytea-колонка проще для небольших вложений.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Создать PostgreSQL large object и получить его OID. Историческое имя.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Строка OID либо false. Все операции large object требуют транзакции. Объект живёт отдельно от ссылающихся строк до lobUnlink; удаление последней ссылки без очистки оставляет мусор. В современной PostgreSQL есть владелец и ACL large objects; старую фразу PHP-страницы «no access controls» нельзя применять к текущему серверу. bytea часто проще: хранит значение в строке и обслуживает его жизненный цикл. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте lobCreate; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. lobCreate создаёт отдельный LOB
  2. OID — адресная ссылка, не содержимое
  3. lobOpen даёт поток
  4. commit подтверждает, rollback отменяет

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Создание, поточные операции и удаление находятся внутри транзакции. Учебный объект удаляется, чтобы пример не оставлял потерянные OID. В приложении OID сохраняют как ссылку, а жизненным циклом управляют явно.

Создать, записать и зафиксировать большой объектПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
try {
    $oid = $db->lobCreate();
    if ($oid === false) { throw new RuntimeException('LOB не создан'); }
    $stream = $db->lobOpen($oid, 'w');
    if ($stream === false) { throw new RuntimeException('LOB не открыт'); }
    fwrite($stream, 'Receipt 42');
    fclose($stream);
    $db->lobUnlink($oid);
    $db->commit();
    echo "Учебный LOB обработан и удалён\n";
} catch (Throwable $error) { if ($db->inTransaction()) { $db->rollBack(); } throw $error; }
Ожидаемый результат
Учебный LOB обработан и удалён

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Rollback отменяет создание в этой транзакции. Удаление строки со ссылкой на ранее подтверждённый OID само по себе не удаляет большой объект.

Отменить создание при отказе бизнес-действияПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
$oid = $db->lobCreate();
if ($oid === false) { throw new RuntimeException('Не создано'); }
$db->rollBack();
echo "Создание отменено\n";
Ожидаемый результат
Создание отменено

Рядом: Pdo\Pgsql::lobCreate(), Pdo\Pgsql::lobOpen(), Pdo\Pgsql::lobUnlink().

Pdo\Pgsql::lobOpenОткрыть поток к существующему large object PostgreSQL.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::lobOpen(string $oid, string $mode = "rb"): resource|false

Сохранить и прочитать отдельное вложение PostgreSQL. Large object имеет OID и отдельный срок жизни. Внутри транзакции создаём объект, открываем поток, пишем квитанцию и читаем её обратно; после учебного чтения удаляем именно свой OID.

Данные и действие: Pdo\Pgsql::lobOpen
  1. lobCreate → lobOpen → fwrite/fread → fclose → lobUnlink
  2. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.
  3. После выполнения: Квитанция заказа #1

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
try / catch / finallytry содержит действие, catch обрабатывает отказ, finally выполняет освобождение ресурсов и при успехе, и при исключении.
Сохранить и прочитать отдельное вложение PostgreSQLПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$db->beginTransaction();
try {
    $oid = $db->lobCreate();
    $stream = $db->lobOpen($oid, 'w');
    if ($stream === false) { throw new RuntimeException('Вложение не открыто'); }
    fwrite($stream, "Квитанция заказа #1\n");
    fclose($stream);
    $stream = $db->lobOpen($oid, 'r');
    if ($stream === false) { throw new RuntimeException('Вложение не прочитано'); }
    echo stream_get_contents($stream);
    fclose($stream);
    if (!$db->lobUnlink($oid)) { throw new RuntimeException('Учебное вложение не удалено'); }
    $db->commit();
} catch (Throwable $error) {
    if ($db->inTransaction()) { $db->rollBack(); }
    throw $error;
}
Ожидаемый результат
Квитанция заказа #1

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.

Если требование изменится. LOB API работает в транзакции; закрывайте потоки до её конца. В настоящем сервисе сохраните OID в записи с проверкой прав и удаляйте его по политике хранения. Обычная bytea-колонка проще для небольших вложений.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Открыть поток к существующему large object PostgreSQL.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$oidСтроковый OID ранее созданного объекта.
$modeЕсли есть w или +, чтение/запись; иначе только чтение. b не меняет поведение, default rb.

Resource потока или false. Открытие и все операции только внутри транзакции; fclose до её завершения. Это иной механизм, чем bytea: столбцы bytea PDO_PGSQL тоже может отдавать потоками, но они не являются отдельными OID large objects. Проверяйте доступ и каждую запись/чтение в производственном импорте.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. OID указывает на LOB ABCDE
  2. lobOpen создаёт поток
  3. fseek(2) ставит позицию перед C
  4. fread(2) возвращает CD

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. rb открывает чтение; stream-функции работают с объектом на сервере, а не локальным файлом. Поток закрывают внутри транзакции, которая дала ему действительность.

Прочитать созданный объект частямиПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
$oid = $db->lobCreate();
$write = $db->lobOpen($oid, 'w');
fwrite($write, 'Receipt 42');
fclose($write);
$read = $db->lobOpen($oid, 'rb');
echo fread($read, 7), "\n";
fclose($read);
$db->lobUnlink($oid);
$db->commit();
Ожидаемый результат
Receipt

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Режим с w или + у PDO_PGSQL означает чтение и запись; это не обещание обычной файловой truncate-семантики. Позиция измеряется байтами. Для текста UTF-8 произвольное смещение может попасть внутрь символа.

Перейти к нужному месту в потокеПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
$oid = $db->lobCreate();
$stream = $db->lobOpen($oid, 'w+');
fwrite($stream, 'ABCDE');
fseek($stream, 2);
echo fread($stream, 2), "\n";
fclose($stream);
$db->lobUnlink($oid);
$db->commit();
Ожидаемый результат
CD

Рядом: Pdo\Pgsql::lobCreate(), Pdo\Pgsql::lobUnlink().

PDO::pgsqlLOBOpenОткрыть поток к существующему large object PostgreSQL. Историческое имя.

PHP 5.1+; старое имя deprecated с PHP 8.5 · PDO; соответствующий драйвер

PDO::pgsqlLOBOpen(string $oid, string $mode = "rb"): resource|false

Сохранить и прочитать отдельное вложение PostgreSQL. Large object имеет OID и отдельный срок жизни. Внутри транзакции создаём объект, открываем поток, пишем квитанцию и читаем её обратно; после учебного чтения удаляем именно свой OID.

Данные и действие: PDO::pgsqlLOBOpen
  1. lobCreate → lobOpen → fwrite/fread → fclose → lobUnlink
  2. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.
  3. После выполнения: Квитанция заказа #1

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
try / catch / finallytry содержит действие, catch обрабатывает отказ, finally выполняет освобождение ресурсов и при успехе, и при исключении.
Сохранить и прочитать отдельное вложение PostgreSQLПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$db->beginTransaction();
try {
    $oid = $db->lobCreate();
    $stream = $db->lobOpen($oid, 'w');
    if ($stream === false) { throw new RuntimeException('Вложение не открыто'); }
    fwrite($stream, "Квитанция заказа #1\n");
    fclose($stream);
    $stream = $db->lobOpen($oid, 'r');
    if ($stream === false) { throw new RuntimeException('Вложение не прочитано'); }
    echo stream_get_contents($stream);
    fclose($stream);
    if (!$db->lobUnlink($oid)) { throw new RuntimeException('Учебное вложение не удалено'); }
    $db->commit();
} catch (Throwable $error) {
    if ($db->inTransaction()) { $db->rollBack(); }
    throw $error;
}
Ожидаемый результат
Квитанция заказа #1

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Возвращаемый OID используется для открытия того же объекта. Пользователь получает содержимое квитанции; числаOID или bool сами по себе не показывали бы, что записано.

Если требование изменится. LOB API работает в транзакции; закрывайте потоки до её конца. В настоящем сервисе сохраните OID в записи с проверкой прав и удаляйте его по политике хранения. Обычная bytea-колонка проще для небольших вложений.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Открыть поток к существующему large object PostgreSQL. Историческое имя.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$oidСтроковый OID ранее созданного объекта.
$modeЕсли есть w или +, чтение/запись; иначе только чтение. b не меняет поведение, default rb.

Resource потока или false. Открытие и все операции только внутри транзакции; fclose до её завершения. Это иной механизм, чем bytea: столбцы bytea PDO_PGSQL тоже может отдавать потоками, но они не являются отдельными OID large objects. Проверяйте доступ и каждую запись/чтение в производственном импорте. С PHP 8.5 старый метод deprecated. Для миграции создайте Pdo\Pgsql (или PDO::connect) и используйте lobOpen; два примера показывают этот целевой API. Простой new PDO по-прежнему создаёт базовый класс.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. OID указывает на LOB ABCDE
  2. lobOpen создаёт поток
  3. fseek(2) ставит позицию перед C
  4. fread(2) возвращает CD

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. rb открывает чтение; stream-функции работают с объектом на сервере, а не локальным файлом. Поток закрывают внутри транзакции, которая дала ему действительность.

Прочитать созданный объект частямиПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
$oid = $db->lobCreate();
$write = $db->lobOpen($oid, 'w');
fwrite($write, 'Receipt 42');
fclose($write);
$read = $db->lobOpen($oid, 'rb');
echo fread($read, 7), "\n";
fclose($read);
$db->lobUnlink($oid);
$db->commit();
Ожидаемый результат
Receipt

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Режим с w или + у PDO_PGSQL означает чтение и запись; это не обещание обычной файловой truncate-семантики. Позиция измеряется байтами. Для текста UTF-8 произвольное смещение может попасть внутрь символа.

Перейти к нужному месту в потокеПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
$oid = $db->lobCreate();
$stream = $db->lobOpen($oid, 'w+');
fwrite($stream, 'ABCDE');
fseek($stream, 2);
echo fread($stream, 2), "\n";
fclose($stream);
$db->lobUnlink($oid);
$db->commit();
Ожидаемый результат
CD

Рядом: Pdo\Pgsql::lobOpen(), Pdo\Pgsql::lobCreate(), Pdo\Pgsql::lobUnlink().

Pdo\Pgsql::setNoticeCallbackПолучать серверные NOTICE/WARNING PostgreSQL в своём обработчике.

PHP 8.4+; отдельные изменения отмечены · PDO; соответствующий драйвер

Pdo\Pgsql::setNoticeCallback(?callable $callback): void

Отдельно обработать информационное сообщение сервера. NOTICE — серверное уведомление о ходе операции, не исключение SQL и не LISTEN/NOTIFY. Callback вызывается при поступлении сообщения.

Данные и действие: Pdo\Pgsql::setNoticeCallback
  1. $db->setNoticeCallback($handler)
  2. use (&$messages) даёт callback доступ к той же переменной массива. Мы отделяем информационный канал от строки товара и затем снимаем обработчик.
  3. После выполнения: Сервер сообщил о завершении проверки каталога · Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
function (...) { ... }Объявляет функцию; тело выполняется при её вызове, не при объявлении. Кто и с какими данными её вызывает, показано в текущем примере. return передаёт значение обратно в место вызова.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Отдельно обработать информационное сообщение сервераПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$messages = [];
$db->setNoticeCallback(function (string $message) use (&$messages) { $messages[] = $message; });
$db->exec('SET client_min_messages TO NOTICE');
$db->exec("DO $$ BEGIN RAISE NOTICE 'catalog checked'; END; $$");
$db->setNoticeCallback(null);
if ($messages === []) { throw new RuntimeException('Сообщение не получено'); }
echo "Сервер сообщил о завершении проверки каталога\n";
$row = $db->query('SELECT name, stock FROM products WHERE id = 1')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Сервер сообщил о завершении проверки каталога
Молоток — 8 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. use (&$messages) даёт callback доступ к той же переменной массива. Мы отделяем информационный канал от строки товара и затем снимаем обработчик.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Не печатайте серверные сообщения прямо в HTTP-ответ: они могут нарушить JSON/HTML и раскрыть внутренние детали. Callback не подтверждает фиксацию бизнес-транзакции.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Получать серверные NOTICE/WARNING PostgreSQL в своём обработчике.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$callbackfunction(string $message): void либо null для возврата стандартного обработчика.

Возврата нет. На получение влияет client_min_messages; NOTICE не равно исключению неудавшегося запроса. Callback держите коротким и не публикуйте сырые сообщения посетителю. Его задача — обработать сообщение, не перезапускать текущий SQL на том же соединении.

При неудаче SQL-операции режим ERRMODE_SILENT оставляет false и диагностику, ERRMODE_WARNING добавляет E_WARNING, ERRMODE_EXCEPTION выбрасывает PDOException (стандарт с PHP 8.0). Ошибки аргументов и отдельные ошибки состояния могут возникать независимо от этого режима. В примерах режим задан явно; сообщение драйвера не выводится посетителю.

Путь данных
  1. Сервер RAISE NOTICE генерирует текст
  2. client_min_messages решает доставку
  3. Callback получает строку
  4. Приложение сохраняет разрешённую диагностику

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Серверная настройка client_min_messages влияет на доставку. Callback не обязан печатать всё в HTTP-ответ; сообщения могут содержать значения из SQL.

Собрать сообщения NOTICE без смешивания с ответомПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$messages = [];
$db->setNoticeCallback(function (string $message) use (&$messages): void { $messages[] = trim($message); });
$db->exec("SET client_min_messages TO NOTICE");
$db->exec("DO $$ BEGIN RAISE NOTICE 'Import completed'; END; $$");
echo count($messages) > 0 ? "Сообщение получено\n" : "Нет сообщения\n";
Ожидаемый результат
Сообщение получено

Как читать этот вариант. Контекстный пример: требуется PostgreSQL, pdo_pgsql и доверенные PG_DSN/PG_USER/PG_PASSWORD. Здесь проверен синтаксис PHP, запрос к серверу не выполнялся. Это особенно полезно у долгоживущего worker: замыкание может удерживать массивы и состояние прошлого задания. null восстанавливает обработку по умолчанию, а не меняет ERRMODE SQL-ошибок.

Не оставлять обработчик с устаревшим контекстомПример для указанного окружения
<?php
$db = new Pdo\Pgsql(getenv('PG_DSN'), getenv('PG_USER'), getenv('PG_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$messages = [];
$db->setNoticeCallback(function (string $message) use (&$messages): void { $messages[] = $message; });
try { $db->query('SELECT 1')->closeCursor(); }
finally { $db->setNoticeCallback(null); }
echo "Обработчик восстановлен\n";
Ожидаемый результат
Обработчик восстановлен

Рядом: PDO::errorInfo().

Pdo\Mysql::getWarningCountУзнать, оставил ли последний MySQL-запрос предупреждения.

PHP 8.4+ · PDO; соответствующий драйвер

Pdo\Mysql::getWarningCount(): int

Не принять преобразованное сервером значение за правильный ввод. SQL может выполниться, но сообщить предупреждение о преобразовании. getWarningCount относится к последней серверной команде; читайте его до следующего запроса.

Данные и действие: Pdo\Mysql::getWarningCount
  1. $db->getWarningCount()
  2. Неверное значение демонстрационно преобразуется только в SELECT; UPDATE не выполняется. Правильный остаток Молотка остаётся8.
  3. После выполнения: Остаток 12x не принят: серверу пришлось преобразовать значение · Молоток — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Не принять преобразованное сервером значение за правильный вводПример для указанного окружения
<?php
require __DIR__ . '/catalog.php';
$statement = $db->query("SELECT CAST('12x' AS UNSIGNED)");
$value = $statement->fetchColumn();
$statement->closeCursor();
if ($db->getWarningCount() > 0) {
    echo "Остаток 12x не принят: серверу пришлось преобразовать значение\n";
}
$row = $db->query('SELECT name, stock FROM products WHERE id = 1')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Остаток 12x не принят: серверу пришлось преобразовать значение
Молоток — 8 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Неверное значение демонстрационно преобразуется только в SELECT; UPDATE не выполняется. Правильный остаток Молотка остаётся8.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Молоток8 шт.

Если требование изменится. Требуется PHP8.4+ и pdo_mysql. SQL-режимы и сервер меняют поведение отдельных преобразований; проверяйте вход до SQL, а предупреждения используйте как дополнительную диагностику.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Узнать, оставил ли последний MySQL-запрос предупреждения.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет.

Целое количество предупреждений последнего запроса. Для подробностей SHOW WARNINGS [LIMIT n]. Это не errorCode и не число затронутых строк. Предупреждения зависят от версии/SQL mode: в другом режиме некорректное значение может стать ошибкой. Читать сразу после нужной команды.

Путь данных
  1. SELECT выполнен сервером
  2. Сервер создал предупреждение
  3. getWarningCount даёт число
  4. SHOW WARNINGS при необходимости читает детали

Как читать этот вариант. Контекст MySQL и его SQL mode; выполнен только lint. SQL может вернуть NULL с предупреждением, не бросив PDOException. Количество надо читать до следующей команды, меняющей состояние.

Отличить предупреждение сервера от отказа PHPПример для указанного окружения
<?php
$db = new Pdo\Mysql(getenv('MYSQL_DSN'), getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'));
$db->query('SELECT 42 / 0')->closeCursor();
$count = $db->getWarningCount();
echo 'warnings=', $count, "\n";
Ожидаемый результат
При серверном SQL-режиме, выдающем предупреждение деления на 0: warnings=1

Как читать этот вариант. SHOW WARNINGS получает текст/код отдельно от getWarningCount. Не вставляйте сырые серверные сообщения в страницу посетителя. Сервера MySQL для выполнения не использовано.

После проверки прочитать сообщения SHOW WARNINGSПример для указанного окружения
<?php
$db = new Pdo\Mysql(getenv('MYSQL_DSN'), getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'));
$db->query('SELECT 42 / 0')->closeCursor();
if ($db->getWarningCount() > 0) {
    $warnings = $db->query('SHOW WARNINGS LIMIT 10')->fetchAll(PDO::FETCH_ASSOC);
    foreach ($warnings as $warning) { echo $warning['Level'], ':', $warning['Code'], "\n"; }
}
Ожидаемый результат
При предупреждении деления на ноль: Warning:1365

Рядом: PDO::errorInfo().

Pdo\Firebird::getApiVersionУзнать версию Firebird API, на которой собран PDO-драйвер.

PHP 8.4+ · PDO; соответствующий драйвер

Pdo\Firebird::getApiVersion(): int

Проверить клиентскую возможность без подключения к серверу. Статический метод возвращает FB_API_VER заголовков клиента, с которыми собран драйвер. Это не версия удалённого Firebird и не проверка доступности базы.

Данные и действие: Pdo\Firebird::getApiVersion
  1. Pdo\Firebird::getApiVersion()
  2. У диагностического инструмента полезный результат — точное объяснение недостающей зависимости. Фиксированное числоAPI не придумывается: оно зависит от установленного бинарника.
  3. После выполнения: При отсутствии pdo_firebird: Отчёт Firebird недоступен: включите pdo_firebird · При наличии: фактическое целое значение клиентского API, затем предложение проверить соединение.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
Проверить клиентскую возможность без подключения к серверуПример для указанного окружения
<?php
if (!class_exists(Pdo\Firebird::class)) {
    exit("Отчёт Firebird недоступен: включите pdo_firebird\n");
}
$api = Pdo\Firebird::getApiVersion();
echo 'Версия клиентского API для диагностики: ', $api, "\n";
echo "Теперь отдельно проверьте соединение и запрос отчёта.\n";
Ожидаемый результат
При отсутствии pdo_firebird: Отчёт Firebird недоступен: включите pdo_firebird
При наличии: фактическое целое значение клиентского API, затем предложение проверить соединение.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. У диагностического инструмента полезный результат — точное объяснение недостающей зависимости. Фиксированное числоAPI не придумывается: оно зависит от установленного бинарника.

Если требование изменится. Метод доступен с PHP8.4. Для запроса нужны сервер, существующая база, права и DSN: полный раздел драйвера сохранён ниже. Диагностическая версия не заменяет получение строки из базы.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

Узнать версию Firebird API, на которой собран PDO-драйвер.

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
АргументыНет; статический вызов без new.

Целое значение C-константы FB_API_VER из ibase.h. Нельзя интерпретировать как версию подключённого сервера: соединение вообще не создаётся. Расширение должно быть доступно текущему PHP.

Путь данных
  1. Сборка драйвера знает FB_API_VER
  2. Статический метод читает это число
  3. Диагностика сравнивает окружения
  4. Сеть и SQL для этого не требуются

Как читать этот вариант. Статический метод не требует соединения. Это версия API сборки клиента, не версия сервера и не строка релиза Firebird. Проверен синтаксис; pdo_firebird здесь не загружался.

Получить версию клиентского Firebird APIПример для указанного окружения
<?php
echo Pdo\Firebird::getApiVersion(), "\n";
Ожидаемый результат
Целое FB_API_VER из клиентских заголовков, с которыми собран драйвер.

Как читать этот вариант. Такая запись помогает сравнить два сервера приложения при несовместимости клиента. Номер версии БД отдельно читают через соединение и поддерживаемый ATTR_SERVER_VERSION. Только lint.

Добавить API-версию в диагностику окруженияПример для указанного окружения
<?php
$details = ['driver' => 'pdo_firebird', 'api' => Pdo\Firebird::getApiVersion()];
echo json_encode($details, JSON_THROW_ON_ERROR), "\n";
Ожидаемый результат
{"driver":"pdo_firebird","api":<целое значение API>}

Рядом: PDO::getAvailableDrivers().

PDO::cubrid_schemaПолучить метаданные схемы CUBRID: ключи, колонки, связи и права.

PECL PDO_CUBRID 8.3.0.0001+ · PDO; соответствующий драйвер

PDO::cubrid_schema(int $schema_type, string $table_name = ?, string $col_name = ?): array|false

Сопоставить первичный ключ со строкой учебного товара. Метод возвращает описание схемы CUBRID, а не строки товаров. Полный SQL создания таблицы и начальная строка находятся в schema.sql архива.

Данные и действие: PDO::cubrid_schema
  1. $db->cubrid_schema(PDO::CUBRID_SCH_PRIMARY_KEY, 'course_products')
  2. Сначала инструмент миграции узнаёт, что ключ — id, затем обычный SELECT читает строку по этому ключу. Регистр имён метаданных зависит от объявленной схемы/драйвера.
  3. После выполнения: Колонка ключа: id · Hammer — 8 шт.

В этом самостоятельном примере подготовка указана непосредственно в коде и дополнительных файлах архива. Запуск: php example.php; требования и внешние зависимости отмечены перед кодом.

Запись в этом примереКак читать
require __DIR__ . ...Выполняет указанный PHP-файл из папки примера. Точка склеивает путь. Файл включён в архив; он создаёт соединение и исходные данные.
$db->method(...)Стрелка вызывает действие у конкретного соединения, команды или результата. Скобки содержат входные значения; результат можно сохранить через =.
Класс::ИМЯДвойное двоеточие обращается к константе режима либо статическому методу класса; это не выбор колонки SQL.
foreach ($rows as $row)Берёт по одной строке из набора. Блок между { и } повторяется для каждой строки; при пустом наборе не выполняется.
[...]Квадратные скобки задают массив либо читают его элемент. Ключ имени колонки и номер позиции — разные способы адресации.
Сопоставить первичный ключ со строкой учебного товараПример для указанного окружения
<?php
$config = require __DIR__ . '/config.php';
$db = new PDO($config['dsn'], $config['user'], $config['password'], [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$keys = $db->cubrid_schema(PDO::CUBRID_SCH_PRIMARY_KEY, 'course_products');
if ($keys === false) { throw new RuntimeException('Описание ключа недоступно'); }
foreach ($keys as $key) { echo 'Колонка ключа: ', $key['ATTR_NAME'], "\n"; }
$row = $db->query('SELECT name, stock FROM course_products WHERE id = 1')->fetch(PDO::FETCH_ASSOC);
echo $row['name'], ' — ', $row['stock'], " шт.\n";
Ожидаемый результат
Колонка ключа: id
Hammer — 8 шт.

Требуется указанное окружение; локально проверен PHP-синтаксис, запрос к этому серверу не выполнялся. Сначала инструмент миграции узнаёт, что ключ — id, затем обычный SELECT читает строку по этому ключу. Регистр имён метаданных зависит от объявленной схемы/драйвера.

Эти же строки в табличном виде. CLI-пример выше печатает текст; таблица помогает увидеть соответствие названия и остатка. Как получить такую таблицу настоящим HTML-обработчиком.

Товар / строкаНаличие
Hammer8 шт.

Если требование изменится. Специальный PECL API не переносится автоматически на PDO MySQL/SQLite. Тип схемы определяет поля ответа; не обращайтесь к ATTR_NAME для произвольного другого вида metadata. Наличие PDO само по себе не устанавливает CUBRID.

Полный контракт, ограничения и следующие варианты. Ниже сохранены параметры, возвращаемые значения, ошибки, версии и дополнительные задачи этой операции. Перед каждым более длинным примером сначала прочитайте его подготовку и ход действий.

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

$db обозначает соединение, $statement — подготовленную команду и её текущий результат. -> вызывает метод конкретного объекта, :: — статический метод или константу класса. Круглые скобки содержат аргументы; результат справа от = сохраняется в переменной. Это отдельные шаги: выполнить SQL и прочитать полученные строки. Основы: объекты, аргументы и возврат.

АргументДоговор
$schema_typeОдна из CUBRID_SCH_*; полный список и формы результата — в разделе CUBRID.
$table_nameИмя нужной таблицы для запросов её описания.
$col_nameИмя колонки только для CUBRID_SCH_COL_PRIVILEGE.

Внешний массив — строки, каждая строка ассоциативный массив полей выбранной схемы; false при отказе. Точная форма зависит от schema_type, поэтому нельзя читать ATTR_NAME из результата SCH_TABLE. Официальная сигнатура историческая, ? обозначает необязательный параметр без документированного конкретного default, а не символ для копирования в объявление PHP.

Путь данных
  1. SCH_IMPORTED_KEYS выбирает вид метаданных
  2. order_lines задаёт таблицу
  3. Драйвер возвращает массив внешних ключей
  4. PHP выводит связь order_id → orders.id

Как читать этот вариант. Требуются PDO_CUBRID и таблица orders. Это чтение метаданных, не данных заказов. Порядок массива не заменяет KEY_SEQ; при составном ключе ориентируются на указанную последовательность. Только lint.

Посмотреть состав первичного ключа таблицыПример для указанного окружения
<?php
$db = new PDO(getenv('CUBRID_DSN'), getenv('CUBRID_USER'), getenv('CUBRID_PASSWORD'));
$keys = $db->cubrid_schema(PDO::CUBRID_SCH_PRIMARY_KEY, 'orders');
if ($keys === false) { throw new RuntimeException('Схема недоступна'); }
foreach ($keys as $key) { echo $key['ATTR_NAME'], ':', $key['KEY_SEQ'], "\n"; }
Ожидаемый результат
По строке на колонку первичного ключа orders: имя и позиция с 1.

Как читать этот вариант. Пример полезен генератору документации схемы. Не следует автоматически удалять/менять таблицы на основе найденных связей. Реальный сервер CUBRID не использован.

Узнать, какие колонки участвуют во внешних ключахПример для указанного окружения
<?php
$db = new PDO(getenv('CUBRID_DSN'), getenv('CUBRID_USER'), getenv('CUBRID_PASSWORD'));
$keys = $db->cubrid_schema(PDO::CUBRID_SCH_IMPORTED_KEYS, 'order_lines');
if ($keys === false) { throw new RuntimeException('Схема недоступна'); }
foreach ($keys as $key) { echo $key['FKCOLUMN_NAME'], ' -> ', $key['PKTABLE_NAME'], '.', $key['PKCOLUMN_NAME'], "\n"; }
Ожидаемый результат
Для согласованной учебной схемы: order_id -> orders.id

Рядом: PDOStatement::getColumnMeta().

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.