Pg free result: примеры (PHP)

Освобождение памяти результата запроса в PHP: функция pg_free_result
Раздел: Базы данных (PostgreSQL)
pg_free_result(PgSql\Result $result): bool

Функция pg_free_result() в PHP освобождает память, занятую ресурсом результата запроса к базе данных PostgreSQL. Использование функции необходимо при работе с большими результатами запросов для предотвращения утечек памяти.

Назначение и применение

Функция вызывается после обработки данных, полученных с помощью pg_query() или подобных функций. Явное освобождение ресурсов особенно полезно в скриптах, выполняющих множество запросов или обрабатывающих большие объемы информации.

Аргументы функции

Функция принимает один обязательный параметр:

  • $result (ресурс PostgreSQL) - дескриптор результата запроса, возвращаемый функциями pg_query(), pg_query_params() или pg_execute().

Возвращаемое значение — логическое true после успешного выполнения или false в случае ошибки.

Примеры использования

Функция имеет простой синтаксис и вызывается после завершения работы с данными результата запроса.

Освобождение результата простого запроса

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

$connection = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($connection, "SELECT id, name FROM users");

// Обработка результата
while ($row = pg_fetch_assoc($result)) {
    echo $row['id'] . ': ' . $row['name'] . "\n";
}

// Освобождение памяти
$freed = pg_free_result($result);
echo 'Ресурс освобожден: ' . ($freed ? 'да' : 'нет');
1: Иван Петров
2: Мария Сидорова
Ресурс освобожден: да
Освобождение ресурса с проверкой

Проверка типа аргумента перед вызовом функции.

$result = pg_query($connection, "SELECT NOW()");

if (is_resource($result) || $result instanceof PgSql\Result) {
    pg_free_result($result);
    echo 'Память результата запроса освобождена.';
} else {
    echo 'Неверный ресурс результата.';
}
Память результата запроса освобождена.
Похожие функции в PHP

В PHP отсутствуют прямые аналоги pg_free_result() для расширения PostgreSQL. Однако освобождение памяти происходит автоматически при завершении скрипта или при присвоении переменной нового значения.

  • unset($result) - уничтожает переменную, но не всегда немедленно освобождает память, занятую ресурсом. Явный вызов pg_free_result() более предсказуем.
  • Для MySQLi существует функция mysqli_free_result(), выполняющая аналогичную роль для результатов MySQL.

Использование pg_free_result() предпочтительно в длительных скриптах, например, в демонах или при обработке большого количества данных, где контроль за памятью критически важен.

Аналоги в других языках и СУБД

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

Python (библиотека psycopg2)
import psycopg2
conn = psycopg2.connect("dbname=test user=postgres")
cur = conn.cursor()
cur.execute("SELECT * FROM users")
rows = cur.fetchall()  # Данные полностью загружены в память
cur.close()  # Курсор закрывается, ресурсы освобождаются
# Явной функции для освобождения только результата нет, управление памятью - за сборщиком мусора.
JavaScript (Node.js с библиотекой 'pg')
const { Client } = require('pg');
const client = new Client();
await client.connect();
const res = await client.query('SELECT * FROM users');
console.log(res.rows); // Данные в массиве rows
// Явного освобождения не требуется. Объект результата будет удален сборщиком мусора.
// Однако для больших результатов можно использовать потоковое чтение.
MySQL (SQL команда)

В самом MySQL нет прямой SQL-команды для освобождения памяти на стороне клиента. В CLI-клиенте или коннекторах (например, C API) существуют аналогичные функции (например, mysql_free_result()). В PHP для MySQLi это mysqli_free_result().

Отличие PHP функции в ее явности и направленности именно на управление памятью в рамках одного расширения (pgsql).

Типичные ошибки

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

