diff options
Diffstat (limited to 'vendor/guzzlehttp/psr7/src/FnStream.php')
-rw-r--r-- | vendor/guzzlehttp/psr7/src/FnStream.php | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/vendor/guzzlehttp/psr7/src/FnStream.php b/vendor/guzzlehttp/psr7/src/FnStream.php new file mode 100644 index 0000000..9fdddb9 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/FnStream.php @@ -0,0 +1,179 @@ +<?php + +declare(strict_types=1); + +namespace GuzzleHttp\Psr7; + +use Psr\Http\Message\StreamInterface; + +/** + * Compose stream implementations based on a hash of functions. + * + * Allows for easy testing and extension of a provided stream without needing + * to create a concrete class for a simple extension point. + */ +#[\AllowDynamicProperties] +final class FnStream implements StreamInterface +{ + private const SLOTS = [ + '__toString', 'close', 'detach', 'rewind', + 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write', + 'isReadable', 'read', 'getContents', 'getMetadata', + ]; + + /** @var array<string, callable> */ + private $methods; + + /** + * @param array<string, callable> $methods Hash of method name to a callable. + */ + public function __construct(array $methods) + { + $this->methods = $methods; + + // Create the functions on the class + foreach ($methods as $name => $fn) { + $this->{'_fn_'.$name} = $fn; + } + } + + /** + * Lazily determine which methods are not implemented. + * + * @throws \BadMethodCallException + */ + public function __get(string $name): void + { + throw new \BadMethodCallException(str_replace('_fn_', '', $name) + .'() is not implemented in the FnStream'); + } + + /** + * The close method is called on the underlying stream only if possible. + */ + public function __destruct() + { + if (isset($this->_fn_close)) { + call_user_func($this->_fn_close); + } + } + + /** + * An unserialize would allow the __destruct to run when the unserialized value goes out of scope. + * + * @throws \LogicException + */ + public function __wakeup(): void + { + throw new \LogicException('FnStream should never be unserialized'); + } + + /** + * Adds custom functionality to an underlying stream by intercepting + * specific method calls. + * + * @param StreamInterface $stream Stream to decorate + * @param array<string, callable> $methods Hash of method name to a closure + * + * @return FnStream + */ + public static function decorate(StreamInterface $stream, array $methods) + { + // If any of the required methods were not provided, then simply + // proxy to the decorated stream. + foreach (array_diff(self::SLOTS, array_keys($methods)) as $diff) { + /** @var callable $callable */ + $callable = [$stream, $diff]; + $methods[$diff] = $callable; + } + + return new self($methods); + } + + public function __toString(): string + { + try { + return call_user_func($this->_fn___toString); + } catch (\Throwable $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR); + + return ''; + } + } + + public function close(): void + { + call_user_func($this->_fn_close); + } + + public function detach() + { + return call_user_func($this->_fn_detach); + } + + public function getSize(): ?int + { + return call_user_func($this->_fn_getSize); + } + + public function tell(): int + { + return call_user_func($this->_fn_tell); + } + + public function eof(): bool + { + return call_user_func($this->_fn_eof); + } + + public function isSeekable(): bool + { + return call_user_func($this->_fn_isSeekable); + } + + public function rewind(): void + { + call_user_func($this->_fn_rewind); + } + + public function seek($offset, $whence = SEEK_SET): void + { + call_user_func($this->_fn_seek, $offset, $whence); + } + + public function isWritable(): bool + { + return call_user_func($this->_fn_isWritable); + } + + public function write($string): int + { + return call_user_func($this->_fn_write, $string); + } + + public function isReadable(): bool + { + return call_user_func($this->_fn_isReadable); + } + + public function read($length): string + { + return call_user_func($this->_fn_read, $length); + } + + public function getContents(): string + { + return call_user_func($this->_fn_getContents); + } + + /** + * @return mixed + */ + public function getMetadata($key = null) + { + return call_user_func($this->_fn_getMetadata, $key); + } +} |