phasync
Streams and files / StringBuffer

Class

StringBuffer

A buffer of streamed bytes that one coroutine fills and another reads, for parsing protocols that arrive in frames.

Introduction#

Designed for servers (HTTP, FastCGI, WebSocket) that read fixed-size frames from a byte stream. A reader waits for data, readFixed() waits for a whole frame, and end() marks the end of the stream. Unbounded by default: a writer that outpaces its reader grows the buffer without limit. With $maxSize, write() waits until the reader has made room. For passing values between coroutines, use a channel.

If the writing coroutine exits without calling end(), readers must not wait forever. Ask for getDeadmanSwitch() in the writer and keep the object until it ends: when it is destroyed without end() having been called, a reader that has read the buffered data gets an exception instead of waiting.

Class synopsis#

class StringBuffer implements SelectableInterface {
    /* Methods */
    public StringBuffer::__construct(?int $maxSize = null)
    public StringBuffer::await(float $timeout = PHP_FLOAT_MAX): void
    public StringBuffer::isReady(): bool
    public StringBuffer::isEmpty(): bool
    public StringBuffer::write(string $chunk, float $timeout = PHP_FLOAT_MAX): void
    public StringBuffer::read(int $maxLength, float $timeout = PHP_FLOAT_MAX): string
    public StringBuffer::readFromResource($resource): Fiber
    public StringBuffer::end(): void
    public StringBuffer::eof(): bool
    public StringBuffer::readFixed(int $length, float $timeout = PHP_FLOAT_MAX): ?string
    public StringBuffer::writeToResource($resource): Fiber
    public StringBuffer::unread(string $chunk): void
    public StringBuffer::getDeadmanSwitch(): DeadmanSwitch
}

Constants#

NameValueDescription
BUFFER_WASTE_LIMIT4096How much unusable string data can the string buffer hold before we must perform substr to remove data already returned.

Methods#

MethodDescription
__constructCreates an empty buffer.
awaitWaits until the buffer has data to read or has ended.
isReadyReturns true if a read would not wait: data is buffered, or the buffer has ended or failed.
isEmptyReturns true if no data is buffered for reading.
writeAppends $chunk to the buffer, and wakes the reader.
readReturns up to $maxLength bytes, and waits while the buffer is empty and not ended.
readFromResourceStarts a coroutine that reads the stream into the buffer, and ends the buffer when the stream ends.
endMarks the end of the stream: no more writes are accepted, and readers get the data left and then the end.
eofReturns true if the buffer has ended and all its data has been read.
readFixedReturns exactly $length bytes, and waits until that many are buffered.
writeToResourceStarts a coroutine that writes the buffer to the stream until the buffer has ended and been read.
unreadPuts $chunk back at the front of the buffer, to be read first.
getDeadmanSwitchGet a deadman switch for this object.

Examples#

Example 1
phasync::run(function () {
    $buffer = new phasync\Util\StringBuffer();

    phasync::go(function () use ($buffer) {
        $buffer->write("he");
        phasync::sleep(0.01);
        $buffer->write("llo\n");
        $buffer->end();
    });

    var_dump($buffer->readFixed(5));   // string(5) "hello", after both writes
    var_dump($buffer->read(10));       // string(1) "\n"
    var_dump($buffer->read(10));       // string(0) "": the buffer has ended
});

See also#

  • phasync::channelCreates a channel and returns its two ends in $read and $write.
  • SelectableInterfaceAn object that can be asked whether using it would block, and waited for until it would not.