Извлечение идентификатора ресурса потока в PHP

Раздел: Программирование на PHP -> Потоки PHP

Индекс потока (resource ID) в PHP

Основной способ получения числового идентификатора потока (resource ID) в PHP версии 8.0 и выше - функция get_resource_id(). Она принимает ресурс и возвращает его целочисленный индекс, который присваивается при открытии потока. Этот индекс уникален для каждого открытого ресурса в рамках запроса.


$file = fopen('example.txt', 'r');
$id = get_resource_id($file);
echo $id; // 5
5

Цель использования: отслеживание и логирование открытых потоков, отладка утечек ресурсов, групповые операции над множеством потоков.

Типичные ошибки: передача нересурсной переменной (например, false при ошибке fopen) вызывает TypeError. Решение - проверять тип перед вызовом:


$file = fopen('nonexistent.txt', 'r');
if (is_resource($file)) {
    echo get_resource_id($file);
} else {
    echo 'Файл не открыт';
}

Как получить индекс потока в более старых версиях PHP (до 8.0)?

В PHP 7 и ниже функция get_resource_id отсутствует. Вместо этого можно использовать приведение ресурса к целому числу: (int) $resource. Результат будет тем же числовым идентификатором.


$file = fopen('test.txt', 'r');
$id = (int) $file;
echo $id; // 5
5

Проблема

В PHP 8.0 и выше приведение ресурса к int вызывает ошибку E_DEPRECATED и в будущих версиях может быть удалено. Рекомендуется использовать get_resource_id() при наличии. Для обратной совместимости можно применять условный вызов:


$id = function_exists('get_resource_id') ? get_resource_id($file) : (int) $file;

Как увидеть индекс потока при отладке без написания кода?

Функции var_dump() и debug_zval_refs() выводят внутренний идентификатор ресурса в стандартном формате.


$stream = fopen('php://stdin', 'r');
var_dump($stream);
resource(5) of type (stream)

Число 5 - это и есть индекс потока. Однако такой способ не подходит для программного извлечения значения. Для автоматизации используйте get_resource_id() или приведение к int.

Ограничение

Вывод var_dump содержит только строковое представление ресурса, его нельзя присвоить переменной. Для получения индекса в коде описанные выше методы являются единственными.

Как получить индекс потока через отладочную функцию debug_zval_refs?

Эта функция показывает ссылочную информацию, включая идентификатор ресурса:


$handle = fopen('data.csv', 'r');
debug_zval_refs($handle);
To resource: (refcount=2, id=5)…

Метод предназначен только для отладки в процессе разработки. Для продакшена используйте get_resource_id().

Проблема

debug_zval_refs выводит данные напрямую в вывод, не возвращая их. Идентификатор извлекается вручную из текста. Для программного доступа он не пригоден.

Можно ли получить индекс потока через stream_get_meta_data?

Нет. Эта функция возвращает ассоциативный массив с метаданными потока (тип, режим, обёртка), но не содержит числовой идентификатор ресурса.


$meta = stream_get_meta_data($file);
print_r($meta);
Array
(
    [stream_type] => STDIO
    [wrapper_type] => plainfile
    [mode] => r
    …
)

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

Расширенные примеры работы с индексами потоков

Ниже приведены подробные примеры, демонстрирующие практическое применение индексов потоков для управления множеством открытых ресурсов, логирования и диагностики.

Пример 1. Отображение индексов нескольких открытых потоков

Пример

$streams = [
    'file1' => fopen('file1.txt', 'w+'),
    'file2' => fopen('file2.txt', 'w+'),
    'stdin' => fopen('php://stdin', 'r'),
];
foreach ($streams as $name => $stream) {
    $id = get_resource_id($stream);
    echo "{$name}: индекс {$id}\n";
}
file1: индекс 5
file2: индекс 6
stdin: индекс 7

Пример 2. Логирование открытия и закрытия потоков с записью индекса

Пример

function log_open($filename, $stream) {
    $id = get_resource_id($stream);
    error_log("[LOG] Открыт поток {$filename} с индексом {$id}");
}

function log_close($stream) {
    $id = get_resource_id($stream);
    error_log("[LOG] Закрыт поток с индексом {$id}");
    fclose($stream);
}

$file = fopen('app.log', 'a');
log_open('app.log', $file);
// ... работа ...
log_close($file);
В файле error.log появится:
[LOG] Открыт поток app.log с индексом 5
[LOG] Закрыт поток с индексом 5

Пример 3. Проверка, является ли переменная потоком, по индексу

Пример

function isStream($var) {
    if (!is_resource($var)) return false;
    $type = get_resource_type($var);
    return $type === 'stream';
}

$handle = fopen('test.txt', 'r');
$number = 42;
echo isStream($handle) ? 'поток' : 'не поток'; // поток
echo isStream($number) ? 'поток' : 'не поток'; // не поток
поток
не поток

Пример 4. Использование индекса для уникальной идентификации потоков в пуле

Пример

$pool = [];
$file1 = fopen('a.txt', 'r');
$file2 = fopen('b.txt', 'r');

$id1 = get_resource_id($file1);
$id2 = get_resource_id($file2);

$pool[$id1] = $file1;
$pool[$id2] = $file2;

// Закрыть поток по его индексу
if (isset($pool[5])) {
    fclose($pool[5]);
    unset($pool[5]);
}

Результат

Массив $pool содержит только активные потоки, индексы служат ключами. После закрытия поток по индексу 5 удаляется.

Пример 5. Обработка ошибок при получении индекса в разных версиях PHP

Пример

function getStreamId($resource) {
    if (!is_resource($resource)) {
        throw new InvalidArgumentException("Переменная не является ресурсом");
    }
    if (function_exists('get_resource_id')) {
        return get_resource_id($resource);
    }
    // fallback для PHP < 8.0
    return (int) $resource;
}

try {
    $stream = fopen('test.txt', 'r');
    echo getStreamId($stream);
} catch (Exception $e) {
    echo $e->getMessage();
}
5

Пример 6. Комбинирование индекса с метаданными для полного описания потока

Пример

$stream = fopen('https://example.com', 'r');
$id = get_resource_id($stream);
$meta = stream_get_meta_data($stream);

$info = [
    'resource_id' => $id,
    'wrapper' => $meta['wrapper_type'],
    'mode' => $meta['mode'],
    'is_blocked' => $meta['blocked'],
];
print_r($info);
Array
(
    [resource_id] => 6
    [wrapper] => http
    [mode] => r
    [is_blocked] => 1
)

Индекс потока PHP - comments

En
Stream index php (php)