xp-forge/json

读取和写入各种输入源中的JSON

v5.1.0 2024-03-24 11:41 UTC

README

Build status on GitHub XP Framework Mdodule BSD Licence Requires PHP 7.0+ Supports PHP 8.0+ Latest Stable Version

读取和写入各种输入源中的JSON。

示例

可以使用一个Input实现来从字符串中读取

// Strings
$value= Json::read('"Test"');

// Input
$in= new FileInput(new File('input.json'));
$in= new StringInput('{"Hello": "World"}');
$in= new StreamInput(new SocketInputStream(...));

$value= Json::read($in);

可以写入字符串或使用一个Output实现

// Strings
$json= Json::of('Test');

// Output
$out= new FileOutput(new File('output.json'));
$out= new StreamOutput(new SocketOuputStream(...));

Json::write($value, $out);

格式化输出

要更改输出格式,请将一个Format实例传递给输出构造函数。可用的格式有

  • DenseFormat($options):最适合网络I/O,没有无意义的空白,如果没有提供则默认,可以通过Format::dense($options= ~Format::ESCAPE_SLASHES)访问。
  • WrappedFormat($indent, $options):包装第一级数组以及所有对象,在逗号和冒号后面使用空白。一个使用4个空格缩进且默认不转义正斜杠的此格式实例可以通过Format::wrapped($indent= " ", $options= ~Format::ESCAPE_SLASHES)访问。

可以组合使用以下选项

  • Format::ESCAPE_SLASHES:用""转义正斜杠 - 默认行为。
  • Format::ESCAPE_UNICODE:用"\uXXXX"转义Unicode - 默认行为。
  • Format::ESCAPE_ENTITIES:转义XML实体&"<>。默认情况下,这些实体以它们的字面形式表示。
$out= new FileOutput(new File('glue.json'), Format::wrapped());
$out->write([
  'name'    => 'example/package',
  'version' => '1.0.0',
  'require' => [
    'xp-forge/json'     => '^3.0',
    'xp-framework/core' => '^10.0'
  ]
]);

上面的代码将产生以下输出

{
    "name": "example/package",
    "version": "1.0.0'",
    "require": {
        "xp-forge/json": "^3.0",
        "xp-framework/core": "^10.0"
    }
}

顺序处理

顺序处理元素可以节省内存,并在某些情况下提供更好的性能。

读取

您可以使用elements()方法接收一个JSON数组的迭代器。它不会将整个源加载到内存中,然后返回解析后的数组;它会逐个解析数组元素,在遍历过程中产生它们。

$conn= new HttpConnection(...);
$in= new StreamInput($conn->get('/search?q=example&limit=1000')->in());
foreach ($in->elements() as $element) {
  // Process
}

如果您得到一个巨大的对象,您也可以使用pairs()方法顺序处理它。这将逐个解析单个键/值对。

$conn= new HttpConnection(...);
$in= new StreamInput($conn->get('/resources/4711?expand=*')->in());
foreach ($in->pairs() as $key => $value) {
  // Process
}

要检测流中的数据类型(同样,不读取它完全),您可以使用type()方法。

$conn= new HttpConnection(...);
$in= new StreamInput($conn->get($resource)->in());
$type= $in->type();
if ($type->isArray()) {
  // Handle arrays
} else if ($type->isObject()) {
  // Handle objects
} else {
  // Handle primitives
}

写入

要顺序写入数据,您可以使用begin()方法和它返回的流。当源提供一种顺序读取数据的方法时,这很有意义;如果您已经将整个数据放在内存中,使用write()会有相同的效果。

$query= $conn->query('select * from person');

$stream= (new StreamOutput(...))->begin(Types::$ARRAY);
while ($record= $query->next()) {
  $stream->element($record);
}
$stream->close();

由于Stream类实现了Closeable接口,因此它可以用于with语句

$query= $conn->query('select * from person');

with ((new StreamOutput(...))->begin(Types::$ARRAY), function($stream) use($query) {
  while ($record= $query->next()) {
    $stream->element($record);
  }
});

进一步阅读

  • 性能数据。TL;DR:虽然比原生功能慢,但性能开销在毫秒范围内。使用顺序处理,我们在性能和内存方面都有优势。
  • 解析JSON是一场灾难。此库在其自己的测试套件旁边运行此测试套件。