scratch – Blame information for rev 87

Subversion Repositories:
Rev:
Rev Author Line No. Line
87 office 1 =======
2 Streams
3 =======
4  
5 Guzzle uses stream objects to represent request and response message bodies.
6 These stream objects allow you to work with various types of data all using a
7 common interface.
8  
9 HTTP messages consist of a start-line, headers, and a body. The body of an HTTP
10 message can be very small or extremely large. Attempting to represent the body
11 of a message as a string can easily consume more memory than intended because
12 the body must be stored completely in memory. Attempting to store the body of a
13 request or response in memory would preclude the use of that implementation from
14 being able to work with large message bodies. The StreamInterface is used in
15 order to hide the implementation details of where a stream of data is read from
16 or written to.
17  
18 Guzzle's StreamInterface exposes several methods that enable streams to be read
19 from, written to, and traversed effectively.
20  
21 Streams expose their capabilities using three methods: ``isReadable()``,
22 ``isWritable()``, and ``isSeekable()``. These methods can be used by stream
23 collaborators to determine if a stream is capable of their requirements.
24  
25 Each stream instance has various capabilities: they can be read-only,
26 write-only, read-write, allow arbitrary random access (seeking forwards or
27 backwards to any location), or only allow sequential access (for example in the
28 case of a socket or pipe).
29  
30 Creating Streams
31 ================
32  
33 The best way to create a stream is using the static factory method,
34 ``GuzzleHttp\Stream\Stream::factory()``. This factory accepts strings,
35 resources returned from ``fopen()``, an object that implements
36 ``__toString()``, and an object that implements
37 ``GuzzleHttp\Stream\StreamInterface``.
38  
39 .. code-block:: php
40  
41 use GuzzleHttp\Stream\Stream;
42  
43 $stream = Stream::factory('string data');
44 echo $stream;
45 // string data
46 echo $stream->read(3);
47 // str
48 echo $stream->getContents();
49 // ing data
50 var_export($stream->eof());
51 // true
52 var_export($stream->tell());
53 // 11
54  
55 Metadata Streams
56 ================
57  
58 Guzzle streams that implement ``GuzzleHttp\Stream\MetadataStreamInterface``
59 expose stream metadata through the ``getMetadata()`` method. This method
60 provides the data you would retrieve when calling PHP's
61 `stream_get_meta_data() function <http://php.net/manual/en/function.stream-get-meta-data.php>`_.
62  
63 .. code-block:: php
64  
65 use GuzzleHttp\Stream\Stream;
66  
67 $resource = fopen('/path/to/file', 'r');
68 $stream = Stream::factory($resource);
69 echo $stream->getMetadata('uri');
70 // /path/to/file
71 var_export($stream->isReadable());
72 // true
73 var_export($stream->isWritable());
74 // false
75 var_export($stream->isSeekable());
76 // true
77  
78 .. note::
79  
80 Streams created using ``GuzzleHttp\Stream\Stream::factory()`` all implement
81 ``GuzzleHttp\Stream\MetadataStreamInterface``.
82  
83 Stream Decorators
84 =================
85  
86 With the small and focused interface, add custom functionality to streams is
87 very simple with stream decorators. Guzzle provides several built-in decorators
88 that provide additional stream functionality.
89  
90 CachingStream
91 -------------
92  
93 The CachingStream is used to allow seeking over previously read bytes on
94 non-seekable streams. This can be useful when transferring a non-seekable
95 entity body fails due to needing to rewind the stream (for example, resulting
96 from a redirect). Data that is read from the remote stream will be buffered in
97 a PHP temp stream so that previously read bytes are cached first in memory,
98 then on disk.
99  
100 .. code-block:: php
101  
102 use GuzzleHttp\Stream\Stream;
103 use GuzzleHttp\Stream\CachingStream;
104  
105 $original = Stream::factory(fopen('http://www.google.com', 'r'));
106 $stream = new CachingStream($original);
107  
108 $stream->read(1024);
109 echo $stream->tell();
110 // 1024
111  
112 $stream->seek(0);
113 echo $stream->tell();
114 // 0
115  
116 LimitStream
117 -----------
118  
119 LimitStream can be used to read a subset or slice of an existing stream object.
120 This can be useful for breaking a large file into smaller pieces to be sent in
121 chunks (e.g. Amazon S3's multipart upload API).
122  
123 .. code-block:: php
124  
125 use GuzzleHttp\Stream\Stream;
126 use GuzzleHttp\Stream\LimitStream;
127  
128 $original = Stream::factory(fopen('/tmp/test.txt', 'r+'));
129 echo $original->getSize();
130 // >>> 1048576
131  
132 // Limit the size of the body to 1024 bytes and start reading from byte 2048
133 $stream = new LimitStream($original, 1024, 2048);
134 echo $stream->getSize();
135 // >>> 1024
136 echo $stream->tell();
137 // >>> 0
138  
139 NoSeekStream
140 ------------
141  
142 NoSeekStream wraps a stream and does not allow seeking.
143  
144 .. code-block:: php
145  
146 use GuzzleHttp\Stream\Stream;
147 use GuzzleHttp\Stream\LimitStream;
148  
149 $original = Stream::factory('foo');
150 $noSeek = new NoSeekStream($original);
151  
152 echo $noSeek->read(3);
153 // foo
154 var_export($noSeek->isSeekable());
155 // false
156 $noSeek->seek(0);
157 var_export($noSeek->read(3));
158 // NULL
159  
160 Creating Custom Decorators
161 --------------------------
162  
163 Creating a stream decorator is very easy thanks to the
164 ``GuzzleHttp\Stream\StreamDecoratorTrait``. This trait provides methods that
165 implement ``GuzzleHttp\Stream\StreamInterface`` by proxying to an underlying
166 stream. Just ``use`` the ``StreamDecoratorTrait`` and implement your custom
167 methods.
168  
169 For example, let's say we wanted to call a specific function each time the last
170 byte is read from a stream. This could be implemented by overriding the
171 ``read()`` method.
172  
173 .. code-block:: php
174  
175 use GuzzleHttp\Stream\StreamDecoratorTrait;
176  
177 class EofCallbackStream implements StreamInterface, MetadataStreamInterface
178 {
179 use StreamDecoratorTrait;
180  
181 private $callback;
182  
183 public function __construct(StreamInterface $stream, callable $callback)
184 {
185 $this->stream = $stream;
186 $this->callback = $callback;
187 }
188  
189 public function read($length)
190 {
191 $result = $this->stream->read($length);
192  
193 // Invoke the callback when EOF is hit.
194 if ($this->eof()) {
195 call_user_func($this->callback);
196 }
197  
198 return $result;
199 }
200 }
201  
202 This decorator could be added to any existing stream and used like so:
203  
204 .. code-block:: php
205  
206 use GuzzleHttp\Stream\Stream;
207  
208 $original = Stream::factory('foo');
209 $eofStream = new EofCallbackStream($original, function () {
210 echo 'EOF!';
211 });
212  
213 $eofStream->read(2);
214 $eofStream->read(1);
215 // echoes "EOF!"
216 $eofStream->seek(0);
217 $eofStream->read(3);
218 // echoes "EOF!"