1: | <?php |
2: | /** |
3: | * This file is part of GameQ. |
4: | * |
5: | * GameQ is free software; you can redistribute it and/or modify |
6: | * it under the terms of the GNU Lesser General Public License as published by |
7: | * the Free Software Foundation; either version 3 of the License, or |
8: | * (at your option) any later version. |
9: | * |
10: | * GameQ is distributed in the hope that it will be useful, |
11: | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12: | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13: | * GNU Lesser General Public License for more details. |
14: | * |
15: | * You should have received a copy of the GNU Lesser General Public License |
16: | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17: | */ |
18: | |
19: | namespace GameQ\Helpers\Arr; |
20: | |
21: | use ArrayIterator; |
22: | use Closure; |
23: | use RecursiveArrayIterator; |
24: | use RecursiveIteratorIterator; |
25: | |
26: | /** |
27: | * This helper contains functions to work with arrays. |
28: | * |
29: | * @mixin \GameQ\Helpers\Arr |
30: | * |
31: | * @package GameQ\Helpers |
32: | */ |
33: | trait Recursively |
34: | { |
35: | /** |
36: | * This function is responsible for handling behaivour specific to PHP versions before 8.1. |
37: | * |
38: | * @param array &$data |
39: | * @param RecursiveIteratorIterator $recursiveIterator |
40: | * @param RecursiveArrayIterator $iterator |
41: | * @param Closure $callback |
42: | * @return void |
43: | */ |
44: | protected static function handleArrayIteratorCopyOrReference( |
45: | array &$data, |
46: | RecursiveIteratorIterator $recursiveIterator, |
47: | RecursiveArrayIterator $iterator, |
48: | Closure $callback |
49: | ) { |
50: | // ArrayIterator before PHP 8.1 does use a copy instead of reference |
51: | if (PHP_VERSION_ID < 80100) { |
52: | // Hash the current state of the iterator |
53: | $hashes = static::hashes((array) $iterator); |
54: | |
55: | // Continue with the provided callback |
56: | $callback(); |
57: | |
58: | // Determine if the current iterator has been modified |
59: | if (! empty($diff = array_diff_assoc(static::hashes((array) $iterator), $hashes))) { |
60: | // Determine path to the current iterator |
61: | $path = []; |
62: | for ($depth = 0; $depth < $recursiveIterator->getDepth(); $depth++) { |
63: | $path[] = $recursiveIterator->getSubIterator($depth)->key(); |
64: | } |
65: | |
66: | // Process all modified values |
67: | foreach (array_keys($diff) as $modified) { |
68: | // Write the modified value to the original array |
69: | static::set($data, array_merge($path, [$modified]), $iterator->offsetGet($modified)); |
70: | } |
71: | } |
72: | } else { |
73: | // There is no need to write back any changes when ArrayIterator does use a reference |
74: | $callback(); |
75: | } |
76: | } |
77: | |
78: | protected static function getArrayIteratorCopyOrReference(array &$data, ArrayIterator $arrayIterator) |
79: | { |
80: | if (PHP_VERSION_ID < 80100) { |
81: | // Return the actual array reference |
82: | return $data; |
83: | } else { |
84: | // Return the ArrayIterator's internal reference |
85: | return $arrayIterator->getArrayCopy(); |
86: | } |
87: | } |
88: | } |
89: |