Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.89% covered (success)
97.89%
93 / 95
95.83% covered (success)
95.83%
23 / 24
CRAP
0.00% covered (danger)
0.00%
0 / 1
Arr
97.89% covered (success)
97.89%
93 / 95
95.83% covered (success)
95.83%
23 / 24
56
0.00% covered (danger)
0.00%
0 / 1
 isArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 toArray
81.82% covered (success)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
7.29
 isNumeric
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isAssoc
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 exists
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 key
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 collapse
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 flatten
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
6
 divide
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 slice
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 split
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 join
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 prepend
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 pull
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 sort
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 sortDesc
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 ksort
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 ksortDesc
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 usort
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 uksort
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 map
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 trim
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 filter
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 make
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Utils;
16
17use ArrayAccess;
18/**
19 * Pop utils array helper class
20 *
21 * @category   Pop
22 * @package    Pop\Utils
23 * @author     Nick Sagona, III <nick@popphp.org>
24 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
25 * @license    https://www.popphp.org/license     New BSD License
26 * @version    3.0.0
27 */
28class Arr
29{
30
31    /**
32     * Check if the value is an array-like (array-accessible) value
33     *
34     * @param  mixed $value
35     * @return bool
36     */
37    public static function isArray(mixed $value): bool
38    {
39        return (is_array($value) || ($value instanceof ArrayAccess));
40    }
41
42    /**
43     * Resolve an array-like value into a plain array
44     *
45     * @param  mixed $value
46     * @return array
47     */
48    public static function toArray(mixed $value): array
49    {
50        if (is_array($value)) {
51            return $value;
52        } else if ($value instanceof AbstractArray) {
53            return $value->toArray();
54        } else if (is_object($value) && method_exists($value, 'toArray')) {
55            return $value->toArray();
56        } else if ($value instanceof \ArrayObject) {
57            return (array)$value;
58        } else if ($value instanceof \Traversable) {
59            return iterator_to_array($value);
60        }
61
62        return [];
63    }
64
65    /**
66     * Check if the value is a numeric (non-associative) array
67     *
68     * @param  array $array
69     * @return bool
70     */
71    public static function isNumeric(array $array): bool
72    {
73        return array_is_list($array);
74    }
75
76    /**
77     * Check if the value is an associative (non-numeric) array
78     *
79     * @param  array $array
80     * @return bool
81     */
82    public static function isAssoc(array $array): bool
83    {
84        return !array_is_list($array);
85    }
86
87    /**
88     * Check if the key value exists in the array
89     *
90     * @param  array|ArrayAccess $array
91     * @param  string|int        $key
92     * @return bool
93     */
94    public static function exists(array|ArrayAccess $array, string|int $key): bool
95    {
96        if ($array instanceof ArrayAccess) {
97            return $array->offsetExists($key);
98        } else {
99            return array_key_exists($key, $array);
100        }
101    }
102
103    /**
104     * Return the key in the array based on the first position of the value
105     *
106     * @param  array|AbstractArray $array
107     * @param  string|int          $value
108     * @param  bool                $strict
109     * @return mixed
110     */
111    public static function key(array|AbstractArray $array, string|int $value, bool $strict = false): mixed
112    {
113        if ($array instanceof ArrayAccess) {
114            $array = $array->toArray();
115        }
116
117        return array_search($value, $array, $strict);
118    }
119
120    /**
121     * Collapse an array of arrays
122     *
123     * @param  array|AbstractArray $array
124     * @return array
125     */
126    public static function collapse(array|AbstractArray $array): array
127    {
128        $collapsed = [];
129
130        foreach ($array as $values) {
131            if ($values instanceof AbstractArray) {
132                $values = $values->toArray();
133            } else if (!is_array($values)) {
134                continue;
135            }
136            $collapsed[] = $values;
137        }
138
139        return array_merge([], ...$collapsed);
140    }
141
142    /**
143     * Flatten a multi-dimensional array
144     *
145     * @param  array|AbstractArray $array
146     * @param  int|float           $depth
147     * @return array
148     */
149    public static function flatten(array|AbstractArray $array, int|float $depth = INF): array
150    {
151        $flattened = [];
152
153        foreach ($array as $value) {
154            if ($value instanceof AbstractArray) {
155                $value = $value->toArray();
156            }
157
158            if (!is_array($value)) {
159                $flattened[] = $value;
160            } else {
161                $values = ($depth === 1) ? array_values($value) : static::flatten($value, $depth - 1);
162                foreach ($values as $val) {
163                    $flattened[] = $val;
164                }
165            }
166        }
167
168        return $flattened;
169    }
170
171    /**
172     * Divide the array in an array of keys and values
173     *
174     * @param  array|AbstractArray $array
175     * @return array
176     */
177    public static function divide(array|AbstractArray $array): array
178    {
179        $array = static::toArray($array);
180        return [array_keys($array), array_values($array)];
181    }
182
183    /**
184     * Return a slice of the array
185     *
186     * @param  array|AbstractArray $array
187     * @param  int                 $limit
188     * @param  int                 $offset
189     * @return array
190     */
191    public static function slice(array|AbstractArray $array, int $limit, int $offset = 0): array
192    {
193        $array = static::toArray($array);
194
195        return (($limit < 0) && ($offset == 0)) ?
196            array_slice($array, $limit, abs($limit)) : array_slice($array, $offset, $limit);
197    }
198
199    /**
200     * Split a string into an array
201     *
202     * @param  string $string
203     * @param  string $separator
204     * @param  ?int    $limit
205     * @return array
206     */
207    public static function split(string $string, string $separator = '', ?int $limit = null): array
208    {
209        if (empty($separator)) {
210            if ($limit === null) {
211                $limit = 1;
212            }
213            return str_split($string, $limit);
214        } else {
215            if ($limit === null) {
216                $limit = PHP_INT_MAX;
217            }
218            return explode($separator, $string, $limit);
219        }
220    }
221
222    /**
223     * Join the array values into a string
224     *
225     * @param  array|AbstractArray $array
226     * @param  string              $glue
227     * @param  string              $finalGlue
228     * @return string
229     */
230    public static function join(array|AbstractArray $array, string $glue, string $finalGlue = ''): string
231    {
232        $array = static::toArray($array);
233
234        if ($finalGlue === '') {
235            return implode($glue, $array);
236        }
237
238        if (count($array) == 0) {
239            return '';
240        }
241
242        if (count($array) == 1) {
243            return end($array);
244        }
245
246        $finalItem = array_pop($array);
247
248        return implode($glue, $array) . $finalGlue . $finalItem;
249    }
250
251    /**
252     * Prepend value to the array
253     *
254     * @param  array|AbstractArray $array
255     * @param  mixed               $value
256     * @param  mixed               $key
257     * @return array
258     */
259    public static function prepend(array|AbstractArray $array, mixed $value, mixed $key = null): array
260    {
261        $array = static::toArray($array);
262
263        if ($key === null) {
264            array_unshift($array, $value);
265        } else {
266            $array = [$key => $value] + $array;
267        }
268
269        return $array;
270    }
271
272    /**
273     * Pull value from the array and remove it
274     *
275     * @param  array $array
276     * @param  mixed $key
277     * @return mixed
278     */
279    public static function pull(array &$array, mixed $key): mixed
280    {
281        $value = $array[$key] ?? null;
282        unset($array[$key]);
283
284        return $value;
285    }
286
287    /**
288     * Sort array
289     *
290     * @param  array|AbstractArray $array
291     * @param  int                 $flags
292     * @param  bool                $assoc
293     * @param  bool                $descending
294     * @return array
295     */
296    public static function sort(
297        array|AbstractArray $array, int $flags = SORT_REGULAR, bool $assoc = true, bool $descending = false
298    ): array
299    {
300        $array = static::toArray($array);
301        if ($descending) {
302            $func = ($assoc) ? 'arsort' : 'rsort';
303        } else {
304            $func = ($assoc) ? 'asort' : 'sort';
305        }
306
307        $func($array, $flags);
308        return $array;
309    }
310
311    /**
312     * Sort array descending
313     *
314     * @param  array|AbstractArray $array
315     * @param  int                 $flags
316     * @param  bool                $assoc
317     * @return array
318     */
319    public static function sortDesc(array|AbstractArray $array, int $flags = SORT_REGULAR, bool $assoc = true): array
320    {
321        return static::sort($array, $flags, $assoc, true);
322    }
323
324    /**
325     * Sort array by keys
326     *
327     * @param  array|AbstractArray $array
328     * @param  int                 $flags
329     * @param  bool                $descending
330     * @return array
331     */
332    public static function ksort(array|AbstractArray $array, int $flags = SORT_REGULAR, bool $descending = false): array
333    {
334        $array = static::toArray($array);
335
336        if ($descending) {
337            krsort($array, $flags);
338        } else {
339            ksort($array, $flags);
340        }
341
342        return $array;
343    }
344
345    /**
346     * Sort array by keys, descending
347     *
348     * @param  array|AbstractArray $array
349     * @param  int                 $flags
350     * @return array
351     */
352    public static function ksortDesc(array|AbstractArray $array, int $flags = SORT_REGULAR): array
353    {
354        return static::ksort($array, $flags, true);
355    }
356
357    /**
358     * Sort array by user-defined callback
359     *
360     * @param  array|AbstractArray $array
361     * @param  mixed               $callback
362     * @param  bool                $assoc
363     * @return array
364     */
365    public static function usort(array|AbstractArray $array, mixed $callback, bool $assoc = true): array
366    {
367        $array = static::toArray($array);
368
369        if ($assoc) {
370            uasort($array, $callback);
371        } else {
372            usort($array, $callback);
373        }
374
375        return $array;
376    }
377
378    /**
379     * Sort array by user-defined callback using keys
380     *
381     * @param  array|AbstractArray $array
382     * @param  mixed               $callback
383     * @return array
384     */
385    public static function uksort(array|AbstractArray $array, mixed $callback): array
386    {
387        $array = static::toArray($array);
388
389        uksort($array, $callback);
390
391        return $array;
392    }
393
394    /**
395     * Execute a callable over the values of the array
396     *
397     * @param  array|AbstractArray $array
398     * @param  mixed               $callback
399     * @return array
400     */
401    public static function map(array|AbstractArray $array, mixed $callback): array
402    {
403        $array = static::toArray($array);
404
405        return array_map($callback, $array);
406    }
407
408    /**
409     * Trim extra whitespace in the array values
410     *
411     * @param  array|AbstractArray $array
412     * @return array
413     */
414    public static function trim(array|AbstractArray $array): array
415    {
416        $array = static::toArray($array);
417
418        return array_map('trim', $array);
419    }
420
421    /**
422     * Execute a filter callback over the values of the array
423     *
424     * @param  array|AbstractArray $array
425     * @param  mixed               $callback
426     * @param  int   $mode
427     * @return array
428     */
429    public static function filter(array|AbstractArray $array, mixed $callback = null, int $mode = ARRAY_FILTER_USE_BOTH): array
430    {
431        $array = static::toArray($array);
432
433        return array_filter($array, $callback, $mode);
434    }
435
436    /**
437     * Force value to be any array (if it is not one already)
438     *
439     * @param  mixed $value
440     * @return array
441     */
442    public static function make(mixed $value): array
443    {
444        return is_array($value) ? $value : [$value];
445    }
446
447}