Menu

Reference / Buffer

Reader

finalclass
final class Reader

A bounded, buffered read from a stream.

Reads go through a {@see ByteBuffer} that you supply and may share. Bytes pulled from the stream beyond what a read asked for stay in that buffer, so the next reader of the same buffer, for example the next request on a keep-alive connection, finds them there.

The limit given to the constructor is a byte budget. With a limit, the Reader reports end of input once the budget is spent, whatever the stream does afterwards; with the default of -1 it reads until the peer closes. A read that finds nothing returns '': that means end of input, not an error, and a short read only means that is what had arrived.

$buf = new Buffer\ByteBuffer();
$r = new Buffer\Reader($stream, $buf, 10);
$body = $r->readAll(1024);

Example

// Buffer\Writer batches small writes; Buffer\Reader reads a bounded body and
// leaves whatever follows it in the shared buffer.

use Buffer\ByteBuffer;
use Buffer\Reader;
use Buffer\Writer;

$p = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);

$w = new Writer($p[0]);
$w->write("HELLO-");
$w->write("BODY");
echo "queued: ", $w->pending(), ", on the wire: ", $w->bytesWritten(), "\n";
$w->writev(["next-", "request"]);   // flushes the queue, then one writev
echo "queued: ", $w->pending(), ", on the wire: ", $w->bytesWritten(), "\n";
fclose($p[0]);                      // the peer is done: reads now see EOF

// A Reader with a 10-byte budget; the buffer is shared with the next reader.
$buf = new ByteBuffer();
$r = new Reader($p[1], $buf, 10);
echo "remaining: ", $r->remaining(), "\n";
echo "read: ", $r->read(4), "\n";
echo "read: ", $r->read(100), "\n";
echo "budget spent: ", var_export($r->eof(), true), ", read '", $r->read(5), "'\n";
echo "left in buffer: ", $buf->view(), "\n";

// readAll() refuses more than its cap: '' and ->over, no exception.
$buf2 = new ByteBuffer();
$q = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
fwrite($q[0], str_repeat("z", 100));
fclose($q[0]);
$r2 = new Reader($q[1], $buf2);
$all = $r2->readAll(50);
echo "readAll(50): ", strlen($all), " bytes, over=", var_export($r2->over, true), "\n";
fclose($p[1]);
fclose($q[1]);

Output

queued: 10, on the wire: 0
queued: 0, on the wire: 22
remaining: 10
read: HELL
read: O-BODY
budget spent: true, read ''
left in buffer: next-request
readAll(50): 0 bytes, over=true

See also: ByteBuffer, Writer

Properties

overboolTrue once a read could not complete because a cap was hit: readAll() refused a body bigger than its cap, or the shared buffer was full.

over#source

bool $over = false

True once a read could not complete because a cap was hit: readAll() refused a body bigger than its cap, or the shared buffer was full. It is a flag and not an exception so a server can choose between answering 413 and carrying on.

Methods

__construct()Create a reader.
remaining()The unspent part of the byte budget.
eof()Whether nothing more will come.
bytesRead()The total number of bytes returned by read() so far.
read()Read up to a number of bytes, waiting for the stream when the buffer is empty.
readAll()Read the rest of the input as one string, refusing to collect more than a cap.
discard()Read to the end of the input and throw the bytes away.

__construct()#source

function __construct(\Resource $src, ByteBuffer $buf, int $limit = -1)

Create a reader.

Parameters

$src \Resource
the stream to read from
$buf ByteBuffer
buffer to read through; pass the same one to successive readers of one stream, so surplus bytes are not lost
$limit int = -1
byte budget, or -1 to read until the peer closes

remaining()#source

function remaining(): int

The unspent part of the byte budget.

Returns

int — bytes left, or -1 when the reader has no limit

eof()#source

function eof(): bool

Whether nothing more will come.

Returns

bool — true when the budget is spent, or the peer has closed and the buffer is drained, or the shared buffer overflowed and is drained

bytesRead()#source

function bytesRead(): int

The total number of bytes returned by read() so far.

Returns

int — the byte count

read()#source

function read(int $max): string

Read up to a number of bytes, waiting for the stream when the buffer is empty.

Parameters

$max int
most bytes to return; never more than the budget has left

Returns

string — the bytes; '' means end of input (budget spent or peer closed), not an error. A short result is ordinary and means only that this is what had arrived.

readAll()#source

function readAll(int $cap): string

Read the rest of the input as one string, refusing to collect more than a cap.

On overflow it returns '' and sets {@see $over}, instead of throwing.

Parameters

$cap int
most bytes to accept in total

Returns

string — everything up to end of input, or '' when it exceeded $cap

discard()#source

function discard(): int

Read to the end of the input and throw the bytes away.

Use it to skip an unwanted body so the stream is positioned at whatever follows.

Returns

int — how many bytes were dropped

View source