2 namespace GuzzleHttp\Psr7;
4 use Psr\Http\Message\StreamInterface;
7 * Compose stream implementations based on a hash of functions.
9 * Allows for easy testing and extension of a provided stream without needing
10 * to create a concrete class for a simple extension point.
12 class FnStream implements StreamInterface
17 /** @var array Methods that must be implemented in the given array */
18 private static $slots = ['__toString', 'close', 'detach', 'rewind',
19 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
20 'isReadable', 'read', 'getContents', 'getMetadata'];
23 * @param array $methods Hash of method name to a callable.
25 public function __construct(array $methods)
27 $this->methods = $methods;
29 // Create the functions on the class
30 foreach ($methods as $name => $fn) {
31 $this->{'_fn_' . $name} = $fn;
36 * Lazily determine which methods are not implemented.
37 * @throws \BadMethodCallException
39 public function __get($name)
41 throw new \BadMethodCallException(str_replace('_fn_', '', $name)
42 . '() is not implemented in the FnStream');
46 * The close method is called on the underlying stream only if possible.
48 public function __destruct()
50 if (isset($this->_fn_close)) {
51 call_user_func($this->_fn_close);
56 * Adds custom functionality to an underlying stream by intercepting
57 * specific method calls.
59 * @param StreamInterface $stream Stream to decorate
60 * @param array $methods Hash of method name to a closure
64 public static function decorate(StreamInterface $stream, array $methods)
66 // If any of the required methods were not provided, then simply
67 // proxy to the decorated stream.
68 foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
69 $methods[$diff] = [$stream, $diff];
72 return new self($methods);
75 public function __toString()
77 return call_user_func($this->_fn___toString);
80 public function close()
82 return call_user_func($this->_fn_close);
85 public function detach()
87 return call_user_func($this->_fn_detach);
90 public function getSize()
92 return call_user_func($this->_fn_getSize);
95 public function tell()
97 return call_user_func($this->_fn_tell);
100 public function eof()
102 return call_user_func($this->_fn_eof);
105 public function isSeekable()
107 return call_user_func($this->_fn_isSeekable);
110 public function rewind()
112 call_user_func($this->_fn_rewind);
115 public function seek($offset, $whence = SEEK_SET)
117 call_user_func($this->_fn_seek, $offset, $whence);
120 public function isWritable()
122 return call_user_func($this->_fn_isWritable);
125 public function write($string)
127 return call_user_func($this->_fn_write, $string);
130 public function isReadable()
132 return call_user_func($this->_fn_isReadable);
135 public function read($length)
137 return call_user_func($this->_fn_read, $length);
140 public function getContents()
142 return call_user_func($this->_fn_getContents);
145 public function getMetadata($key = null)
147 return call_user_func($this->_fn_getMetadata, $key);