Complex classes like Arrays often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Arrays, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | class Arrays |
||
16 | { |
||
17 | const TREAT_NULL_AS_VALUE = 1; |
||
18 | |||
19 | /** |
||
20 | * Returns true if every element in array satisfies the predicate. |
||
21 | * |
||
22 | * Example: |
||
23 | * <code> |
||
24 | * $array = array(1, 2); |
||
25 | * $all = Arrays::all($array, function ($element) { |
||
26 | * return $element < 3; |
||
27 | * }); |
||
28 | * </code> |
||
29 | * Result: |
||
30 | * <code> |
||
31 | * true |
||
32 | * </code> |
||
33 | * |
||
34 | * @param array $elements |
||
35 | * @param callable $predicate |
||
36 | * @return bool |
||
37 | */ |
||
38 | public static function all(array $elements, $predicate) |
||
39 | { |
||
40 | foreach ($elements as $element) { |
||
41 | if (!Functions::call($predicate, $element)) { |
||
42 | return false; |
||
43 | } |
||
44 | } |
||
45 | return true; |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * This method creates associative array using key and value functions on array elements. |
||
50 | * |
||
51 | * Example: |
||
52 | * <code> |
||
53 | * $array = range(1, 2); |
||
54 | * $map = Arrays::toMap($array, function ($elem) { |
||
55 | * return $elem * 10; |
||
56 | * }, function ($elem) { |
||
57 | * return $elem + 1; |
||
58 | * }); |
||
59 | * </code> |
||
60 | * Result: |
||
61 | * <code> |
||
62 | * Array |
||
63 | * ( |
||
64 | * [10] => 2 |
||
65 | * [20] => 3 |
||
66 | * ) |
||
67 | * </code> |
||
68 | * |
||
69 | * @param array $elements |
||
70 | * @param callable $keyFunction |
||
71 | * @param callable|null $valueFunction |
||
72 | * @return array |
||
73 | */ |
||
74 | public static function toMap(array $elements, $keyFunction, $valueFunction = null) |
||
75 | { |
||
76 | if ($valueFunction == null) { |
||
77 | $valueFunction = Functions::identity(); |
||
78 | } |
||
79 | |||
80 | $keys = array_map($keyFunction, $elements); |
||
81 | $values = array_map($valueFunction, $elements); |
||
82 | return empty($keys) ? array() : array_combine($keys, $values); |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * Returns a new array that is a one-dimensional flattening of the given array. |
||
87 | * |
||
88 | * Example: |
||
89 | * <code> |
||
90 | * $array = array( |
||
91 | * 'names' => array( |
||
92 | * 'john', |
||
93 | * 'peter', |
||
94 | * 'bill' |
||
95 | * ), |
||
96 | * 'products' => array( |
||
97 | * 'cheese', |
||
98 | * array( |
||
99 | * 'natural' => 'milk', |
||
100 | * 'brie' |
||
101 | * ) |
||
102 | * ) |
||
103 | * ); |
||
104 | * $flatten = Arrays::flatten($array); |
||
105 | * </code> |
||
106 | * Result: |
||
107 | * <code> |
||
108 | * Array |
||
109 | * ( |
||
110 | * [0] => john |
||
111 | * [1] => peter |
||
112 | * [2] => bill |
||
113 | * [3] => cheese |
||
114 | * [4] => milk |
||
115 | * [5] => brie |
||
116 | * ) |
||
117 | * </code> |
||
118 | * |
||
119 | * @param array $array |
||
120 | * @return array |
||
121 | */ |
||
122 | public static function flatten(array $array) |
||
123 | { |
||
124 | $return = array(); |
||
125 | array_walk_recursive($array, function ($a) use (&$return) { |
||
126 | $return[] = $a; |
||
127 | }); |
||
128 | return $return; |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * This method returns a key for the given value. |
||
133 | * |
||
134 | * Example: |
||
135 | * <code> |
||
136 | * $array = array( |
||
137 | * 'k1' => 4, |
||
138 | * 'k2' => 'd', |
||
139 | * 'k3' => 0, |
||
140 | * 9 => 'p' |
||
141 | * ); |
||
142 | * $key = Arrays::findKeyByValue($array, 0); |
||
143 | * </code> |
||
144 | * Result: |
||
145 | * <code> |
||
146 | * k3 |
||
147 | * </code> |
||
148 | * |
||
149 | * @param array $elements |
||
150 | * @param string $value |
||
151 | * @return bool|int|string |
||
152 | */ |
||
153 | public static function findKeyByValue(array $elements, $value) |
||
154 | { |
||
155 | if ($value === 0) { |
||
156 | $value = '0'; |
||
157 | } |
||
158 | foreach ($elements as $key => $item) { |
||
159 | if ($item == $value) { |
||
160 | return $key; |
||
161 | } |
||
162 | } |
||
163 | return false; |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * Returns true if at least one element in the array satisfies the predicate. |
||
168 | * |
||
169 | * Example: |
||
170 | * <code> |
||
171 | * $array = array('a', true, 'c'); |
||
172 | * $any = Arrays::any($array, function ($element) { |
||
173 | * return is_bool($element); |
||
174 | * }); |
||
175 | * </code> |
||
176 | * Result: |
||
177 | * <code> |
||
178 | * true |
||
179 | * </code> |
||
180 | * |
||
181 | * @param array $elements |
||
182 | * @param callable $predicate |
||
183 | * @return bool |
||
184 | */ |
||
185 | public static function any(array $elements, $predicate) |
||
186 | { |
||
187 | foreach ($elements as $element) { |
||
188 | if (Functions::call($predicate, $element)) { |
||
189 | return true; |
||
190 | } |
||
191 | } |
||
192 | return false; |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * This method returns the first value in the given array. |
||
197 | * |
||
198 | * Example: |
||
199 | * <code> |
||
200 | * $array = array('one', 'two' 'three'); |
||
201 | * $first = Arrays::first($array); |
||
202 | * </code> |
||
203 | * Result: |
||
204 | * <code>one</code> |
||
205 | * |
||
206 | * @param array $elements |
||
207 | * @return mixed |
||
208 | * @throws InvalidArgumentException |
||
209 | */ |
||
210 | public static function first(array $elements) |
||
211 | { |
||
212 | if (empty($elements)) { |
||
213 | throw new InvalidArgumentException('empty array'); |
||
214 | } |
||
215 | $keys = array_keys($elements); |
||
216 | return $elements[$keys[0]]; |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * This method returns the last value in the given array. |
||
221 | * |
||
222 | * Example: |
||
223 | * <code> |
||
224 | * $array = array('a', 'b', 'c'); |
||
225 | * $last = Arrays::last($array); |
||
226 | * </code> |
||
227 | * Result: |
||
228 | * <code>c</code> |
||
229 | * |
||
230 | * @param array $elements |
||
231 | * @return mixed |
||
232 | * @throws InvalidArgumentException |
||
233 | */ |
||
234 | public static function last(array $elements) |
||
235 | { |
||
236 | if (empty($elements)) { |
||
237 | throw new InvalidArgumentException('empty array'); |
||
238 | } |
||
239 | return end($elements); |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * This method returns the first value or null if array is empty. |
||
244 | * |
||
245 | * Example: |
||
246 | * <code> |
||
247 | * $array = array(); |
||
248 | * $return = Arrays::firstOrNull($array); |
||
249 | * </code> |
||
250 | * Result: |
||
251 | * <code>null</code> |
||
252 | * |
||
253 | * @param array $elements |
||
254 | * @return mixed|null |
||
255 | */ |
||
256 | public static function firstOrNull(array $elements) |
||
257 | { |
||
258 | return empty($elements) ? null : self::first($elements); |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Returns the element for the given key or a default value otherwise. |
||
263 | * |
||
264 | * Example: |
||
265 | * <code> |
||
266 | * $array = array('id' => 1, 'name' => 'john'); |
||
267 | * $value = Arrays::getValue($array, 'name'); |
||
268 | * </code> |
||
269 | * Result: |
||
270 | * <code>john</code> |
||
271 | * |
||
272 | * Example: |
||
273 | * <code> |
||
274 | * $array = array('id' => 1, 'name' => 'john'); |
||
275 | * $value = Arrays::getValue($array, 'surname', '--not found--'); |
||
276 | * </code> |
||
277 | * Result: |
||
278 | * <code>--not found--</code> |
||
279 | * |
||
280 | * @param array $elements |
||
281 | * @param string|int $key |
||
282 | * @param mixed|null $default |
||
283 | * @return mixed|null |
||
284 | */ |
||
285 | public static function getValue(array $elements, $key, $default = null) |
||
286 | { |
||
287 | return isset($elements[$key]) ? $elements[$key] : $default; |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * Returns an array containing only the given keys. |
||
292 | * |
||
293 | * Example: |
||
294 | * <code> |
||
295 | * $array = array('a' => 1, 'b' => 2, 'c' => 3); |
||
296 | * $filtered = Arrays::filterByAllowedKeys($array, array('a', 'b')); |
||
297 | * </code> |
||
298 | * Result: |
||
299 | * <code> |
||
300 | * Array |
||
301 | * ( |
||
302 | * [a] => 1 |
||
303 | * [b] => 2 |
||
304 | * ) |
||
305 | * </code> |
||
306 | * |
||
307 | * @param array $elements |
||
308 | * @param array $allowedKeys |
||
309 | * @return array |
||
310 | */ |
||
311 | public static function filterByAllowedKeys(array $elements, array $allowedKeys) |
||
312 | { |
||
313 | return array_intersect_key($elements, array_flip($allowedKeys)); |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * Filters array by keys using the predicate. |
||
318 | * |
||
319 | * Example: |
||
320 | * <code> |
||
321 | * $array = array('a1' => 1, 'a2' => 2, 'c' => 3); |
||
322 | * $filtered = Arrays::filterByKeys($array, function ($elem) { |
||
323 | * return $elem[0] == 'a'; |
||
324 | * }); |
||
325 | * </code> |
||
326 | * Result: |
||
327 | * <code> |
||
328 | * Array |
||
329 | * ( |
||
330 | * [a1] => 1 |
||
331 | * [b2] => 2 |
||
332 | * ) |
||
333 | * </code> |
||
334 | * |
||
335 | * @param array $elements |
||
336 | * @param callable $predicate |
||
337 | * @return array |
||
338 | */ |
||
339 | public static function filterByKeys(array $elements, $predicate) |
||
340 | { |
||
341 | $allowedKeys = array_filter(array_keys($elements), $predicate); |
||
342 | return self::filterByAllowedKeys($elements, $allowedKeys); |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Group elements in array by result of the given function. If $orderField is set grouped elements will be also sorted. |
||
347 | * |
||
348 | * Example: |
||
349 | * <code> |
||
350 | * $obj1 = new stdClass(); |
||
351 | * $obj1->name = 'a'; |
||
352 | * $obj1->description = '1'; |
||
353 | * |
||
354 | * $obj2 = new stdClass(); |
||
355 | * $obj2->name = 'b'; |
||
356 | * $obj2->description = '2'; |
||
357 | * |
||
358 | * $obj3 = new stdClass(); |
||
359 | * $obj3->name = 'b'; |
||
360 | * $obj3->description = '3'; |
||
361 | * |
||
362 | * $array = array($obj1, $obj2, $obj3); |
||
363 | * $grouped = Arrays::groupBy($array, Functions::extractField('name')); |
||
364 | * </code> |
||
365 | * Result: |
||
366 | * <code> |
||
367 | * Array |
||
368 | * ( |
||
369 | * [a] => Array |
||
370 | * ( |
||
371 | * [0] => stdClass Object |
||
372 | * ( |
||
373 | * [name] => a |
||
374 | * [description] => 1 |
||
375 | * ) |
||
376 | * ) |
||
377 | * [b] => Array |
||
378 | * ( |
||
379 | * [0] => stdClass Object |
||
380 | * ( |
||
381 | * [name] => b |
||
382 | * [description] => 2 |
||
383 | * ) |
||
384 | * [1] => stdClass Object |
||
385 | * ( |
||
386 | * [name] => b |
||
387 | * [description] => 3 |
||
388 | * ) |
||
389 | * ) |
||
390 | * ) |
||
391 | * </code> |
||
392 | * |
||
393 | * @param array $elements |
||
394 | * @param callable $keyFunction |
||
395 | * @param string|null $orderField |
||
396 | * @return array |
||
397 | */ |
||
398 | public static function groupBy(array $elements, $keyFunction, $orderField = null) |
||
399 | { |
||
400 | $map = array(); |
||
401 | if (!empty($orderField)) { |
||
402 | $elements = self::orderBy($elements, $orderField); |
||
403 | } |
||
404 | foreach ($elements as $element) { |
||
405 | $key = Functions::call($keyFunction, $element); |
||
406 | $map[$key][] = $element; |
||
407 | } |
||
408 | return $map; |
||
409 | } |
||
410 | |||
411 | /** |
||
412 | * This method sorts elements in array using order field. |
||
413 | * |
||
414 | * Example: |
||
415 | * <code> |
||
416 | * $obj1 = new stdClass(); |
||
417 | * $obj1->name = 'a'; |
||
418 | * $obj1->description = '1'; |
||
419 | * |
||
420 | * $obj2 = new stdClass(); |
||
421 | * $obj2->name = 'c'; |
||
422 | * $obj2->description = '2'; |
||
423 | * |
||
424 | * $obj3 = new stdClass(); |
||
425 | * $obj3->name = 'b'; |
||
426 | * $obj3->description = '3'; |
||
427 | * |
||
428 | * $array = array($obj1, $obj2, $obj3); |
||
429 | * $sorted = Arrays::orderBy($array, 'name'); |
||
430 | * </code> |
||
431 | * Result: |
||
432 | * <code> |
||
433 | * Array |
||
434 | * ( |
||
435 | * [0] => stdClass Object |
||
436 | * ( |
||
437 | * [name] => a |
||
438 | * [description] => 1 |
||
439 | * ) |
||
440 | * [1] => stdClass Object |
||
441 | * ( |
||
442 | * [name] => b |
||
443 | * [description] => 3 |
||
444 | * ) |
||
445 | * [2] => stdClass Object |
||
446 | * ( |
||
447 | * [name] => c |
||
448 | * [description] => 2 |
||
449 | * ) |
||
450 | * ) |
||
451 | * </code> |
||
452 | * |
||
453 | * @param array $elements |
||
454 | * @param string $orderField |
||
455 | * @return array |
||
456 | */ |
||
457 | public static function orderBy(array $elements, $orderField) |
||
458 | { |
||
459 | usort($elements, function ($a, $b) use ($orderField) { |
||
460 | return $a->$orderField < $b->$orderField ? -1 : 1; |
||
461 | }); |
||
462 | return $elements; |
||
463 | } |
||
464 | |||
465 | /** |
||
466 | * This method maps array keys using the function. |
||
467 | * Invokes the function for each key in the array. Creates a new array containing the keys returned by the function. |
||
468 | * |
||
469 | * Example: |
||
470 | * <code> |
||
471 | * $array = array( |
||
472 | * 'k1' => 'v1', |
||
473 | * 'k2' => 'v2', |
||
474 | * 'k3' => 'v3' |
||
475 | * ); |
||
476 | * $arrayWithNewKeys = Arrays::mapKeys($array, function ($key) { |
||
477 | * return 'new_' . $key; |
||
478 | * }); |
||
479 | * </code> |
||
480 | * Result: |
||
481 | * <code> |
||
482 | * Array |
||
483 | * ( |
||
484 | * [new_k1] => v1 |
||
485 | * [new_k2] => v2 |
||
486 | * [new_k3] => v3 |
||
487 | * ) |
||
488 | * </code> |
||
489 | * |
||
490 | * @param array $elements |
||
491 | * @param callable $function |
||
492 | * @return array |
||
493 | */ |
||
494 | public static function mapKeys(array $elements, $function) |
||
495 | { |
||
496 | $newArray = array(); |
||
497 | foreach ($elements as $oldKey => $value) { |
||
498 | $newKey = Functions::call($function, $oldKey); |
||
499 | $newArray[$newKey] = $value; |
||
500 | } |
||
501 | return $newArray; |
||
502 | } |
||
503 | |||
504 | /** |
||
505 | * This method maps array values using the function. |
||
506 | * Invokes the function for each value in the array. Creates a new array containing the values returned by the function. |
||
507 | * |
||
508 | * Example: |
||
509 | * <code> |
||
510 | * $array = array('k1', 'k2', 'k3'); |
||
511 | * $result = Arrays::map($array, function ($value) { |
||
512 | * return 'new_' . $value; |
||
513 | * }); |
||
514 | * </code> |
||
515 | * Result: |
||
516 | * <code> |
||
517 | * Array |
||
518 | * ( |
||
519 | * [0] => new_k1 |
||
520 | * [1] => new_k2 |
||
521 | * [2] => new_k3 |
||
522 | * ) |
||
523 | * </code> |
||
524 | * |
||
525 | * @param array $elements |
||
526 | * @param callable $function |
||
527 | * @return array |
||
528 | */ |
||
529 | public static function map(array $elements, $function) |
||
530 | { |
||
531 | return array_map($function, $elements); |
||
532 | } |
||
533 | |||
534 | /** |
||
535 | * This method filters array using function. Result contains all elements for which function returns true. |
||
536 | * |
||
537 | * Example: |
||
538 | * <code> |
||
539 | * $array = array(1, 2, 3, 4); |
||
540 | * $result = Arrays::filter($array, function ($value) { |
||
541 | * return $value > 2; |
||
542 | * }); |
||
543 | * </code> |
||
544 | * Result: |
||
545 | * <code> |
||
546 | * Array |
||
547 | * ( |
||
548 | * [2] => 3 |
||
549 | * [3] => 4 |
||
550 | * ) |
||
551 | * </code> |
||
552 | * |
||
553 | * @param array $elements |
||
554 | * @param callable $function |
||
555 | * @return array |
||
556 | */ |
||
557 | public static function filter(array $elements, $function) |
||
558 | { |
||
559 | return array_filter($elements, $function); |
||
560 | } |
||
561 | |||
562 | /** |
||
563 | * This method filter array will remove all values that are blank. |
||
564 | * |
||
565 | * @param array $elements |
||
566 | * @return array |
||
567 | */ |
||
568 | public static function filterNotBlank(array $elements) |
||
569 | { |
||
570 | return array_filter($elements); |
||
571 | } |
||
572 | |||
573 | /** |
||
574 | * Make array from element. Returns the given argument if it's already an array. |
||
575 | * |
||
576 | * Example: |
||
577 | * <code> |
||
578 | * $result = Arrays::toArray('test'); |
||
579 | * </code> |
||
580 | * Result: |
||
581 | * <code> |
||
582 | * Array |
||
583 | * ( |
||
584 | * [0] => test |
||
585 | * ) |
||
586 | * </code> |
||
587 | * |
||
588 | * @param mixed $element |
||
589 | * @return array |
||
590 | */ |
||
591 | public static function toArray($element) |
||
592 | { |
||
593 | return $element ? is_array($element) ? $element : array($element) : array(); |
||
594 | } |
||
595 | |||
596 | /** |
||
597 | * Returns a random element from the given array. |
||
598 | * |
||
599 | * Example: |
||
600 | * <code> |
||
601 | * $array = array('john', 'city', 'small'); |
||
602 | * $rand = Arrays::randElement($array); |
||
603 | * </code> |
||
604 | * Result: <i>rand element from array</i> |
||
605 | * |
||
606 | * @param array $elements |
||
607 | * @return null |
||
608 | */ |
||
609 | public static function randElement($elements) |
||
610 | { |
||
611 | return $elements ? $elements[array_rand($elements)] : null; |
||
612 | } |
||
613 | |||
614 | /** |
||
615 | * Returns a new array with $keys as array keys and $values as array values. |
||
616 | * |
||
617 | * Example: |
||
618 | * <code> |
||
619 | * $keys = array('id', 'name', 'surname'); |
||
620 | * $values = array(1, 'john', 'smith'); |
||
621 | * $combined = Arrays::combine($keys, $values); |
||
622 | * </code> |
||
623 | * Result: |
||
624 | * <code> |
||
625 | * Array |
||
626 | * ( |
||
627 | * [id] => 1 |
||
628 | * [name] => john |
||
629 | * [surname] => smith |
||
630 | * ) |
||
631 | * </code> |
||
632 | * |
||
633 | * @param array $keys |
||
634 | * @param array $values |
||
635 | * @return array |
||
636 | */ |
||
637 | public static function combine(array $keys, array $values) |
||
638 | { |
||
639 | if (!empty($keys) && !empty($values)) { |
||
640 | return array_combine($keys, $values); |
||
641 | } |
||
642 | return array(); |
||
643 | } |
||
644 | |||
645 | /** |
||
646 | * Checks is key exists in an array. |
||
647 | * |
||
648 | * Example: |
||
649 | * <code> |
||
650 | * $array = array('id' => 1, 'name' => 'john'); |
||
651 | * $return = Arrays::keyExists($array, 'name'); |
||
652 | * </code> |
||
653 | * Result: |
||
654 | * <code>true</code> |
||
655 | * |
||
656 | * @param array $elements |
||
657 | * @param string|int $key |
||
658 | * @return bool |
||
659 | */ |
||
660 | public static function keyExists(array $elements, $key) |
||
661 | { |
||
662 | return array_key_exists($key, $elements); |
||
663 | } |
||
664 | |||
665 | /** |
||
666 | * Method to reduce an array elements to a string value. |
||
667 | * |
||
668 | * @param array $elements |
||
669 | * @param callable $function |
||
670 | * @return mixed |
||
671 | */ |
||
672 | public static function reduce(array $elements, $function) |
||
673 | { |
||
674 | return array_reduce($elements, $function); |
||
675 | } |
||
676 | |||
677 | /** |
||
678 | * Finds first element in array that is matched by function. |
||
679 | * Returns null if element was not found. |
||
680 | * |
||
681 | * @param array $elements |
||
682 | * @param callable $function |
||
683 | * @return mixed |
||
684 | */ |
||
685 | public static function find(array $elements, $function) |
||
686 | { |
||
687 | foreach ($elements as $element) { |
||
688 | if ($function($element)) { |
||
689 | return $element; |
||
690 | } |
||
691 | } |
||
692 | return null; |
||
693 | } |
||
694 | |||
695 | /** |
||
696 | * Computes the intersection of arrays. |
||
697 | * |
||
698 | * @param array $array1 |
||
699 | * @param array $array2 |
||
700 | * @return array |
||
701 | */ |
||
702 | public static function intersect(array $array1, array $array2) |
||
703 | { |
||
704 | return array_intersect($array1, $array2); |
||
705 | } |
||
706 | |||
707 | /** |
||
708 | * Setting nested value. |
||
709 | * |
||
710 | * Example: |
||
711 | * <code> |
||
712 | * $array = array(); |
||
713 | * Arrays::setNestedValue($array, array('1', '2', '3'), 'value'); |
||
714 | * </code> |
||
715 | * Result: |
||
716 | * <code> |
||
717 | * Array |
||
718 | * ( |
||
719 | * [1] => Array |
||
720 | * ( |
||
721 | * [2] => Array |
||
722 | * ( |
||
723 | * [3] => value |
||
724 | * ) |
||
725 | * ) |
||
726 | * ) |
||
727 | * </code> |
||
728 | * |
||
729 | * @param array $array |
||
730 | * @param array $keys |
||
731 | * @param $value |
||
732 | */ |
||
733 | public static function setNestedValue(array &$array, array $keys, $value) |
||
734 | { |
||
735 | $current = &$array; |
||
736 | foreach ($keys as $key) { |
||
737 | if (!isset($current[$key])) { |
||
738 | $current[$key] = array(); |
||
739 | } |
||
740 | $current = &$current[$key]; |
||
741 | } |
||
742 | $current = $value; |
||
743 | } |
||
744 | |||
745 | /** |
||
746 | * Returns a new array with is sorted using given comparator. |
||
747 | * The comparator function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second. |
||
748 | * To obtain comparator one may use <code>Comparator</code> class (for instance <code>Comparator::natural()</code> which yields ordering using comparison operators). |
||
749 | * |
||
750 | * Example: |
||
751 | * <code> |
||
752 | * class Foo |
||
753 | * { |
||
754 | * private $value; |
||
755 | * function __construct($value) |
||
756 | * { |
||
757 | * $this->value = $value; |
||
758 | * } |
||
759 | * public function getValue() |
||
760 | * { |
||
761 | * return $this->value; |
||
762 | * } |
||
763 | * } |
||
764 | * $values = array(new Foo(1), new Foo(3), new Foo(2)); |
||
765 | * $sorted = Arrays::sort($values, Comparator::compareBy('getValue()')); |
||
766 | * </code> |
||
767 | * Result: |
||
768 | * <code> |
||
769 | * Array |
||
770 | * ( |
||
771 | * [0] => class Foo (1) { |
||
772 | * private $value => int(1) |
||
773 | * } |
||
774 | * [1] => class Foo (1) { |
||
775 | * private $value => int(2) |
||
776 | * } |
||
777 | * [2] => class Foo (1) { |
||
778 | * private $value => int(3) |
||
779 | * } |
||
780 | * ) |
||
781 | * </code> |
||
782 | * |
||
783 | * @param array $array |
||
784 | * @param $comparator |
||
785 | * @return array sorted according to the comparator |
||
786 | * @throws InvalidArgumentException |
||
787 | */ |
||
788 | public static function sort(array $array, $comparator) |
||
789 | { |
||
790 | usort($array, $comparator); |
||
791 | return $array; |
||
792 | } |
||
793 | |||
794 | /** |
||
795 | * Return nested value when found, otherwise return <i>null</i> value. |
||
796 | * |
||
797 | * Example: |
||
798 | * <code> |
||
799 | * $array = array('1' => array('2' => array('3' => 'value'))); |
||
800 | * $value = Arrays::getNestedValue($array, array('1', '2', '3')); |
||
801 | * </code> |
||
802 | * Result: |
||
803 | * <code> |
||
804 | * value |
||
805 | * </code> |
||
806 | * |
||
807 | * @param array $array |
||
808 | * @param array $keys |
||
809 | * @return array|mixed|null |
||
810 | */ |
||
811 | public static function getNestedValue(array $array, array $keys) |
||
812 | { |
||
813 | foreach ($keys as $key) { |
||
814 | $array = self::getValue(self::toArray($array), $key); |
||
815 | if (!$array) { |
||
816 | return $array; |
||
817 | } |
||
818 | } |
||
819 | return $array; |
||
820 | } |
||
821 | |||
822 | /** |
||
823 | * @deprecated |
||
824 | * @param array $array |
||
825 | * @param array $keys |
||
826 | */ |
||
827 | public static function removeNestedValue(array &$array, array $keys) |
||
828 | { |
||
829 | trigger_error('Use Arrays::removeNestedKey instead', E_USER_DEPRECATED); |
||
830 | self::removeNestedKey($array, $keys); |
||
831 | } |
||
832 | |||
833 | /** |
||
834 | * Removes nested keys in array. |
||
835 | * |
||
836 | * Example: |
||
837 | * <code> |
||
838 | * $array = array('1' => array('2' => array('3' => 'value')));$array = array('1' => array('2' => array('3' => 'value'))); |
||
839 | * Arrays::removeNestedKey($array, array('1', '2')); |
||
840 | * </code> |
||
841 | * Result: |
||
842 | * <code> |
||
843 | * Array |
||
844 | * ( |
||
845 | * [1] => Array |
||
846 | * ( |
||
847 | * ) |
||
848 | * ) |
||
849 | * </code> |
||
850 | * |
||
851 | * @param array $array |
||
852 | * @param array $keys |
||
853 | */ |
||
854 | public static function removeNestedKey(array &$array, array $keys) |
||
855 | { |
||
856 | $key = array_shift($keys); |
||
857 | if (count($keys) == 0) { |
||
858 | unset($array[$key]); |
||
859 | } else if ($array[$key] !== null) { |
||
860 | self::removeNestedKey($array[$key], $keys); |
||
861 | } |
||
862 | } |
||
863 | |||
864 | /** |
||
865 | * Checks if array has nested key. It's possible to check array with null values using flag <i>Arrays::TREAT_NULL_AS_VALUE</i>. |
||
866 | * |
||
867 | * Example: |
||
868 | * <code> |
||
869 | * $array = array('1' => array('2' => array('3' => 'value'))); |
||
870 | * $value = Arrays::hasNestedKey($array, array('1', '2', '3')); |
||
871 | * </code> |
||
872 | * Result: |
||
873 | * <code> |
||
874 | * true |
||
875 | * </code> |
||
876 | * |
||
877 | * Example with null values: |
||
878 | * <code> |
||
879 | * $array = array('1' => array('2' => array('3' => null))); |
||
880 | * $value = Arrays::hasNestedKey($array, array('1', '2', '3'), Arrays::TREAT_NULL_AS_VALUE); |
||
881 | * </code> |
||
882 | * Result: |
||
883 | * <code> |
||
884 | * true |
||
885 | * </code> |
||
886 | * |
||
887 | * @param array $array |
||
888 | * @param array $keys |
||
889 | * @param null $flags |
||
890 | * @return bool |
||
891 | */ |
||
892 | public static function hasNestedKey(array $array, array $keys, $flags = null) |
||
893 | { |
||
894 | foreach ($keys as $key) { |
||
895 | if (!array_key_exists($key, $array) || (!($flags & self::TREAT_NULL_AS_VALUE) && !isset($array[$key]))) { |
||
896 | return false; |
||
897 | } |
||
898 | $array = self::getValue($array, $key); |
||
899 | } |
||
900 | return true; |
||
901 | } |
||
902 | |||
903 | /** |
||
904 | * Returns maps of the flatten keys with corresponding values. |
||
905 | * |
||
906 | * Example: |
||
907 | * <code> |
||
908 | * $array = array( |
||
909 | * 'customer' => array( |
||
910 | * 'name' => 'Name', |
||
911 | * 'phone' => '123456789' |
||
912 | * ), |
||
913 | * 'other' => array( |
||
914 | * 'ids_map' => array( |
||
915 | * '1qaz' => 'qaz', |
||
916 | * '2wsx' => 'wsx' |
||
917 | * ), |
||
918 | * 'first' => array( |
||
919 | * 'second' => array( |
||
920 | * 'third' => 'some value' |
||
921 | * ) |
||
922 | * ) |
||
923 | * ) |
||
924 | * ); |
||
925 | * $flatten = Arrays::flattenKeysRecursively($array) |
||
926 | * </code> |
||
927 | * Result: |
||
928 | * <code> |
||
929 | * Array |
||
930 | * ( |
||
931 | * [customer.name] => Name |
||
932 | * [customer.phone] => 123456789 |
||
933 | * [other.ids_map.1qaz] => qaz |
||
934 | * [other.ids_map.2wsx] => wsx |
||
935 | * [other.first.second.third] => some value |
||
936 | * ) |
||
937 | * </code> |
||
938 | * |
||
939 | * @param array $array |
||
940 | * @return array |
||
941 | */ |
||
942 | public static function flattenKeysRecursively(array $array) |
||
943 | { |
||
944 | $result = array(); |
||
945 | self::_flattenKeyRecursively($array, $result, ''); |
||
946 | return $result; |
||
947 | } |
||
948 | |||
949 | private static function _flattenKeyRecursively($array, &$result, $parentKey) |
||
950 | { |
||
951 | foreach ($array as $key => $value) { |
||
952 | $itemKey = ($parentKey ? $parentKey . '.' : '') . $key; |
||
953 | if (is_array($value)) { |
||
954 | self::_flattenKeyRecursively($value, $result, $itemKey); |
||
955 | } else { |
||
956 | $result[$itemKey] = $value; |
||
957 | } |
||
958 | } |
||
959 | } |
||
960 | |||
961 | /** |
||
962 | * Returns the number of elements for which the predicate returns true. |
||
963 | * |
||
964 | * Example: |
||
965 | * <code> |
||
966 | * $array = array(1, 2, 3); |
||
967 | * $count = Arrays::count($array, function ($element) { |
||
968 | * return $element < 3; |
||
969 | * }); |
||
970 | * </code> |
||
971 | * Result: |
||
972 | * <code> |
||
973 | * 2 |
||
974 | * </code> |
||
975 | * |
||
976 | * @param array $elements |
||
977 | * @param callable $predicate |
||
978 | * @return int |
||
979 | */ |
||
980 | public static function count(array $elements, $predicate) |
||
981 | { |
||
982 | $count = 0; |
||
983 | foreach ($elements as $element) { |
||
984 | if (Functions::call($predicate, $element)) { |
||
985 | $count++; |
||
986 | } |
||
987 | } |
||
988 | return $count; |
||
989 | } |
||
990 | |||
991 | /** |
||
992 | * This method maps array values using the function which takes key and value as parameters. |
||
993 | * Invokes the function for each value in the array. Creates a new array containing the values returned by the function. |
||
994 | * |
||
995 | * Example: |
||
996 | * <code> |
||
997 | * $array = array('a' => '1', 'b' => '2', 'c' => '3'); |
||
998 | * $result = Arrays::mapEntries($array, function ($key, $value) { |
||
999 | * return $key . '_' . $value; |
||
1000 | * }); |
||
1001 | * </code> |
||
1002 | * Result: |
||
1003 | * <code> |
||
1004 | * Array |
||
1005 | * ( |
||
1006 | * [a] => a_1 |
||
1007 | * [b] => b_2 |
||
1008 | * [c] => c_3 |
||
1009 | * ) |
||
1010 | * </code> |
||
1011 | * |
||
1012 | * @param array $elements |
||
1013 | * @param callable $function |
||
1014 | * @return array |
||
1015 | */ |
||
1016 | public static function mapEntries(array $elements, $function) |
||
1017 | { |
||
1018 | $keys = array_keys($elements); |
||
1019 | $values = array_values($elements); |
||
1020 | return array_combine($keys, array_map($function, $keys, $values)); |
||
1021 | } |
||
1022 | |||
1023 | /** |
||
1024 | * Removes duplicate values from an array. It uses the given expression to extract value that is compared. |
||
1025 | * |
||
1026 | * Example: |
||
1027 | * <code> |
||
1028 | * $a = new stdClass(); |
||
1029 | * $a->name = 'bob'; |
||
1030 | * |
||
1031 | * $b = new stdClass(); |
||
1032 | * $b->name = 'bob'; |
||
1033 | * |
||
1034 | * $array = [$a, $b]; |
||
1035 | * $result = Arrays::uniqueBy($array, 'name'); |
||
1036 | * </code> |
||
1037 | * Result: |
||
1038 | * <code> |
||
1039 | * Array |
||
1040 | * ( |
||
1041 | * [0] => $b |
||
1042 | * ) |
||
1043 | * </code> |
||
1044 | * |
||
1045 | * @param array $elements |
||
1046 | * @param $selector |
||
1047 | * @return array |
||
1048 | * @throws Exception |
||
1049 | */ |
||
1050 | public static function uniqueBy(array $elements, $selector) |
||
1051 | { |
||
1052 | return array_values(self::toMap($elements, Functions::extractExpression($selector))); |
||
1053 | } |
||
1054 | } |
||
1055 |