1
- # Streaming Json Encoder #
1
+ # Streaming JSON Encoder #
2
2
3
+ * Streaming JSON Encoder* is a PHP library that provides a set of classes to help
4
+ with encoding JSON in a streaming manner, i.e. allowing you to encode the JSON
5
+ document bit by bit rather than encoding the whole document at once. Compared to
6
+ the built in ` json_encode ` function, there are two main advantages:
3
7
8
+ * You will not need to load the entire data set into memory, as the encoder
9
+ supports iterating over both arrays and any kind of iterators, like
10
+ generators, for example.
11
+ * You will not need to load the entire resulting JSON document into the
12
+ memory, since the JSON document will be encoded value by value and it's
13
+ possible to output the encoded document piece by piece.
14
+
15
+ In other words, the Streaming JSON encoder can provide the greatest benefit
16
+ when you need handle large data sets that may otherwise take up too much memory
17
+ to process.
18
+
19
+ In order to increase interoperability, the library also provides a PSR-7
20
+ compatible stream to use with frameworks and HTTP requests.
4
21
5
22
## Requirements ##
6
23
7
24
In order to use this library, the following requirements must be met:
8
25
9
- * PHP version 5.6
26
+ * PHP version 5.6, 7.0 or later
27
+ * The PHP library ` psr/http-message ` must be available
10
28
11
29
## Installation ##
12
30
13
- This library can be installed by using [ Composer] ( http://getcomposer.org/ ) . In
14
- order to do this, you must download the latest Composer version and run the
15
- ` require ` command to add this library as a dependency to your project. The
16
- easiest way to complete these two tasks is to run the following two commands
17
- in your terminal:
18
-
19
- ```
20
- php -r "readfile('https://getcomposer.org/installer');" | php
21
- php composer.phar require "violet/streaming-json-encoder:^1.0"
22
- ```
31
+ The easiest way to install this library is to use Composer to handle your
32
+ dependencies. In order to install this library via Composer, simply follow
33
+ the following two steps:
23
34
24
- If you already have Composer installed on your system and you know how to use
25
- it, you can also install this library by adding it as a dependency to your
26
- ` composer.json ` file and running the ` composer install ` command. Here is an
27
- example of what your ` composer.json ` file could look like:
35
+ 1 . Acquire the ` composer.phar ` by running in your project root the
36
+ Command-line installation script found at the [ Composer
37
+ Download] ( https://getcomposer.org/download/ ) page.
38
+ 2 . Once you've run the installation script, you should have a ` composer.phar `
39
+ file in you project root and you can run the following command:
40
+
41
+ ```
42
+ php composer.phar require "violet/streaming-json-encoder:^1.0"
43
+ ```
44
+
45
+ If you are already familiar with how to use Composer, you may also alternatively
46
+ simply add the library as a dependency by adding the following `composer.json`
47
+ file to your project and running the `composer install` command:
28
48
29
49
```json
30
50
{
@@ -40,15 +60,202 @@ the installation.
40
60
41
61
### Manual installation ###
42
62
43
- You can also install this library manually without using Composer. In order to
44
- do this, you must download the [ latest release] ( https://github.com/violet/streaming-json-encoder/releases/latest )
45
- and extract the ` src ` folder from the archive to your project folder. To load
46
- the library, you can simply include the ` src/autoload.php ` file that was
47
- provided in the archive.
63
+ If you do not wish to use Composer to load the library, you may also download
64
+ the library manually by downloading the [ latest release] ( https://github.com/violet/streaming-json-encoder/releases/latest )
65
+ and extracting the ` src ` folder to your project. You may then include the
66
+ provided ` src/autoload.php ` file to load the library classes.
67
+
68
+ Please note that using Composer will also automatically download the other
69
+ required PHP libraries. If you install this library manually, you will need to
70
+ also make those other required libraries available.
48
71
49
72
## Usage ##
50
73
74
+ This library offers 3 main different ways to use the library via the classes
75
+ ` BufferJsonEncoder ` , ` StreamJsonEncoder ` and the PSR-7 compatible stream
76
+ ` JsonStream ` .
77
+
78
+ ### Using BufferJsonEncoder ###
79
+
80
+ The buffer encoder is most useful when you need to generate the JSON document
81
+ in a way that does not involve passing callbacks to handle the generated JSON.
82
+
83
+ The easiest way to use the ` BufferJsonEncoder ` is to instantiate it with the
84
+ JSON value to encode and call the ` encode() ` method to return the entire output
85
+ as a string:
86
+
87
+ ``` php
88
+ <?php
89
+
90
+ require 'vendor/autoload.php';
91
+
92
+ $encoder = new \Violet\StreamingJsonEncoder\BufferJsonEncoder(['array_value']);
93
+ echo $encoder->encode();
94
+ ```
95
+
96
+ The most useful way to use this encoder, however, is to use it as an iterator.
97
+ As the encoder implements the ` Iterator ` interface, you can simply loop over the
98
+ generated JSON with a foreach loop:
99
+
100
+ ``` php
101
+ <?php
102
+
103
+ require 'vendor/autoload.php';
104
+
105
+ $encoder = new \Violet\StreamingJsonEncoder\BufferJsonEncoder(range(0, 10));
106
+
107
+ foreach ($encoder as $string) {
108
+ echo $string;
109
+ }
110
+ ```
111
+
112
+ It's also worth noting that the encoder also supports iterators for values.
113
+ What's more, any closure passed to the encoder will also be called and the
114
+ return value used as the value instead. The previous example could also be
115
+ written as:
116
+
117
+ ``` php
118
+ <?php
119
+
120
+ require 'vendor/autoload.php';
121
+
122
+ $encoder = new \Violet\StreamingJsonEncoder\BufferJsonEncoder(function () {
123
+ for ($i = 0; $i <= 10; $i++) {
124
+ yield $i;
125
+ }
126
+ });
127
+
128
+ foreach ($encoder as $string) {
129
+ echo $string;
130
+ }
131
+ ```
132
+
133
+ As a side note, the encoder will respect the ` JsonSerializable ` interface as
134
+ well and will call the ` jsonSerialize ` for objects that implement the interface.
135
+
136
+ ### Using StreamJsonEncoder ###
137
+
138
+ The stream encoder works very similarly to the ` BufferJsonEncoder ` as they
139
+ extend the same abstract class. However, the key difference is in how they
140
+ handle passing the JSON output.
141
+
142
+ The ` StreamJsonEncoder ` accepts a callable as the second constructor argument.
143
+ Whenever JSON needs to be outputted, this callable is called with two arguments,
144
+ the actual string to output and the type of the token to output (which is one
145
+ of the ` JsonToken ` constants).
146
+
147
+ If no callable is passed, the StreamJsonEncoder will simply output the JSON
148
+ using an echo statement. For example:
149
+
150
+ ``` php
151
+ <?php
152
+
153
+ require 'vendor/autoload.php';
154
+
155
+ $encoder = new \Violet\StreamingJsonEncoder\StreamJsonEncoder(['array_value']);
156
+ $encoder->encode();
157
+ ```
158
+
159
+ The ` encode() ` method in ` StreamJsonEncoder ` returns the total number of bytes
160
+ it passed to the output. This encoder makes it convenient, for example, to
161
+ write the JSON to file in a streaming manner. For example:
162
+
163
+ ``` php
164
+ <?php
165
+
166
+ require 'vendor/autoload.php';
167
+
168
+ $fp = fopen('test.json', 'w');
169
+ $encoder = new \Violet\StreamingJsonEncoder\StreamJsonEncoder(
170
+ range(1, 100),
171
+ function ($json) use ($fp) {
172
+ fwrite($fp, $json);
173
+ }
174
+ );
175
+
176
+ $encoder->encode();
177
+ fclose($fp);
178
+ ```
179
+
180
+ ### Using JsonStream ###
181
+
182
+ The stream class provides a PSR-7 compatible ` StreamInterface ` for streaming
183
+ JSON content. It actually uses the ` BufferJsonEncoder ` to do the hard work and
184
+ simply wraps the calls in a stream like fashion.
185
+
186
+ The constructor of ` JsonStream ` either accepts a value to encode as JSON or an
187
+ instance of ` BufferJsonEncoder ` (which allows you to set the encoding options).
188
+ You can then operate on the stream using the methods provided by the PSR-7
189
+ interface. For example:
190
+
191
+ ``` php
192
+ <?php
193
+
194
+ require 'vendor/autoload.php';
195
+
196
+ $iterator = function () {
197
+ foreach (new DirectoryIterator(__DIR__) as $file) {
198
+ yield $file->getFilename();
199
+ }
200
+ };
201
+
202
+ $encoder = (new \Violet\StreamingJsonEncoder\BufferJsonEncoder($iterator))
203
+ ->setOptions(JSON_PRETTY_PRINT);
204
+
205
+ $stream = new \Violet\StreamingJsonEncoder\JsonStream($encoder);
206
+
207
+ while (!$stream->eof()) {
208
+ echo $stream->read(1024 * 8);
209
+ }
210
+ ```
211
+
212
+ For more information about PSR-7 streams, please refer to the [ PSR-7
213
+ documentation] ( http://www.php-fig.org/psr/psr-7/#psrhttpmessagestreaminterface ) .
214
+
215
+ ### How the encoder resolves values ###
216
+
217
+ Since Streaming JSON Encoder only handles values one at a time and tries to
218
+ avoid loading entire data sets into memory at once, there are several
219
+ fundamental differences to how this library handles values compared to
220
+ ` json_encode ` .
221
+
222
+ To determine whether any given value should be encoded as an object or as an
223
+ array, the encoder makes the following decisions:
224
+
225
+ * Only arrays that have keys from 0 to n-1 in that order are encoded as JSON
226
+ arrays. All other arrays are encoded as objects.
227
+ * Any object is encoded as a JSON array if the key of the first value
228
+ returned by iterating over the objects equals to ` 0 ` . All other objects are
229
+ encoded as JSON objects.
230
+
231
+ Additionally, prior to the decision whether to encode an object as an array or
232
+ an object is made, the encoder will attempt to resolve the value as follows:
233
+
234
+ * As long as the processed value is a ` JsonSerializable ` , it will replace the
235
+ processed value with the return value of the ` jsonSerialize() ` method.
236
+ * As long as the processed value is a ` Closure ` , it will be replaced with the
237
+ value returned by invoking the closure in question.
238
+
239
+ Note that it's possible to override the array or object decision by using the
240
+ ` JSON_FORCE_OBJECT ` option.
241
+
242
+ ### JSON encoding options ###
243
+
244
+ Both ` BufferJsonEncoder ` and ` StreamJsonEncoder ` have a method ` setOptions() ` to
245
+ change the JSON encoding options. The accepted options are the same as those
246
+ accepted by ` json_encode() ` function. The encoder still internally uses the
247
+ ` json_encode() ` method to encode other values than arrays or object. A few
248
+ options also have additional effects on the encoders:
51
249
250
+ * Using ` JSON_FORCE_OBJECT ` will force all arrays and values to be encoded
251
+ as JSON objects similar to ` json_encode() ` .
252
+ * Using ` JSON_PRETTY_PRINT ` causes the encoder to output whitespace to make
253
+ a more readable output. The indentation used can be changed using the
254
+ method ` setIndent() ` which accepts either a string argument to use as the
255
+ indent or an integer to indicate the number of spaces.
256
+ * Using ` JSON_PARTIAL_OUTPUT_ON_ERROR ` will cause the encoder to continue the
257
+ output despite encoding errors. Otherwise the encoding will halt and the
258
+ encoder will throw an ` EncodingException ` .
52
259
53
260
## Credits ##
54
261
0 commit comments