Использование освобожденного ресурса
$result = pg_query($connection, "SELECT 1");
pg_free_result($result);
$row = pg_fetch_row($result); // Ошибка: ресурс результата недействителен
echo 'Эта строка не выполнится.';
Warning: pg_fetch_row(): supplied resource is not a valid PostgreSQL result resource in ...
Передача нересурсной переменной (в PHP 8+)
$not_a_result = null;
$freed = pg_free_result($not_a_result); // Вызовет TypeError в PHP 8
echo 'Результат: ' . $freed;
TypeError: pg_free_result(): Argument #1 ($result) must be of type PgSql\Result, null given
Двойное освобождение ресурса
$result = pg_query($connection, "SELECT 1");
pg_free_result($result); // Первый вызов - успешен
$freedAgain = pg_free_result($result); // Второй вызов вернет false
echo 'Второе освобождение: ' . ($freedAgain ? 'успешно' : 'неудачно');
Второе освобождение: неудачно
Изменения в версиях PHP

В PHP 8.0 API расширения PostgreSQL было модернизировано. Вместо ресурсов (resource) теперь используются объекты класса PgSql\Result. Функция pg_free_result() продолжает работать, но принимает и возвращает объект вместо ресурса.

  • До PHP 8.0: pg_free_result(resource $result): bool
  • Начиная с PHP 8.0: pg_free_result(PgSql\Result $result): bool

Это изменение повышает типобезопасность кода. Попытка передать неверный тип аргумента вызывает TypeError, а не предупреждение.

Расширенные примеры использования
Освобождение в цикле при множественных запросах

При последовательном выполнении множества запросов в цикле важно своевременно освобождать память.

Пример php
$queries = ["SELECT * FROM logs_202301", "SELECT * FROM logs_202302", "SELECT * FROM logs_202303"];
foreach ($queries as $query) {
    $result = pg_query($connection, $query);
    if (!$result) {
        continue;
    }
    // Какая-то минимальная обработка...
    $count = pg_num_rows($result);
    echo "Найдено записей: $count\n";
    // Освобождаем память перед следующей итерацией
    pg_free_result($result);
}
Найдено записей: 150
Найдено записей: 200
Найдено записей: 175
Освобождение результата после обработки курсора

При использовании курсоров PostgreSQL результат основной функции его создания также требует очистки.

Пример php
// Создание курсора
$result = pg_query($connection, "DECLARE my_cursor CURSOR FOR SELECT * FROM large_table");
// Результат создания курсора нужно освободить
pg_free_result($result);

// Далее работа с курсором через FETCH...
$fetchRes = pg_query($connection, "FETCH 100 FROM my_cursor");
// Обработка данных из fetchRes...
pg_free_result($fetchRes);

// Закрытие курсора
$closeRes = pg_query($connection, "CLOSE my_cursor");
pg_free_result($closeRes);
Использование в пользовательской функции-обертке

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

Пример php
function processAndFreeResult($connection, $query, callable $processor) {
    $result = pg_query($connection, $query);
    if (!$result) {
        return false;
    }
    try {
        // Вызов пользовательской функции обработки
        $processorResult = $processor($result);
        return $processorResult;
    } finally {
        // Гарантированное освобождение ресурса, даже если в коллбэке было исключение
        pg_free_result($result);
    }
}

// Пример вызова
$conn = pg_connect("...");
$data = processAndFreeResult($conn, "SELECT * FROM products", function ($res) {
    return pg_fetch_all($res);
});
print_r($data);
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Товар 1
        )
    ...
)
Проверка на необходимость освобождения (для кода, совместимого с PHP 7 и 8)
Пример php
function safePgFreeResult($result) {
    if ($result instanceof PgSql\Result || (is_resource($result) && get_resource_type($result) === 'pgsql result')) {
        return pg_free_result($result);
    }
    return false;
}

$res = pg_query($connection, "SELECT 1");
safePgFreeResult($res);
// Безопасно для PHP 7 и 8

PHP pg_free_result function comments

En
Pg free result Free result memory