data types and standard library

Streams

A stream is a handle PHP can read from or write to progressively. Files, temporary memory buffers, request bodies, process pipes, network connections, and output buffers can all be treated as streams.

Streams matter because not every piece of data should be loaded fully into memory. Imports, exports, downloads, uploaded files, and large reports are safer when processed in chunks or lines.

Use php://temp for examples and tests

php://temp gives you a stream without creating a named file in your project.

PHP example
<?php

declare(strict_types=1);

$stream = fopen('php://temp', 'r+');

fwrite($stream, "first line\nsecond line\n");
rewind($stream);

while (($line = fgets($stream)) !== false) {
    echo trim($line) . PHP_EOL;
}

fclose($stream);

// Prints:
// first line
// second line

The same functions, fwrite(), rewind(), fgets(), and fclose(), are used with real files too.

Check that a stream opened successfully

fopen() can fail. Check the result before using it.

PHP example
<?php

declare(strict_types=1);

$stream = fopen('php://temp', 'r+');

if (!is_resource($stream)) {
    throw new RuntimeException('Could not open stream.');
}

fwrite($stream, "ready\n");
rewind($stream);

echo fgets($stream);

fclose($stream);

// Prints:
// ready

This guard is especially important for filesystem paths and remote resources where permissions or availability can change.

Write functions that accept streams

PHP has no resource type declaration, so validate stream parameters inside the function.

PHP example
<?php

declare(strict_types=1);

function countLines($stream): int
{
    if (!is_resource($stream)) {
        throw new InvalidArgumentException('Expected a stream resource.');
    }

    $count = 0;

    while (($line = fgets($stream)) !== false) {
        $count++;
    }

    return $count;
}

$stream = fopen('php://temp', 'r+');
fwrite($stream, "alpha\nbeta\ngamma\n");
rewind($stream);

echo countLines($stream) . PHP_EOL;

fclose($stream);

// Prints:
// 3

This kind of function can work with a temporary stream in tests and a real uploaded file in production.

Copy streams without loading everything

Use stream_copy_to_stream() when moving data between streams.

PHP example
<?php

declare(strict_types=1);

$source = fopen('php://temp', 'r+');
$destination = fopen('php://temp', 'r+');

fwrite($source, "export contents\n");
rewind($source);

stream_copy_to_stream($source, $destination);
rewind($destination);

echo stream_get_contents($destination);

fclose($source);
fclose($destination);

// Prints:
// export contents

This pattern is useful for downloads, generated exports, file transformations, and moving uploaded content into storage.

Read fixed-size chunks

Line-based reading is useful for text. Chunk-based reading is useful for binary files or large payloads.

PHP example
<?php

declare(strict_types=1);

$stream = fopen('php://temp', 'r+');
fwrite($stream, 'abcdef');
rewind($stream);

while (!feof($stream)) {
    $chunk = fread($stream, 2);

    if ($chunk === '') {
        break;
    }

    echo '[' . $chunk . ']';
}

echo PHP_EOL;
fclose($stream);

// Prints:
// [ab][cd][ef]

Do not assume one read returns the whole file. Stream code should be comfortable with partial reads.

Know the common PHP stream wrappers

PHP stream wrappers let you use stream functions with special sources and destinations.

PHP example
<?php

declare(strict_types=1);

$input = fopen('php://temp', 'r+');
$output = fopen('php://memory', 'r+');

echo is_resource($input) && is_resource($output) ? 'streams opened' : 'failed';
echo PHP_EOL;

fclose($input);
fclose($output);

// Prints:
// streams opened

You will often see php://input for raw HTTP request bodies, php://output for streaming responses, php://temp for temporary buffering, and php://memory for in-memory data.

What to remember

Streams let PHP process data progressively. Check handles before use, close what you open, prefer line or chunk processing for large data, and write stream-based functions when the same logic should work for files, uploads, and test buffers.

Practice

Task: Copy a report between streams

Write a small example that copies report data from one stream to another.

Requirements

  • Use declare(strict_types=1);.
  • Open two php://temp streams.
  • Check both handles are valid stream resources.
  • Write at least two lines to the source stream.
  • Rewind the source stream.
  • Copy the source stream into the destination stream with stream_copy_to_stream().
  • Rewind the destination stream.
  • Print the destination contents.
  • Close both streams.
  • Include the expected output as comments in the same PHP code block.

The example should show progressive stream handling rather than copying through a normal string variable.

Show solution
PHP example
<?php

declare(strict_types=1);

$source = fopen('php://temp', 'r+');
$destination = fopen('php://temp', 'r+');

if (!is_resource($source) || !is_resource($destination)) {
    throw new RuntimeException('Could not open temporary streams.');
}

fwrite($source, "Daily total: 120\n");
fwrite($source, "Weekly total: 560\n");
rewind($source);

stream_copy_to_stream($source, $destination);
rewind($destination);

echo stream_get_contents($destination);

fclose($source);
fclose($destination);

// Prints:
// Daily total: 120
// Weekly total: 560

The source and destination could be real files, upload streams, or response streams. The code works with stream handles, so it does not depend on a specific path or on loading a whole file into a normal string first.