vcn / pipette
轻松从JSON中提取所需内容。
Requires
- php: ^8.1
- ext-json: *
Requires (Dev)
- friends-of-phpspec/phpspec-code-coverage: ^6.0
- justinrainbow/json-schema: ^5.2
- phpspec/phpspec: ^7.2
- phpunit/phpunit: ^9.5
- vcn/enum: ^1.0
Suggests
- justinrainbow/json-schema: To validate against JSON Schemas.
- vcn/enum: To extract Vcn\Lib\Enum values.
This package is auto-updated.
Last update: 2024-08-30 16:25:37 UTC
README
轻松从JSON中提取所需内容。
快速入门
composer require vcn/pipette
(从examples/目录)
<?php use Vcn\Pipette\Json; try { $parseInt = function (Json\Value $json) { return $json->int(); }; $parseColor = function (Json\Value $json) use ($parseInt) { $name = $json->field('name')->string(); $category = $json->field('category')->string(); $type = $json->¿field('type')->¿string(); $codeRgba = $json->field('code')->field('rgba')->arrayMap($parseInt); $codeHex = $json->field('code')->field('hex')->string(); return [$name, $category, $type, $codeRgba, $codeHex]; }; $source = file_get_contents(__DIR__ . '/colors.json'); $colors = Json::parse($source)->field('colors')->arrayMap($parseColor); print_r(['colors' => $colors]); } catch (Json\Exception\CantDecode | Json\Exception\AssertionFailed $e) { print_r($e->getMessage()); }
用法
Pipette期望你有一段字符串,你强烈怀疑它代表JSON。你可以要求Pipette解析它
<?php use Vcn\Pipette\Json; $input = <<<JSON { "id": 672, "name": "Jane Doe" } JSON; try { $json = Json::parse($input); } catch (Json\Exception\CantDecode $e) { error_log($e); }
解析可能会失败,但如果成功,你将得到一个Json\Value
。它代表它可能解析的所有可能值,并允许你查询该值
<?php use Vcn\Pipette\Json; $input = <<<JSON { "a": [1,2,3], "b": [4,5,6] } JSON; try { $json = Json::parse($input); $a = $json->field('a'); // Assert this is an object, assert the field 'a' is present, then retrieve it. $b = $json->field('b'); $as = $a->arrayMap( // Assert the 'a' field is an array. function (Json\Value $value) { return $value->int(); // Assert each value in that array is a number and return those numbers as an array of ints. } ); $bs = $b->arrayMap( function (Json\Value $value) { return $value->int(); } ); print_r(array_sum(array_merge($as, $bs))); // 21 } catch (Json\Exception\CantDecode | Json\Exception\AssertionFailed $e) { error_log($e); }
请注意,如果这些断言中的任何一个为假,则会抛出异常。
可选值
许多方法可以用倒问号(¿)前缀。这会导致它们在值为null或对象中不存在字段时也返回null。
在¿field
的情况下,返回的Json\OptionalValue
是一个null安全的变体,其中后续的所有调用都将返回null,如果原始字段是null或不存在。
<?php use Vcn\Pipette\Json; $input = <<<JSON { "a": "some string" } JSON; try { $json = Json::parse($input); // Expect $ to be an object, expect field $.a to be present and expect it to be a string or null: $foo = $json->field('a')->¿string(); // Expect $ to be an object, if $.a is not present return null, otherwise expect field $.a to be a string or null: $bar = $json->¿field('a')->¿string(); print_r([$foo, $bar]); // $.a is present but $.a is not an object, therefore this fails: $baz = $json->¿field('a')->¿field('b')->¿string(); print_r($baz); } catch (Json\Exception\CantDecode | Json\Exception\AssertionFailed $e) { error_log($e); }
联合
如果你期望你的JSON与多个结构之一匹配,你可以使用either
<?php use Vcn\Pipette\Json; $inputA = <<<JSON { "a": "some string" } JSON; $inputB = <<<JSON { "b": 42 } JSON; try { foreach ([$inputA, $inputB] as $input) { $json = Json::parse($input); // With the first input this parser will match its first composite, // with the second input the first composite parser fails and falls back to the second. // In practice you will either coerce these different types or construct members of a sealed trait. $foo = $json->either( function (Json\Value $json) { return $json->field('a')->string(); }, function (Json\Value $json) { return $json->field('b')->int(); } ); print_r($foo); } } catch (Json\Exception\CantDecode | Json\Exception\AssertionFailed $e) { error_log($e); }
参见examples/huttonsrazor.php中的另一个示例。
超出类型的验证
Pipette还提供了一个基本的接口来挂钩更强大的验证方法。目前它支持通过justinrainbow/json-schema进行JSON Schema验证。
想法是你可以定义一个JsonSchemaRepository
作为依赖项,它包含对JsonSchemas
的引用。这些模式可以在解析JSON后,但在你使用pipette将其转换为类型数据之前进行验证。
<?php namespace Vcn\Pipette\Examples; use JsonSchema\Validator; use Vcn\Pipette\Json; use Vcn\Pipette\Json\Validators\JsonSchemaRepository; // Define a dependency. // This looks for schema files inside the current directory. // See the json-schema library to tailor this behaviour. $validator = new Validator(); $baseUri = "file://" . __DIR__; $schemas = new JsonSchemaRepository($validator, $baseUri); try { // Somewhere that has access to this dependency. $parseInt = function (Json\Value $json) { return $json->int(); }; $parseColor = function (Json\Value $json) use ($parseInt) { $name = $json->field('name')->string(); $category = $json->field('category')->string(); $type = $json->¿field('type')->¿string(); $codeRgba = $json->field('code')->field('rgba')->arrayMap($parseInt); $codeHex = $json->field('code')->field('hex')->string(); return [$name, $category, $type, $codeRgba, $codeHex]; }; $input = file_get_contents(__DIR__ . '/colors.json'); $json = $schemas->get('/colors.schema.json')->parse($input); // Use the colors.schema.json schema to first validate the JSON before returning. $colors = $json->apply($parseColor); print_r($colors); } catch (Json\Exception\CantDecode | Json\Exception\AssertionFailed $e) { echo $e->getMessage() . "\n"; }
参见examples/目录中的典型请求解析器设置。
为JSON-like数据使用Pipette
在底层,Pipette简单地包装了由json_decode()
返回的数据,并根据你的查询执行临时的验证。这意味着如果你有与json_decode()
类型同构的数据,你也可以为这些数据使用这个库
<?php use Vcn\Pipette\Json; try { $data = (object)[ 'foo' => 'bar', 'baz' => 123, 'seventeen' => (object)[ 'eighteen', 'nineteen', ] ]; // The object casts are necessary since json_decode produces an stdClass for JSON objects. $json = Json::pretend($data); $bar = $json->field('foo')->string(); print_r($bar); } catch (Json\Exception\AssertionFailed $e) { error_log($e); }
Pipette支持哪些数据?(或php-json
如何表示JSON?)
字符串
int
/float
(JSON数字)布尔值
null
array
(非关联数组,JSON数组)stdClass
(JSON对象)
Pipette对任何其他类型的操作行为是未定义的。
小心!
测试
由phpspec提供支持。phpspec已配置为收集代码覆盖率信息。这需要xdebug或pcov。您也可以禁用代码覆盖率。
# default (using pcov)
php vendor/bin/phpspec run
# xdebug coverage
XDEBUG_MODE=coverage php vendor/bin/phpspec run
# no code coverage
php vendor/bin/phpspec run -c phpspec-nocc.yml