File indexing completed on 2024-12-29 05:27:23
0001 <?php 0002 namespace GuzzleHttp\Psr7; 0003 0004 use Psr\Http\Message\StreamInterface; 0005 0006 /** 0007 * Compose stream implementations based on a hash of functions. 0008 * 0009 * Allows for easy testing and extension of a provided stream without needing 0010 * to create a concrete class for a simple extension point. 0011 */ 0012 class FnStream implements StreamInterface 0013 { 0014 /** @var array */ 0015 private $methods; 0016 0017 /** @var array Methods that must be implemented in the given array */ 0018 private static $slots = ['__toString', 'close', 'detach', 'rewind', 0019 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write', 0020 'isReadable', 'read', 'getContents', 'getMetadata']; 0021 0022 /** 0023 * @param array $methods Hash of method name to a callable. 0024 */ 0025 public function __construct(array $methods) 0026 { 0027 $this->methods = $methods; 0028 0029 // Create the functions on the class 0030 foreach ($methods as $name => $fn) { 0031 $this->{'_fn_' . $name} = $fn; 0032 } 0033 } 0034 0035 /** 0036 * Lazily determine which methods are not implemented. 0037 * @throws \BadMethodCallException 0038 */ 0039 public function __get($name) 0040 { 0041 throw new \BadMethodCallException(str_replace('_fn_', '', $name) 0042 . '() is not implemented in the FnStream'); 0043 } 0044 0045 /** 0046 * The close method is called on the underlying stream only if possible. 0047 */ 0048 public function __destruct() 0049 { 0050 if (isset($this->_fn_close)) { 0051 call_user_func($this->_fn_close); 0052 } 0053 } 0054 0055 /** 0056 * Adds custom functionality to an underlying stream by intercepting 0057 * specific method calls. 0058 * 0059 * @param StreamInterface $stream Stream to decorate 0060 * @param array $methods Hash of method name to a closure 0061 * 0062 * @return FnStream 0063 */ 0064 public static function decorate(StreamInterface $stream, array $methods) 0065 { 0066 // If any of the required methods were not provided, then simply 0067 // proxy to the decorated stream. 0068 foreach (array_diff(self::$slots, array_keys($methods)) as $diff) { 0069 $methods[$diff] = [$stream, $diff]; 0070 } 0071 0072 return new self($methods); 0073 } 0074 0075 public function __toString() 0076 { 0077 return call_user_func($this->_fn___toString); 0078 } 0079 0080 public function close() 0081 { 0082 return call_user_func($this->_fn_close); 0083 } 0084 0085 public function detach() 0086 { 0087 return call_user_func($this->_fn_detach); 0088 } 0089 0090 public function getSize() 0091 { 0092 return call_user_func($this->_fn_getSize); 0093 } 0094 0095 public function tell() 0096 { 0097 return call_user_func($this->_fn_tell); 0098 } 0099 0100 public function eof() 0101 { 0102 return call_user_func($this->_fn_eof); 0103 } 0104 0105 public function isSeekable() 0106 { 0107 return call_user_func($this->_fn_isSeekable); 0108 } 0109 0110 public function rewind() 0111 { 0112 call_user_func($this->_fn_rewind); 0113 } 0114 0115 public function seek($offset, $whence = SEEK_SET) 0116 { 0117 call_user_func($this->_fn_seek, $offset, $whence); 0118 } 0119 0120 public function isWritable() 0121 { 0122 return call_user_func($this->_fn_isWritable); 0123 } 0124 0125 public function write($string) 0126 { 0127 return call_user_func($this->_fn_write, $string); 0128 } 0129 0130 public function isReadable() 0131 { 0132 return call_user_func($this->_fn_isReadable); 0133 } 0134 0135 public function read($length) 0136 { 0137 return call_user_func($this->_fn_read, $length); 0138 } 0139 0140 public function getContents() 0141 { 0142 return call_user_func($this->_fn_getContents); 0143 } 0144 0145 public function getMetadata($key = null) 0146 { 0147 return call_user_func($this->_fn_getMetadata, $key); 0148 } 0149 }