BufferStream.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <?php
  2. declare(strict_types=1);
  3. namespace GuzzleHttp\Psr7;
  4. use Psr\Http\Message\StreamInterface;
  5. /**
  6. * Provides a buffer stream that can be written to to fill a buffer, and read
  7. * from to remove bytes from the buffer.
  8. *
  9. * This stream returns a "hwm" metadata value that tells upstream consumers
  10. * what the configured high water mark of the stream is, or the maximum
  11. * preferred size of the buffer.
  12. */
  13. final class BufferStream implements StreamInterface
  14. {
  15. /** @var int */
  16. private $hwm;
  17. /** @var string */
  18. private $buffer = '';
  19. /**
  20. * @param int $hwm High water mark, representing the preferred maximum
  21. * buffer size. If the size of the buffer exceeds the high
  22. * water mark, then calls to write will continue to succeed
  23. * but will return 0 to inform writers to slow down
  24. * until the buffer has been drained by reading from it.
  25. */
  26. public function __construct(int $hwm = 16384)
  27. {
  28. $this->hwm = $hwm;
  29. }
  30. public function __toString(): string
  31. {
  32. return $this->getContents();
  33. }
  34. public function getContents(): string
  35. {
  36. $buffer = $this->buffer;
  37. $this->buffer = '';
  38. return $buffer;
  39. }
  40. public function close(): void
  41. {
  42. $this->buffer = '';
  43. }
  44. public function detach()
  45. {
  46. $this->close();
  47. return null;
  48. }
  49. public function getSize(): ?int
  50. {
  51. return strlen($this->buffer);
  52. }
  53. public function isReadable(): bool
  54. {
  55. return true;
  56. }
  57. public function isWritable(): bool
  58. {
  59. return true;
  60. }
  61. public function isSeekable(): bool
  62. {
  63. return false;
  64. }
  65. public function rewind(): void
  66. {
  67. $this->seek(0);
  68. }
  69. public function seek($offset, $whence = SEEK_SET): void
  70. {
  71. throw new \RuntimeException('Cannot seek a BufferStream');
  72. }
  73. public function eof(): bool
  74. {
  75. return strlen($this->buffer) === 0;
  76. }
  77. public function tell(): int
  78. {
  79. throw new \RuntimeException('Cannot determine the position of a BufferStream');
  80. }
  81. /**
  82. * Reads data from the buffer.
  83. */
  84. public function read($length): string
  85. {
  86. $currentLength = strlen($this->buffer);
  87. if ($length >= $currentLength) {
  88. // No need to slice the buffer because we don't have enough data.
  89. $result = $this->buffer;
  90. $this->buffer = '';
  91. } else {
  92. // Slice up the result to provide a subset of the buffer.
  93. $result = substr($this->buffer, 0, $length);
  94. $this->buffer = substr($this->buffer, $length);
  95. }
  96. return $result;
  97. }
  98. /**
  99. * Writes data to the buffer.
  100. */
  101. public function write($string): int
  102. {
  103. $this->buffer .= $string;
  104. if (strlen($this->buffer) >= $this->hwm) {
  105. return 0;
  106. }
  107. return strlen($string);
  108. }
  109. /**
  110. * {@inheritdoc}
  111. *
  112. * @return mixed
  113. */
  114. public function getMetadata($key = null)
  115. {
  116. if ($key === 'hwm') {
  117. return $this->hwm;
  118. }
  119. return $key ? null : [];
  120. }
  121. }