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(). Для дальнейшего изучения обратитесь к разделам создание и запись файлов и обработка ошибок.