From f051ff57c0e932817625cf5be5ee3b526c69e433 Mon Sep 17 00:00:00 2001 From: Filip Halaxa Date: Sat, 23 Nov 2024 12:57:14 +0100 Subject: [PATCH] Readme update --- README.md | 93 ++++++++++++++++++++++++++++++++++-------- src/RecursiveItems.php | 4 +- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 64c4b4e..78799a6 100644 --- a/README.md +++ b/README.md @@ -320,25 +320,51 @@ foreach ($fruits as $key => $value) { ``` -### Recursive iteration (BETA) -Recursive iteration can be enabled via `recursive` option set to `true`. -Every JSON iterable that JSON Machine encounters will then be yielded as an instance of `NestedIterator`. -No JSON array or object will be materialized and kept in memory. -The only PHP values you get materialized will be scalar values. -Let's see an example with many, many users with many, many friends +### Recursive iteration +Use `RecursiveItems` instead of `Items`. +When `RecursiveItems` encounters a list or dict in the JSON, it returns a new instance of `RecursiveItems` +which can then be iterated over and the cycle repeats. +Thus, it never returns a PHP array or object, but only either scalar values or `RecursiveItems`. +No JSON vector will ever be fully loaded into memory at once. +This feature is advantageous when the JSON has a complex structure +that is difficult or even impossible to iterate over with just `Items` and JSON pointers. + +Let's see an example with many, many users with many, many friends: +```json +[ + { + "username": "user", + "e-mail": "user@example.com", + "friends": [ + { + "username": "friend1", + "e-mail": "friend1@example.com" + }, + { + "username": "friend2", + "e-mail": "friend2@example.com" + } + ] + } +] +``` ```php true]); -foreach ($users as $user) { // $user instanceof Traversable, not an array/object - foreach ($user as $userField => $userValue) { - if ($userField === 'friends') { - foreach ($userValue as $friend) { // $userValue instanceof Traversable, not an array/object - foreach ($friend as $friendField => $friendValue) { // $friend instanceof Traversable, not an array/object - // do whatever you want here +use JsonMachine\RecursiveItems + +$users = RecursiveItems::fromFile('users.json'); +foreach ($users as $user) { + /** @var $user RecursiveItems */ + foreach ($user as $field => $value) { + if ($field === 'friends') { + /** @var $value RecursiveItems */ + foreach ($value as $friend) { + /** @var $friend RecursiveItems */ + foreach ($friend as $friendField => $friendValue) { + $friendField == 'username'; + $friendValue == 'friend1'; } } } @@ -351,6 +377,42 @@ foreach ($users as $user) { // $user instanceof Traversable, not an array/object > JSON Machine must iterate it the background to be able to read next value. > Such an attempt will result in closed generator exception. +#### Convenience methods of `RecursiveItems` +- `toArray(): array` +If you are sure that a certain instance of RecursiveItems is pointing to a memory-manageable data structure +(for example, $friend), you can call `$friend->toArray()`, and the item will materialize into a PHP array. + +- `advanceToKey(int|string $key): scalar|RecursiveItems` +When searching for a specific key in a collection (for example, `$user["friends"]`), +you do not need to use a loop and a condition to search for it. +Instead, you can simply call `$user->advanceToKey("friends")`. +It will iterate for you and return the value at this key. + +The previous example could thus be simplified as follows: +```php +advanceToKey('friends') as $friend) { + /** @var $friend RecursiveItems */ + $friendArray = $friend->toArray(); + $friendArray['username'] == 'friend1'; + } +} +``` + +#### Also `RecursiveItems implements \RecursiveIterator` +So you can use for example PHP's builtin tools to work over `\RecursiveIterator` like those: + +- [RecursiveCallbackFilterIterator](https://www.php.net/manual/en/class.recursivecallbackfilteriterator.php) +- [RecursiveFilterIterator](https://www.php.net/manual/en/class.recursivefilteriterator.php) +- [RecursiveRegexIterator](https://www.php.net/manual/en/class.recursiveregexiterator.php) +- [RecursiveTreeIterator](https://www.php.net/manual/en/class.recursivetreeiterator.php) + ### What is JSON Pointer anyway? It's a way of addressing one item in JSON document. See the [JSON Pointer RFC 6901](https://tools.ietf.org/html/rfc6901). @@ -378,7 +440,6 @@ Some examples: Options may change how a JSON is parsed. Array of options is the second parameter of all `Items::from*` functions. Available options are: - `pointer` - A JSON Pointer string that tells which part of the document you want to iterate. -- `recursive` - Bool. Any JSON array/object the parser hits will not be decoded but served lazily as a `Traversable`. Default `false`. - `decoder` - An instance of `ItemDecoder` interface. - `debug` - `true` or `false` to enable or disable the debug mode. When the debug mode is enabled, data such as line, column and position in the document are available during parsing or in exceptions. Keeping debug disabled adds slight diff --git a/src/RecursiveItems.php b/src/RecursiveItems.php index bee99df..e8895be 100644 --- a/src/RecursiveItems.php +++ b/src/RecursiveItems.php @@ -156,9 +156,9 @@ public function getChildren(): ?\RecursiveIterator * Finds the desired key on this level and returns its value. * It moves the internal cursor to it so subsequent calls to self::current() returns the same value. * - * @param $key + * @param string|int $key * - * @return mixed + * @return scalar|self * * @throws JsonMachineException when the key is not found on this level */