紫色/流式JSON编码器

库,用于逐块迭代编码大型JSON文档

v1.1.5 2022-12-09 15:47 UTC

This package is auto-updated.

Last update: 2024-09-12 16:25:52 UTC


README

流式JSON编码器 是一个PHP库,提供一系列类以帮助以流式方式编码JSON,即允许你逐块编码JSON文档,而不是一次性编码整个文档。与内置的 json_encode 函数相比,有两个主要优点

  • 你不需要将整个数据集加载到内存中,因为编码器支持迭代数组和任何类型的迭代器,例如生成器。
  • 你也不需要将整个结果JSON文档加载到内存中,因为JSON文档将按值逐个编码,并且可以分块输出编码文档。

换句话说,当需要处理可能占用太多内存处理的大型数据集时,流式JSON编码器可以提供最大的好处。

为了提高互操作性,该库还提供与PSR-7兼容的流,用于框架和HTTP请求。

API文档可在以下位置找到: http://violet.riimu.net/api/streaming-json-encoder/

CI Scrutinizer codecov Packagist

要求

  • 最低支持的PHP版本是5.6
  • 该库依赖于以下外部PHP库

安装

使用Composer安装

安装此库最简单的方法是使用Composer处理你的依赖关系。要使用Composer安装此库,只需按照以下两个步骤操作

  1. 通过在你的项目根目录中运行Composer 命令行安装 来获取 composer.phar

  2. 运行安装脚本后,你应该在项目根目录中拥有 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库。如果你手动安装此库,你还需要使这些其他所需的库可用。

用法

此库通过类 BufferJsonEncoderStreamJsonEncoder 和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 BufferJsonEncoderStreamJsonEncoder 都有一个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以获取许可和复制信息。