Chris@0: methods = $methods; Chris@0: Chris@0: // Create the functions on the class Chris@0: foreach ($methods as $name => $fn) { Chris@0: $this->{'_fn_' . $name} = $fn; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Lazily determine which methods are not implemented. Chris@0: * @throws \BadMethodCallException Chris@0: */ Chris@0: public function __get($name) Chris@0: { Chris@0: throw new \BadMethodCallException(str_replace('_fn_', '', $name) Chris@0: . '() is not implemented in the FnStream'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * The close method is called on the underlying stream only if possible. Chris@0: */ Chris@0: public function __destruct() Chris@0: { Chris@0: if (isset($this->_fn_close)) { Chris@0: call_user_func($this->_fn_close); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@17: * An unserialize would allow the __destruct to run when the unserialized value goes out of scope. Chris@17: * @throws \LogicException Chris@17: */ Chris@17: public function __wakeup() Chris@17: { Chris@17: throw new \LogicException('FnStream should never be unserialized'); Chris@17: } Chris@17: Chris@17: /** Chris@0: * Adds custom functionality to an underlying stream by intercepting Chris@0: * specific method calls. Chris@0: * Chris@0: * @param StreamInterface $stream Stream to decorate Chris@0: * @param array $methods Hash of method name to a closure Chris@0: * Chris@0: * @return FnStream Chris@0: */ Chris@0: public static function decorate(StreamInterface $stream, array $methods) Chris@0: { Chris@0: // If any of the required methods were not provided, then simply Chris@0: // proxy to the decorated stream. Chris@0: foreach (array_diff(self::$slots, array_keys($methods)) as $diff) { Chris@0: $methods[$diff] = [$stream, $diff]; Chris@0: } Chris@0: Chris@0: return new self($methods); Chris@0: } Chris@0: Chris@0: public function __toString() Chris@0: { Chris@0: return call_user_func($this->_fn___toString); Chris@0: } Chris@0: Chris@0: public function close() Chris@0: { Chris@0: return call_user_func($this->_fn_close); Chris@0: } Chris@0: Chris@0: public function detach() Chris@0: { Chris@0: return call_user_func($this->_fn_detach); Chris@0: } Chris@0: Chris@0: public function getSize() Chris@0: { Chris@0: return call_user_func($this->_fn_getSize); Chris@0: } Chris@0: Chris@0: public function tell() Chris@0: { Chris@0: return call_user_func($this->_fn_tell); Chris@0: } Chris@0: Chris@0: public function eof() Chris@0: { Chris@0: return call_user_func($this->_fn_eof); Chris@0: } Chris@0: Chris@0: public function isSeekable() Chris@0: { Chris@0: return call_user_func($this->_fn_isSeekable); Chris@0: } Chris@0: Chris@0: public function rewind() Chris@0: { Chris@0: call_user_func($this->_fn_rewind); Chris@0: } Chris@0: Chris@0: public function seek($offset, $whence = SEEK_SET) Chris@0: { Chris@0: call_user_func($this->_fn_seek, $offset, $whence); Chris@0: } Chris@0: Chris@0: public function isWritable() Chris@0: { Chris@0: return call_user_func($this->_fn_isWritable); Chris@0: } Chris@0: Chris@0: public function write($string) Chris@0: { Chris@0: return call_user_func($this->_fn_write, $string); Chris@0: } Chris@0: Chris@0: public function isReadable() Chris@0: { Chris@0: return call_user_func($this->_fn_isReadable); Chris@0: } Chris@0: Chris@0: public function read($length) Chris@0: { Chris@0: return call_user_func($this->_fn_read, $length); Chris@0: } Chris@0: Chris@0: public function getContents() Chris@0: { Chris@0: return call_user_func($this->_fn_getContents); Chris@0: } Chris@0: Chris@0: public function getMetadata($key = null) Chris@0: { Chris@0: return call_user_func($this->_fn_getMetadata, $key); Chris@0: } Chris@0: }