gyselroth / php-stream-iterator

PSR-7 compatible stream wrapper for iterators
MIT License
3 stars 0 forks source link

violation: StreamInterface::read($maxBytes) vs StreamIterator::read($maxItems) #1

Open githubeing opened 5 years ago

githubeing commented 5 years ago

The StreamInterface clearly states:

Read up to $length bytes from the object and return them.

The StreamIterator pretends to implement it, but nevertheless explicitly violates this rule:

Read up to $length items from the iterator.

As it stringifies its input argument's items and concatenates them as strings, it definitely must count their size in bytes, and not how much items it's processed. E.g.:

    private $remainder = '';

    public function read($length)
    {
        $contents = $this->remainder;
        while ($this->iterator->valid() && strlen($contents) < $length) {
            $contents .= $this->iterator->current();
            $this->iterator->next();
        }
        $this->remainder = substr($contents, $length);
        return substr($contents, 0, $length);
    }

(i haven't run this code, wrote it just to express the idea)

the seek method also needs to be rewritten but not sure if it's possible at all

githubeing commented 5 years ago

e.g. take a look how it's made in guzzle/psr7:

You can create streams from iterators. The iterator can yield any number of bytes per iteration. Any excess bytes returned by the iterator that were not requested by a stream consumer will be buffered until a subsequent read.


$generator = function ($bytes) {
    for ($i = 0; $i < $bytes; $i++) {
        yield '.';
    }
};

$iter = $generator(1024);
$stream = Psr7\stream_for($iter);
echo $stream->read(3); // ...

http://docs.guzzlephp.org/en/stable/psr7.html#creating-streams

stream_for(Iterator): https://github.com/guzzle/psr7/blob/b3b7e2a620622ecf2f0c297517f12238a5a1a9be/src/functions.php#L95

PumpStream::read(): https://github.com/guzzle/psr7/blob/3b42ac3ad76541f1d7c17c592ccc53917770313a/src/PumpStream.php#L116