Извлечение идентификатора ресурса потока в 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
)