规范化为 JSON¶
规范化器能够将数据结构规范化为 JSON,而无需使用本机json_encode()函数。
使用规范化器而不是本机json_encode()函数有一些好处:
- 将使用默认转换对值进行递归规范化
- 所有注册的变换器将在格式化之前应用于数据
- JSON可以以节省内存的方式流式传输到 PHP 资源
基本用法:
namespace My\App;
$normalizer = (new \CuyZ\Valinor\NormalizerBuilder())
->normalizer(\CuyZ\Valinor\Normalizer\Format::json());
$userAsJson = $normalizer->normalize(
new \My\App\User(
name: 'John Doe',
age: 42,
country: new \My\App\Country(
name: 'France',
countryCode: 'FR',
),
)
);
// `$userAsJson` is a valid JSON string representing the data:
// {"name":"John Doe","age":42,"country":{"name":"France","countryCode":"FR"}}
流式传输到 PHP 资源¶
默认情况下,JSON 规范化器将返回一个表示所给数据的 JSON 字符串。可以将 JSON 数据流式传输到 PHP 资源,而不是获取字符串:
$file = fopen('path/to/some_file.json', 'w');
$normalizer = (new \CuyZ\Valinor\NormalizerBuilder())
->normalizer(\CuyZ\Valinor\Normalizer\Format::json())
->streamTo($file);
$normalizer->normalize(/* … */);
// The file now contains the JSON data
将数据流式传输到 PHP 资源的另一个好处是,在使用生成器时,例如在查询数据库时,它可能会更加节省内存:
// In this example, we assume that the result of the query below is a generator,
// every entry will be yielded one by one, instead of everything being loaded in
// memory at once.
$users = $database->execute('SELECT * FROM users');
$file = fopen('path/to/some_file.json', 'w');
$normalizer = (new \CuyZ\Valinor\NormalizerBuilder())
->normalizer(\CuyZ\Valinor\Normalizer\Format::json())
->streamTo($file);
// Even if there are thousands of users, memory usage will be kept low when
// writing JSON into the file.
$normalizer->normalize($users);
传递json_encode标志¶
默认情况下,JSON 规范化器将仅使用JSON_THROW_ON_ERROR来编码非布尔标量值。在某些用例中,项目可能需要诸如JSON_PRESERVE_ZERO_FRACTION之类的标志。
这可以通过将这些标志传递给JsonNormalizer::withOptions()方法来实现:
namespace My\App;
$normalizer = (new \CuyZ\Valinor\NormalizerBuilder())
->normalizer(\CuyZ\Valinor\Normalizer\Format::json())
->withOptions(\JSON_PRESERVE_ZERO_FRACTION);
$lowerManhattanAsJson = $normalizer->normalize(
new \My\App\Coordinates(
longitude: 40.7128,
latitude: -74.0000
)
);
// `$lowerManhattanAsJson` is a valid JSON string representing the data:
// {"longitude":40.7128,"latitude":-74.0000}
该方法接受以下JSON_*常量表示形式的 int-mask(有关更多信息,请参阅官方文档):
JSON_HEX_QUOTJSON_HEX_TAGJSON_HEX_AMPJSON_HEX_APOSJSON_INVALID_UTF8_IGNOREJSON_INVALID_UTF8_SUBSTITUTEJSON_NUMERIC_CHECKJSON_PRETTY_PRINTJSON_PRESERVE_ZERO_FRACTIONJSON_UNESCAPED_LINE_TERMINATORSJSON_UNESCAPED_SLASHESJSON_UNESCAPED_UNICODE
JSON_THROW_ON_ERROR始终强制执行,因此不被接受。