1<?php 2 3namespace GuzzleHttp\Psr7; 4 5use Psr\Http\Message\StreamInterface; 6 7/** 8 * Stream decorator trait 9 * 10 * @property StreamInterface stream 11 */ 12trait StreamDecoratorTrait 13{ 14 /** 15 * @param StreamInterface $stream Stream to decorate 16 */ 17 public function __construct(StreamInterface $stream) 18 { 19 $this->stream = $stream; 20 } 21 22 /** 23 * Magic method used to create a new stream if streams are not added in 24 * the constructor of a decorator (e.g., LazyOpenStream). 25 * 26 * @param string $name Name of the property (allows "stream" only). 27 * 28 * @return StreamInterface 29 */ 30 public function __get($name) 31 { 32 if ($name == 'stream') { 33 $this->stream = $this->createStream(); 34 return $this->stream; 35 } 36 37 throw new \UnexpectedValueException("$name not found on class"); 38 } 39 40 public function __toString() 41 { 42 try { 43 if ($this->isSeekable()) { 44 $this->seek(0); 45 } 46 return $this->getContents(); 47 } catch (\Exception $e) { 48 // Really, PHP? https://bugs.php.net/bug.php?id=53648 49 trigger_error('StreamDecorator::__toString exception: ' 50 . (string) $e, E_USER_ERROR); 51 return ''; 52 } 53 } 54 55 public function getContents() 56 { 57 return Utils::copyToString($this); 58 } 59 60 /** 61 * Allow decorators to implement custom methods 62 * 63 * @param string $method Missing method name 64 * @param array $args Method arguments 65 * 66 * @return mixed 67 */ 68 public function __call($method, array $args) 69 { 70 $result = call_user_func_array([$this->stream, $method], $args); 71 72 // Always return the wrapped object if the result is a return $this 73 return $result === $this->stream ? $this : $result; 74 } 75 76 public function close() 77 { 78 $this->stream->close(); 79 } 80 81 public function getMetadata($key = null) 82 { 83 return $this->stream->getMetadata($key); 84 } 85 86 public function detach() 87 { 88 return $this->stream->detach(); 89 } 90 91 public function getSize() 92 { 93 return $this->stream->getSize(); 94 } 95 96 public function eof() 97 { 98 return $this->stream->eof(); 99 } 100 101 public function tell() 102 { 103 return $this->stream->tell(); 104 } 105 106 public function isReadable() 107 { 108 return $this->stream->isReadable(); 109 } 110 111 public function isWritable() 112 { 113 return $this->stream->isWritable(); 114 } 115 116 public function isSeekable() 117 { 118 return $this->stream->isSeekable(); 119 } 120 121 public function rewind() 122 { 123 $this->seek(0); 124 } 125 126 public function seek($offset, $whence = SEEK_SET) 127 { 128 $this->stream->seek($offset, $whence); 129 } 130 131 public function read($length) 132 { 133 return $this->stream->read($length); 134 } 135 136 public function write($string) 137 { 138 return $this->stream->write($string); 139 } 140 141 /** 142 * Implement in subclasses to dynamically create streams when requested. 143 * 144 * @return StreamInterface 145 * 146 * @throws \BadMethodCallException 147 */ 148 protected function createStream() 149 { 150 throw new \BadMethodCallException('Not implemented'); 151 } 152} 153