紫色 / 流式JSON编码器
库,用于逐块迭代编码大型JSON文档
Requires
- php: >=5.6.0
- psr/http-message: ^1.0
README
流式JSON编码器 是一个PHP库,提供一系列类以帮助以流式方式编码JSON,即允许你逐块编码JSON文档,而不是一次性编码整个文档。与内置的 json_encode
函数相比,有两个主要优点
- 你不需要将整个数据集加载到内存中,因为编码器支持迭代数组和任何类型的迭代器,例如生成器。
- 你也不需要将整个结果JSON文档加载到内存中,因为JSON文档将按值逐个编码,并且可以分块输出编码文档。
换句话说,当需要处理可能占用太多内存处理的大型数据集时,流式JSON编码器可以提供最大的好处。
为了提高互操作性,该库还提供与PSR-7兼容的流,用于框架和HTTP请求。
API文档可在以下位置找到: http://violet.riimu.net/api/streaming-json-encoder/
要求
- 最低支持的PHP版本是5.6
- 该库依赖于以下外部PHP库
- psr/http-message (
^1.0
)
- psr/http-message (
安装
使用Composer安装
安装此库最简单的方法是使用Composer处理你的依赖关系。要使用Composer安装此库,只需按照以下两个步骤操作
-
通过在你的项目根目录中运行Composer 命令行安装 来获取
composer.phar
。 -
运行安装脚本后,你应该在项目根目录中拥有
composer.phar
文件,并且可以运行以下命令php composer.phar require "violet/streaming-json-encoder:^1.1"
通过Composer安装此库后,你可以通过包含Composer在安装过程中生成的 vendor/autoload.php
文件来加载库。
将库作为依赖项添加
如果你已经熟悉如何使用Composer,你可以通过将以下 composer.json
文件添加到你的项目中,并运行 composer install
命令来将库作为依赖项添加。
{ "require": { "violet/streaming-json-encoder": "^1.1" } }
手动安装
如果你不希望使用Composer加载库,你也可以通过下载 最新版本 并将 src
文件夹提取到你的项目中来自动安装库。然后,你可以包含提供的 src/autoload.php
文件来加载库类。
请注意,使用Composer还会自动下载其他所需的PHP库。如果你手动安装此库,你还需要使这些其他所需的库可用。
用法
此库通过类 BufferJsonEncoder
、StreamJsonEncoder
和PSR-7兼容的流 JsonStream
提供了三种主要不同的使用方式。
使用 BufferJsonEncoder
缓冲编码器在您需要以不涉及传递回调来处理生成的JSON的方式生成JSON文档时非常有用。
使用BufferJsonEncoder
的最简单方法是用要编码的JSON值实例化它,并调用encode()
方法以将整个输出作为字符串返回。
<?php require 'vendor/autoload.php'; $encoder = new \Violet\StreamingJsonEncoder\BufferJsonEncoder(['array_value']); echo $encoder->encode();
然而,使用此编码器的最有用方法是将其用作迭代器。由于编码器实现了Iterator
接口,您可以使用foreach循环简单地遍历生成的JSON。
<?php require 'vendor/autoload.php'; $encoder = new \Violet\StreamingJsonEncoder\BufferJsonEncoder(range(0, 10)); foreach ($encoder as $string) { echo $string; }
值得注意的是,编码器支持值迭代器。此外,传递给编码器的任何闭包也将被调用,并使用其返回值作为值。前面的示例也可以写成:
<?php require 'vendor/autoload.php'; $encoder = new \Violet\StreamingJsonEncoder\BufferJsonEncoder(function () { for ($i = 0; $i <= 10; $i++) { yield $i; } }); foreach ($encoder as $string) { echo $string; }
顺便提一下,编码器还将尊重JsonSerializable
接口,并调用实现该接口的对象的jsonSerialize
方法。
使用StreamJsonEncoder
流编码器与BufferJsonEncoder
非常相似,因为它们扩展了相同的抽象类。然而,它们处理传递JSON输出的关键区别在于。
StreamJsonEncoder
接受一个可调用的作为第二个构造函数参数。每当需要输出JSON时,此可调用将使用两个参数调用:实际要输出的字符串和要输出的标记的类型(它是JsonToken
常量之一)。
如果没有传递可调用,StreamJsonEncoder将简单地使用echo语句输出JSON。例如:
<?php require 'vendor/autoload.php'; $encoder = new \Violet\StreamingJsonEncoder\StreamJsonEncoder(['array_value']); $encoder->encode();
StreamJsonEncoder
中的encode()
方法返回它传递给输出的总字节数。此编码器使得以流式方式将JSON写入文件变得方便。例如:
<?php require 'vendor/autoload.php'; $fp = fopen('test.json', 'wb'); $encoder = new \Violet\StreamingJsonEncoder\StreamJsonEncoder( range(1, 100), function ($json) use ($fp) { fwrite($fp, $json); } ); $encoder->encode(); fclose($fp);
使用JsonStream
该流类提供了一个与PSR-7兼容的StreamInterface
,用于流式传输JSON内容。它实际上使用BufferJsonEncoder
来完成艰苦的工作,并以流的方式包装调用。
JsonStream
的构造函数接受一个要编码为JSON的值或BufferJsonEncoder
的实例(允许您设置编码选项)。然后,您可以使用PSR-7接口提供的方法对流进行操作。例如:
<?php require 'vendor/autoload.php'; $iterator = function () { foreach (new DirectoryIterator(__DIR__) as $file) { yield $file->getFilename(); } }; $encoder = (new \Violet\StreamingJsonEncoder\BufferJsonEncoder($iterator)) ->setOptions(JSON_PRETTY_PRINT); $stream = new \Violet\StreamingJsonEncoder\JsonStream($encoder); while (!$stream->eof()) { echo $stream->read(1024 * 8); }
有关PSR-7流的更多信息,请参阅PSR-7文档。
编码器如何解析值
在许多方面,流式JSON编码器旨在作为json_encode()
的替代品。然而,由于编码器旨在处理大型数据集,它在处理对象和数组方面有一些显著的不同。
首先,为了确定如何编码对象,编码器将尝试以下方式解析对象值
- 对于任何实现
JsonSerializable
的对象,将调用实现的jsonSerialize()
方法,并使用返回值代替。 - 将调用任何
Closure
,并使用返回值代替。但是,不以此方式调用任何其他可调用的。
返回值将循环,直到无法进一步解析。之后,将决定是否将数组或对象编码为数组或对象。使用的逻辑如下
- 任何空数组或键从0到n-1按顺序排列的数组都编码为JSON数组。所有其他数组都编码为JSON对象。
- 如果对象实现
Traversable
,并且它返回一个整数0
作为第一个键或根本不返回任何值,则将其编码为JSON数组(不考虑其他键)。所有其他实现Traversable
的对象都编码为JSON对象。 - 任何其他对象,无论是空的还是具有什么键,都编码为JSON对象。
注意,但是,如果使用了JSON编码选项JSON_FORCE_OBJECT
,所有对象和数组都将被编码为JSON对象。
注意,所有对象都通过foreach
语句遍历。这意味着所有Traversable
对象都使用迭代器返回的值进行编码。对于其他对象,这意味着使用公共属性(按照默认迭代行为)。
所有其他值(即null、布尔值、数字和字符串)的处理方式与json_encode()
相同(实际上,它用于编码这些值)。
JSON编码选项
Both BufferJsonEncoder
和 StreamJsonEncoder
都有一个setOptions()
方法来更改JSON编码选项。接受的选项与json_encode()
函数接受的选项相同。编码器仍然内部使用json_encode()
方法来编码数组或对象以外的值。一些选项也对编码器有额外的效果
- 使用
JSON_FORCE_OBJECT
将强制所有数组和对象以与json_encode()
类似的方式编码。 - 使用
JSON_PRETTY_PRINT
会导致编码器输出空格以使输出更易读。可以使用setIndent()
方法更改使用的缩进,该方法接受一个字符串参数作为缩进,或者一个整数来表示空格的数量。 - 使用
JSON_PARTIAL_OUTPUT_ON_ERROR
会导致编码器在编码错误的情况下继续输出。否则,编码将停止,编码器将抛出EncodingException
。
致谢
本库版权所有(c)2017-2022 Riikka Kalliomäki。
请参阅LICENSE以获取许可和复制信息。