Chris@0
|
1 <?php
|
Chris@0
|
2 namespace GuzzleHttp\Psr7;
|
Chris@0
|
3
|
Chris@0
|
4 use Psr\Http\Message\StreamInterface;
|
Chris@0
|
5
|
Chris@0
|
6 /**
|
Chris@0
|
7 * Compose stream implementations based on a hash of functions.
|
Chris@0
|
8 *
|
Chris@0
|
9 * Allows for easy testing and extension of a provided stream without needing
|
Chris@0
|
10 * to create a concrete class for a simple extension point.
|
Chris@0
|
11 */
|
Chris@0
|
12 class FnStream implements StreamInterface
|
Chris@0
|
13 {
|
Chris@0
|
14 /** @var array */
|
Chris@0
|
15 private $methods;
|
Chris@0
|
16
|
Chris@0
|
17 /** @var array Methods that must be implemented in the given array */
|
Chris@0
|
18 private static $slots = ['__toString', 'close', 'detach', 'rewind',
|
Chris@0
|
19 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
|
Chris@0
|
20 'isReadable', 'read', 'getContents', 'getMetadata'];
|
Chris@0
|
21
|
Chris@0
|
22 /**
|
Chris@0
|
23 * @param array $methods Hash of method name to a callable.
|
Chris@0
|
24 */
|
Chris@0
|
25 public function __construct(array $methods)
|
Chris@0
|
26 {
|
Chris@0
|
27 $this->methods = $methods;
|
Chris@0
|
28
|
Chris@0
|
29 // Create the functions on the class
|
Chris@0
|
30 foreach ($methods as $name => $fn) {
|
Chris@0
|
31 $this->{'_fn_' . $name} = $fn;
|
Chris@0
|
32 }
|
Chris@0
|
33 }
|
Chris@0
|
34
|
Chris@0
|
35 /**
|
Chris@0
|
36 * Lazily determine which methods are not implemented.
|
Chris@0
|
37 * @throws \BadMethodCallException
|
Chris@0
|
38 */
|
Chris@0
|
39 public function __get($name)
|
Chris@0
|
40 {
|
Chris@0
|
41 throw new \BadMethodCallException(str_replace('_fn_', '', $name)
|
Chris@0
|
42 . '() is not implemented in the FnStream');
|
Chris@0
|
43 }
|
Chris@0
|
44
|
Chris@0
|
45 /**
|
Chris@0
|
46 * The close method is called on the underlying stream only if possible.
|
Chris@0
|
47 */
|
Chris@0
|
48 public function __destruct()
|
Chris@0
|
49 {
|
Chris@0
|
50 if (isset($this->_fn_close)) {
|
Chris@0
|
51 call_user_func($this->_fn_close);
|
Chris@0
|
52 }
|
Chris@0
|
53 }
|
Chris@0
|
54
|
Chris@0
|
55 /**
|
Chris@0
|
56 * Adds custom functionality to an underlying stream by intercepting
|
Chris@0
|
57 * specific method calls.
|
Chris@0
|
58 *
|
Chris@0
|
59 * @param StreamInterface $stream Stream to decorate
|
Chris@0
|
60 * @param array $methods Hash of method name to a closure
|
Chris@0
|
61 *
|
Chris@0
|
62 * @return FnStream
|
Chris@0
|
63 */
|
Chris@0
|
64 public static function decorate(StreamInterface $stream, array $methods)
|
Chris@0
|
65 {
|
Chris@0
|
66 // If any of the required methods were not provided, then simply
|
Chris@0
|
67 // proxy to the decorated stream.
|
Chris@0
|
68 foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
|
Chris@0
|
69 $methods[$diff] = [$stream, $diff];
|
Chris@0
|
70 }
|
Chris@0
|
71
|
Chris@0
|
72 return new self($methods);
|
Chris@0
|
73 }
|
Chris@0
|
74
|
Chris@0
|
75 public function __toString()
|
Chris@0
|
76 {
|
Chris@0
|
77 return call_user_func($this->_fn___toString);
|
Chris@0
|
78 }
|
Chris@0
|
79
|
Chris@0
|
80 public function close()
|
Chris@0
|
81 {
|
Chris@0
|
82 return call_user_func($this->_fn_close);
|
Chris@0
|
83 }
|
Chris@0
|
84
|
Chris@0
|
85 public function detach()
|
Chris@0
|
86 {
|
Chris@0
|
87 return call_user_func($this->_fn_detach);
|
Chris@0
|
88 }
|
Chris@0
|
89
|
Chris@0
|
90 public function getSize()
|
Chris@0
|
91 {
|
Chris@0
|
92 return call_user_func($this->_fn_getSize);
|
Chris@0
|
93 }
|
Chris@0
|
94
|
Chris@0
|
95 public function tell()
|
Chris@0
|
96 {
|
Chris@0
|
97 return call_user_func($this->_fn_tell);
|
Chris@0
|
98 }
|
Chris@0
|
99
|
Chris@0
|
100 public function eof()
|
Chris@0
|
101 {
|
Chris@0
|
102 return call_user_func($this->_fn_eof);
|
Chris@0
|
103 }
|
Chris@0
|
104
|
Chris@0
|
105 public function isSeekable()
|
Chris@0
|
106 {
|
Chris@0
|
107 return call_user_func($this->_fn_isSeekable);
|
Chris@0
|
108 }
|
Chris@0
|
109
|
Chris@0
|
110 public function rewind()
|
Chris@0
|
111 {
|
Chris@0
|
112 call_user_func($this->_fn_rewind);
|
Chris@0
|
113 }
|
Chris@0
|
114
|
Chris@0
|
115 public function seek($offset, $whence = SEEK_SET)
|
Chris@0
|
116 {
|
Chris@0
|
117 call_user_func($this->_fn_seek, $offset, $whence);
|
Chris@0
|
118 }
|
Chris@0
|
119
|
Chris@0
|
120 public function isWritable()
|
Chris@0
|
121 {
|
Chris@0
|
122 return call_user_func($this->_fn_isWritable);
|
Chris@0
|
123 }
|
Chris@0
|
124
|
Chris@0
|
125 public function write($string)
|
Chris@0
|
126 {
|
Chris@0
|
127 return call_user_func($this->_fn_write, $string);
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 public function isReadable()
|
Chris@0
|
131 {
|
Chris@0
|
132 return call_user_func($this->_fn_isReadable);
|
Chris@0
|
133 }
|
Chris@0
|
134
|
Chris@0
|
135 public function read($length)
|
Chris@0
|
136 {
|
Chris@0
|
137 return call_user_func($this->_fn_read, $length);
|
Chris@0
|
138 }
|
Chris@0
|
139
|
Chris@0
|
140 public function getContents()
|
Chris@0
|
141 {
|
Chris@0
|
142 return call_user_func($this->_fn_getContents);
|
Chris@0
|
143 }
|
Chris@0
|
144
|
Chris@0
|
145 public function getMetadata($key = null)
|
Chris@0
|
146 {
|
Chris@0
|
147 return call_user_func($this->_fn_getMetadata, $key);
|
Chris@0
|
148 }
|
Chris@0
|
149 }
|