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; |
20: | |
21: | use Closure; |
22: | use RecursiveArrayIterator; |
23: | use RecursiveIteratorIterator; |
24: | |
25: | /** |
26: | * This helper contains functions to work with arrays. |
27: | * |
28: | * @package GameQ\Helpers |
29: | */ |
30: | class Arr |
31: | { |
32: | use Arr\Recursively; |
33: | |
34: | /** |
35: | * This helper does process each element of the provided array recursively. |
36: | * It does so allowing for modifications to the provided array and without |
37: | * using actual recursive calls. |
38: | * |
39: | * @param array $data |
40: | * @param Closure $callback |
41: | * |
42: | * @return array |
43: | */ |
44: | public static function recursively(array $data, Closure $callback) |
45: | { |
46: | // Initialize the RecursiveArrayIterator for the provided data |
47: | $arrayIterator = new RecursiveArrayIterator($data); |
48: | |
49: | // Configure the Iterator for the RecursiveIterator |
50: | $recursiveIterator = new RecursiveIteratorIterator($arrayIterator); |
51: | |
52: | // Traverse the provided data |
53: | foreach ($recursiveIterator as $key => $value) { |
54: | // Get the current sub iterator with Type hinting |
55: | /** @var RecursiveArrayIterator */ |
56: | $subIterator = $recursiveIterator->getSubIterator(); |
57: | |
58: | // Wrap the implementation to handle PHP < 8.1 behaviour |
59: | static::handleArrayIteratorCopyOrReference( |
60: | $data, |
61: | $recursiveIterator, |
62: | $subIterator, |
63: | function () use ($callback, &$value, $key, $subIterator) { |
64: | // Execute the callback |
65: | $callback($value, $key, $subIterator); |
66: | |
67: | // Update the modified value |
68: | $subIterator->offsetSet($key, $value); |
69: | } |
70: | ); |
71: | } |
72: | |
73: | // Return the processed data |
74: | return static::getArrayIteratorCopyOrReference($data, $arrayIterator); |
75: | } |
76: | |
77: | /** |
78: | * This helper is intended to hash the provided array's values |
79: | * and return it back as key => hash. |
80: | * |
81: | * @param array $array |
82: | * @return array<string|int, string> |
83: | */ |
84: | public static function hashes(array $array) |
85: | { |
86: | $hashes = []; |
87: | |
88: | // Process the provided array |
89: | foreach ($array as $key => $value) { |
90: | // Serialze and hash each value individually |
91: | $hashes[$key] = md5(serialize($value)); |
92: | } |
93: | |
94: | // Return array containing the hashes |
95: | return $hashes; |
96: | } |
97: | |
98: | /** |
99: | * This helper is intended to set a value inside the provided array. |
100: | * |
101: | * @param array &$array |
102: | * @param array $path |
103: | * @param mixed $value |
104: | * @return array |
105: | */ |
106: | public static function set(array &$array, array $path, $value) |
107: | { |
108: | $current = &$array; |
109: | |
110: | // Process the path until the last element |
111: | foreach ($path as $i => $element) { |
112: | // Remove the element from the path |
113: | unset($path[$i]); |
114: | |
115: | // Create missing key |
116: | if (! isset($current[$element])) { |
117: | $current[$element] = []; |
118: | } |
119: | |
120: | // Set current to a reference of next |
121: | $current = &$current[$element]; |
122: | } |
123: | |
124: | // Finally set the value using the last key |
125: | $current = $value; |
126: | |
127: | // Return the current, modified array (level) |
128: | return $array; |
129: | } |
130: | |
131: | /** |
132: | * This helper method is intended to shift the provided arguments to the left. |
133: | * |
134: | * **Example:** foo, bar, baz becomes bar, baz, baz |
135: | * |
136: | * @param mixed &...$args |
137: | * @return void |
138: | */ |
139: | public static function shift(&...$args) |
140: | { |
141: | // Get the array keys to ensure numeric index |
142: | $keys = array_keys($args); |
143: | |
144: | // Iterate the provided arguments keys in order |
145: | foreach ($keys as $i => $key) { |
146: | // Process until the last argument |
147: | if ($i < count($keys) - 1) { |
148: | // Shift next into current |
149: | $args[$key] = $args[$keys[$i + 1]]; |
150: | } |
151: | } |
152: | } |
153: | } |
154: |