W3docs

PHP Stream

Потоки в PHP — мощный инструмент для чтения и записи данных из файлов, сокетов и HTTP-запросов через единый унифицированный интерфейс.

PHP-потоки

Поток (stream) в PHP — это универсальный способ чтения и записи данных вне зависимости от того, где эти данные находятся. Файл на диске, область памяти, сетевой сокет и тело HTTP-ответа — всё это совершенно разные вещи, однако PHP позволяет работать с ними с помощью одного и того же набора функций. В этой унификации и заключается главное преимущество: если вы умеете читать файл с помощью fopen()/fgets(), то уже знаете, как читать веб-страницу или буфер памяти.

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

Какую проблему решают потоки?

Без потоков для каждого источника данных потребовался бы отдельный API — один для файлов, другой для HTTP, третий для сокетов. Потоки предоставляют единую абстракцию:

  • Обёртка (wrapper) — префикс вроде file://, php://, http:// или php://memory, который сообщает PHP, к какому типу ресурса вы обращаетесь.
  • Дескриптор ресурса — значение, которое возвращает fopen(); его передают во все остальные функции работы с потоками.
  • Фильтры и контексты — необязательные слои, преобразующие данные (например, gzip) или настраивающие соединение (например, HTTP-заголовки, таймауты).

Благодаря такой архитектуре можно заменить локальный путь удалённым URL, и большая часть кода останется неизменной.

Основные функции для работы с потоками

Эти функции составляют основу Streams API:

ФункцияЧто делает
fopen($target, $mode)Открывает файл или URL и возвращает дескриптор потока (или false при ошибке).
fread($handle, $length)Читает до $length байт.
fgets($handle)Читает одну строку.
fwrite($handle, $string)Записывает строку и возвращает количество записанных байт.
feof($handle)Возвращает true, когда достигнут конец потока.
fclose($handle)Освобождает дескриптор потока.

Параметр $mode управляет режимом доступа: 'r' (чтение), 'w' (запись, с усечением файла), 'a' (добавление в конец), а также варианты с '+' для чтения и записи одновременно.

Для разовых операций чтения и записи управлять дескриптором вручную не нужно — высокоуровневые вспомогательные функции file_get_contents() и file_put_contents() открывают, передают данные и закрывают поток за один вызов.

Обёртки и типы потоков

Обёртка в начале строки с адресом источника определяет тип потока:

  • Файловые потоки (file:// или просто путь без префикса) — чтение и запись данных в файловой системе. См. Работа с файлами в PHP и Открытие и чтение файла.
  • Потоки памяти (php://memory, php://temp) — буфер чтения/записи в оперативной памяти; удобен для формирования данных в тестах без обращения к диску.
  • Потоки ввода/вывода (php://stdin, php://stdout, php://input) — стандартный ввод/вывод и необработанное тело запроса.
  • Сетевые потоки / сокеты (tcp://, ssl://) — чтение и запись через сетевое соединение.
  • HTTP/FTP-потоки (http://, https://, ftp://) — загрузка удалённых документов как обычных файлов (требует включённого параметра allow_url_fopen).

Чтение файла построчно

Этот минимальный самодостаточный пример записывает небольшой файл, читает его обратно через поток построчно, а затем удаляет:

<?php

$path = sys_get_temp_dir() . '/stream-demo.txt';

// Write three lines using the high-level helper.
file_put_contents($path, "alpha\nbeta\ngamma\n");

// Read them back through a stream handle.
$handle = fopen($path, 'r');
if ($handle === false) {
    exit("Could not open the stream.\n");
}

while (!feof($handle)) {
    $line = fgets($handle);
    if ($line !== false) {
        echo "Line: " . trim($line) . PHP_EOL;
    }
}

fclose($handle);
unlink($path);

Вывод:

Line: alpha
Line: beta
Line: gamma

Файл открывается в режиме чтения, цикл продолжается до тех пор, пока feof() не сообщит о конце потока, а каждая строка читается с помощью fgets(). Всегда проверяйте, что fopen() не вернул false, прежде чем использовать дескриптор, и вызывайте fclose() по завершении работы.

Использование потока памяти

Потоки памяти ведут себя как файлы, но никогда не обращаются к диску — удобно для формирования вывода или для модульных тестов:

<?php

$handle = fopen('php://memory', 'r+');

fwrite($handle, "buffered data");

// Rewind to the start before reading what we wrote.
rewind($handle);

echo fread($handle, 1024);

fclose($handle);

Вывод:

buffered data

После записи необходимо вернуть указатель в начало с помощью rewind(), прежде чем читать, поскольку внутренняя позиция находится в конце только что записанных данных.

Чтение удалённого потока

Поскольку HTTP — это просто ещё одна обёртка, тот же цикл работает с URL при включённом параметре allow_url_fopen:

<?php

$handle = fopen('https://www.example.com', 'r');
if ($handle === false) {
    exit("Failed to open the remote stream.\n");
}

while (!feof($handle)) {
    echo fgets($handle);
}

fclose($handle);

Этот пример требует доступа к сети и включённого параметра allow_url_fopen, поэтому он не будет работать в офлайн-среде. В реальных приложениях специализированный HTTP-клиент, например cURL, даёт больше контроля над заголовками, таймаутами и ошибками.

Обработка ошибок

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

  • Проверяйте возвращаемое значение fopen() перед чтением или записью.
  • Оборачивайте рискованные операции в блок try/catch, если вы преобразуете предупреждения в исключения — см. Исключения в PHP.
  • Всегда вызывайте fclose() для открытых дескрипторов, чтобы освобождать ресурсы.

Заключение

Потоки обеспечивают PHP единым, согласованным интерфейсом для любого вида передачи данных — файлов, буферов памяти, сокетов и HTTP-ответов. Освойте небольшой набор основных функций (fopen, fread/fgets, fwrite, feof, fclose), разберитесь с обёртками вроде file:// и php://memory, а для простых случаев используйте высокоуровневые вспомогательные функции file_get_contents()/file_put_contents(). Для дальнейшего изучения обратитесь к разделам создание и запись файлов и обработка ошибок.

Практика

Практика
Для чего можно использовать потоки PHP?
Для чего можно использовать потоки PHP?
Was this page helpful?