source = $source; $this->size = Integers::assertOptionalNonNegativeSize($options['size'] ?? null, 'Stream size'); $this->metadata = $options['metadata'] ?? []; $this->buffer = new BufferStream(); } public function __unserialize(array $data): void { $this->source = null; $this->size = null; $this->tellPos = 0; $this->metadata = []; $this->buffer = new BufferStream(); throw new \LogicException(static::class.' should never be unserialized'); } public function __toString(): string { return Utils::copyToString($this); } public function close(): void { $this->detach(); } public function detach() { $this->tellPos = 0; $this->source = null; $this->buffer->close(); return null; } public function getSize(): ?int { return $this->size; } public function tell(): int { return $this->tellPos; } public function eof(): bool { return $this->source === null; } public function isSeekable(): bool { return false; } public function rewind(): void { $this->seek(0); } public function seek(int $offset, int $whence = SEEK_SET): void { throw new \RuntimeException('Cannot seek a PumpStream'); } public function isWritable(): bool { return false; } public function write(string $string): int { throw new \RuntimeException('Cannot write to a PumpStream'); } public function isReadable(): bool { return true; } public function read(int $length): string { if ($length < 0) { throw new \RuntimeException('Length parameter cannot be negative'); } $bufferLength = $this->buffer->getSize() ?? 0; if ($length > $bufferLength) { $this->pump($length - $bufferLength); } $data = $this->buffer->read($length); $this->tellPos = Integers::add($this->tellPos, strlen($data)); return $data; } public function getContents(): string { return Utils::copyToString($this); } /** * @return mixed */ public function getMetadata(?string $key = null) { if ($key === null) { return $this->metadata; } return $this->metadata[$key] ?? null; } private function pump(int $length): void { if ($this->source !== null) { do { /** @var string|false|null $data */ $data = ($this->source)($length); if ($data === false || $data === null) { $this->source = null; return; } if ($data === '') { throw new \RuntimeException('PumpStream source returned an empty string'); } $this->buffer->write($data); $length -= strlen($data); } while ($length > 0); } } }