Completed
Push — master ( f8d6fe...92a23c )
by Lars
02:21
created

Arrayy::implodeKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Arrayy;
4
5
use voku\helper\Bootup;
6
use voku\helper\UTF8;
7
8
/** @noinspection ClassReImplementsParentInterfaceInspection */
9
10
/**
11
 * Methods to manage arrays.
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 */
16
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \Countable
17
{
18
  /**
19
   * @var array
20
   */
21
  protected $array = array();
22
23
  /**
24
   * @var string
25
   */
26
  protected $iteratorClass;
27
28
  /**
29
   * @var string
30
   */
31
  protected $pathSeparator = '.';
32
33
  /** @noinspection MagicMethodsValidityInspection */
34
  /**
35
   * Initializes
36
   *
37
   * @param array  $array
38
   * @param string $iteratorClass
39
   */
40 815
  public function __construct($array = array(), $iteratorClass = '\\Arrayy\\ArrayyIterator')
41
  {
42 815
    $array = $this->fallbackForArray($array);
43 813
    $this->array = $array;
44
45 813
    $this->setIteratorClass($iteratorClass);
46 813
  }
47
48
  /**
49
   * Get a value by key.
50
   *
51
   * @param $key
52
   *
53
   * @return mixed <p>Get a Value from the current array.</p>
54
   */
55 2
  public function &__get($key)
56
  {
57 2
    $return = $this->get($key);
58
59 2
    if (\is_array($return)) {
60
      return static::create($return);
61
    }
62
63 2
    return $return;
64
  }
65
66
  /**
67
   * Call object as function.
68
   *
69
   * @param mixed $key
70
   *
71
   * @return mixed
72
   */
73 1
  public function __invoke($key = null)
74
  {
75 1
    if ($key !== null) {
76 1
      if (isset($this->array[$key])) {
77 1
        return $this->array[$key];
78
      }
79
80
      return false;
81
    }
82
83
    return (array)$this->array;
84
  }
85
86
  /**
87
   * Whether or not an element exists by key.
88
   *
89
   * @param mixed $key
90
   *
91
   * @return bool <p>True is the key/index exists, otherwise false.</p>
92
   */
93
  public function __isset($key)
94
  {
95
    return $this->offsetExists($key);
96
  }
97
98
  /**
99
   * Assigns a value to the specified element.
100
   *
101
   * @param mixed $key
102
   * @param mixed $value
103
   */
104 2
  public function __set($key, $value)
105
  {
106 2
    $this->internalSet($key, $value);
107 2
  }
108
109
  /**
110
   * magic to string
111
   *
112
   * @return string
113
   */
114 16
  public function __toString()
115
  {
116 16
    return $this->toString();
117
  }
118
119
  /**
120
   * Unset element by key.
121
   *
122
   * @param mixed $key
123
   */
124
  public function __unset($key)
125
  {
126
    $this->internalRemove($key);
127
  }
128
129
  /**
130
   * alias: for "Arrayy->append()"
131
   *
132
   * @see Arrayy::append()
133
   *
134
   * @param mixed $value
135
   *
136
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
137
   */
138 1
  public function add($value)
139
  {
140 1
    return $this->append($value);
141
  }
142
143
  /**
144
   * Append a (key) + value to the current array.
145
   *
146
   * @param mixed $value
147
   * @param mixed $key
148
   *
149
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
150
   */
151 9
  public function append($value, $key = null)
152
  {
153 9
    if ($key !== null) {
154
      $this->array[$key] = $value;
155
    } else {
156 9
      $this->array[] = $value;
157
    }
158
159 9
    return $this;
160
  }
161
162
  /**
163
   * Sort the entries by value.
164
   *
165
   * @param int $sort_flags [optional] <p>
166
   *                        You may modify the behavior of the sort using the optional
167
   *                        parameter sort_flags, for details
168
   *                        see sort.
169
   *                        </p>
170
   *
171
   * @return static <p>(Mutable) Return this Arrayy object.</p>
172
   */
173 4
  public function asort($sort_flags = null)
174
  {
175 4
    \asort($this->array, $sort_flags);
176
177 4
    return $this;
178
  }
179
180
  /**
181
   * Count the values from the current array.
182
   *
183
   * alias: for "Arrayy->size()"
184
   *
185
   * @see Arrayy::size()
186
   *
187
   * @param int $mode
188
   *
189 93
   * @return int
190
   */
191 93
  public function count($mode = COUNT_NORMAL)
192
  {
193
    return $this->size($mode);
194
  }
195
196
  /**
197
   * Exchange the array for another one.
198
   *
199
   * @param array|Arrayy $data
200
   *
201 1
   * @return array
202
   */
203 1
  public function exchangeArray($data)
204
  {
205 1
    $this->array = $this->fallbackForArray($data);
206
207
    return $this->array;
208
  }
209
210
  /**
211
   * Creates a copy of the ArrayyObject.
212
   *
213 1
   * @return array
214
   */
215 1
  public function getArrayCopy()
216
  {
217
    return $this->array;
218
  }
219
220
  /**
221
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
222
   *
223 20
   * @return ArrayyIterator <p>An iterator for the values in the array.</p>
224
   */
225 20
  public function getIterator()
226
  {
227 20
    $iterator = $this->getIteratorClass();
228
229
    return new $iterator($this->array);
230
  }
231
232
  /**
233
   * Gets the iterator classname for the ArrayObject.
234
   *
235 20
   * @return string
236
   */
237 20
  public function getIteratorClass()
238
  {
239
    return $this->iteratorClass;
240
  }
241
242
  /**
243
   * Sort the entries by key
244
   *
245
   * @param int $sort_flags [optional] <p>
246
   *                        You may modify the behavior of the sort using the optional
247
   *                        parameter sort_flags, for details
248
   *                        see sort.
249
   *                        </p>
250
   *
251 4
   * @return static <p>(Mutable) Return this Arrayy object.</p>
252
   */
253 4
  public function ksort($sort_flags = null)
254
  {
255 4
    \ksort($this->array, $sort_flags);
256
257
    return $this;
258
  }
259
260
  /**
261
   * Sort an array using a case insensitive "natural order" algorithm
262
   *
263
   * @return static <p>(Mutable) Return this Arrayy object.</p>
264
   */
265
  public function natcasesort()
266
  {
267
    \natcasesort($this->array);
268
269
    return $this;
270
  }
271
272
  /**
273
   * Sort entries using a "natural order" algorithm
274
   *
275 1
   * @return static <p>(Mutable) Return this Arrayy object.</p>
276
   */
277 1
  public function natsort()
278
  {
279 1
    \natsort($this->array);
280
281
    return $this;
282
  }
283
284
  /**
285
   * Whether or not an offset exists.
286
   *
287
   * @param int|float|string $offset
288
   *
289 40
   * @return bool
290
   */
291 40
  public function offsetExists($offset)
292 4
  {
293
    if ($this->isEmpty()) {
294
      return false;
295
    }
296 36
297 1
    // php cast "bool"-index into "int"-index
298 1
    if ((bool)$offset === $offset) {
299
      $offset = (int)$offset;
300 36
    }
301
302
    $tmpReturn = \array_key_exists($offset, $this->array);
303
304 36
    if (
305
        $tmpReturn === true
306
        ||
307 12
        (
308 12
            $tmpReturn === false
309 12
            &&
310 36
            \strpos((string)$offset, $this->pathSeparator) === false
311 34
        )
312
    ) {
313
      return $tmpReturn;
314 3
    }
315
316 3
    $offsetExists = false;
317
318 3
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
319 3
320 3
      $offsetExists = false;
321 3
      $explodedPath = \explode($this->pathSeparator, (string)$offset);
322
      $lastOffset = \array_pop($explodedPath);
323 3
      $containerPath = \implode($this->pathSeparator, $explodedPath);
324 3
325
      $this->callAtPath(
326 3
          $containerPath,
327 3
          function ($container) use ($lastOffset, &$offsetExists) {
328 3
            $offsetExists = \array_key_exists($lastOffset, $container);
329 3
          }
330
      );
331 3
    }
332
333
    return $offsetExists;
334
  }
335
336
  /**
337
   * Returns the value at specified offset.
338
   *
339
   * @param mixed $offset
340
   *
341 26
   * @return mixed <p>Will return null if the offset did not exists.</p>
342
   */
343 26
  public function offsetGet($offset)
344
  {
345
    return $this->offsetExists($offset) ? $this->get($offset) : null;
346
  }
347
348
  /**
349
   * Assigns a value to the specified offset.
350
   *
351
   * @param mixed $offset
352 17
   * @param mixed $value
353
   */
354 17
  public function offsetSet($offset, $value)
355 4
  {
356 4
    if ($offset === null) {
357 13
      $this->array[] = $value;
358
    } else {
359 17
      $this->internalSet($offset, $value);
360
    }
361
  }
362
363
  /**
364
   * Unset an offset.
365
   *
366 7
   * @param mixed $offset
367
   */
368 7
  public function offsetUnset($offset)
369 1
  {
370
    if ($this->isEmpty()) {
371
      return;
372 6
    }
373 4
374
    if (\array_key_exists($offset, $this->array)) {
375 4
      unset($this->array[$offset]);
376
377
      return;
378 3
    }
379
380 2
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
381 2
382
      $path = \explode($this->pathSeparator, (string)$offset);
383 2
      $pathToUnset = \array_pop($path);
384 2
385
      $this->callAtPath(
386 2
          \implode($this->pathSeparator, $path),
387 2
          function (&$offset) use ($pathToUnset) {
388 2
            unset($offset[$pathToUnset]);
389
          }
390 2
      );
391 3
392
    }
393
  }
394
395
  /**
396
   * Serialize the current "Arrayy"-object.
397
   *
398 1
   * @return string
399
   */
400 1
  public function serialize()
401
  {
402
    return parent::serialize();
403
  }
404
405
  /**
406
   * Sets the iterator classname for the current "Arrayy"-object.
407
   *
408
   * @param  string $class
409
   *
410
   * @return void
411
   *
412 813
   * @throws \InvalidArgumentException
413
   */
414 813
  public function setIteratorClass($class)
415 813
  {
416
    if (\class_exists($class)) {
417 813
      $this->iteratorClass = $class;
418
419
      return;
420
    }
421
422
    if (\strpos($class, '\\') === 0) {
423
      $class = '\\' . $class;
424
      if (\class_exists($class)) {
425
        $this->iteratorClass = $class;
426
427
        return;
428
      }
429
    }
430
431
    throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
432
  }
433
434
  /**
435
   * Sort the entries with a user-defined comparison function and maintain key association.
436
   *
437
   * @param callable $function
438
   *
439
   * @return static <p>(Mutable) Return this Arrayy object.</p>
440
   *
441
   * @throws \InvalidArgumentException
442
   */
443 View Code Duplication
  public function uasort($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
444
  {
445
    if (!\is_callable($function)) {
446
      throw new \InvalidArgumentException(
447
          'Passed function must be callable'
448
      );
449
    }
450
451
    \uasort($this->array, $function);
452
453
    return $this;
454
  }
455
456
  /**
457
   * Sort the entries by keys using a user-defined comparison function.
458
   *
459
   * @param callable $function
460
   *
461
   * @return static <p>(Mutable) Return this Arrayy object.</p>
462
   *
463 5
   * @throws \InvalidArgumentException
464
   */
465 5
  public function uksort($function)
466
  {
467
    return $this->customSortKeys($function);
468
  }
469
470
  /**
471
   * Unserialize an string and return this object.
472
   *
473
   * @param string $string
474
   *
475 1
   * @return static <p>(Mutable)</p>
476
   */
477 1
  public function unserialize($string)
478
  {
479 1
    parent::unserialize($string);
480
481
    return $this;
482
  }
483
484
  /**
485
   * Add a suffix to each key.
486
   *
487
   * @param string $prefix
488
   *
489 10
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
490
   */
491 10 View Code Duplication
  public function appendToEachKey($prefix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
492 10
  {
493 9
    $result = array();
494
    foreach ($this->array as $key => $item) {
495 9
      if ($item instanceof self) {
496
        $result[$prefix . $key] = $item->appendToEachKey($prefix);
497
      } elseif (\is_array($item)) {
498 9
        $result[$prefix . $key] = self::create($item)->appendToEachKey($prefix)->toArray();
499
      } else {
500 10
        $result[$prefix . $key] = $item;
501
      }
502 10
    }
503
504
    return self::create($result);
505
  }
506
507
  /**
508
   * Add a prefix to each value.
509
   *
510
   * @param mixed $prefix
511
   *
512 10
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
513
   */
514 10 View Code Duplication
  public function appendToEachValue($prefix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
515 10
  {
516 9
    $result = array();
517
    foreach ($this->array as $key => $item) {
518 9
      if ($item instanceof self) {
519
        $result[$key] = $item->appendToEachValue($prefix);
520 9
      } elseif (\is_array($item)) {
521 1
        $result[$key] = self::create($item)->appendToEachValue($prefix)->toArray();
522 1
      } elseif (\is_object($item)) {
523 8
        $result[$key] = $item;
524
      } else {
525 10
        $result[$key] = $prefix . $item;
526
      }
527 10
    }
528
529
    return self::create($result);
530
  }
531
532
  /**
533
   * Convert an array into a object.
534
   *
535
   * @param array $array PHP array
536
   *
537 4
   * @return \stdClass (object)
538
   */
539 4
  protected static function arrayToObject(array $array = array())
540
  {
541 4
    $object = new \stdClass();
542 1
543
    if (!\is_array($array) || \count($array) <= 0) {
544
      return $object;
545 3
    }
546 3
547 1
    foreach ($array as $name => $value) {
548 1
      if (\is_array($value)) {
549
        $object->$name = self::arrayToObject($value);
550 3
        continue;
551 3
      }
552
      $object->{$name} = $value;
553 3
    }
554
555
    return $object;
556
  }
557
558
  /**
559
   * Sort an array in reverse order and maintain index association.
560
   *
561 4
   * @return static <p>(Mutable) Return this Arrayy object.</p>
562
   */
563 4
  public function arsort()
564
  {
565 4
    \arsort($this->array);
566
567
    return $this;
568
  }
569
570
  /**
571
   * Iterate over the current array and execute a callback for each loop.
572
   *
573
   * @param \Closure $closure
574
   *
575 2
   * @return static <p>(Immutable)</p>
576
   */
577 2 View Code Duplication
  public function at(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
578
  {
579 2
    $array = $this->array;
580 2
581 2
    foreach ($array as $key => $value) {
582
      $closure($value, $key);
583 2
    }
584
585
    return static::create($array);
586
  }
587
588
  /**
589
   * Returns the average value of the current array.
590
   *
591
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
592
   *
593 10
   * @return int|double <p>The average value.</p>
594
   */
595 10
  public function average($decimals = 0)
596
  {
597 10
    $count = $this->count();
598 2
599
    if (!$count) {
600
      return 0;
601 8
    }
602 3
603 3
    if (!\is_int($decimals)) {
604
      $decimals = 0;
605 8
    }
606
607
    return \round(\array_sum($this->array) / $count, $decimals);
608
  }
609
610
  /**
611
   * @param mixed      $path
612
   * @param callable   $callable
613 4
   * @param null|array $currentOffset
614
   */
615 4
  protected function callAtPath($path, $callable, &$currentOffset = null)
616 4
  {
617 4
    if ($currentOffset === null) {
618
      $currentOffset = &$this->array;
619 4
    }
620 4
621
    $explodedPath = \explode($this->pathSeparator, $path);
622 4
    $nextPath = \array_shift($explodedPath);
623
624
    if (!isset($currentOffset[$nextPath])) {
625
      return;
626 4
    }
627 1
628 1
    if (!empty($explodedPath)) {
629 1
      $this->callAtPath(
630 1
          \implode($this->pathSeparator, $explodedPath),
631 1
          $callable,
632 1
          $currentOffset[$nextPath]
633 4
      );
634
    } else {
635 4
      $callable($currentOffset[$nextPath]);
636
    }
637
  }
638
639
  /**
640
   * Changes all keys in an array.
641
   *
642
   * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
643
   *                  or <strong>CASE_LOWER</strong> (default)</p>
644
   *
645 1
   * @return static <p>(Immutable)</p>
646
   */
647 1
  public function changeKeyCase($case = CASE_LOWER)
648
  {
649
    return static::create(UTF8::array_change_key_case($this->array, $case));
0 ignored issues
show
Security Bug introduced by
It seems like \voku\helper\UTF8::array...se($this->array, $case) targeting voku\helper\UTF8::array_change_key_case() can also be of type false; however, Arrayy\Arrayy::create() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
650
  }
651
652
  /**
653
   * Change the path separator of the array wrapper.
654
   *
655
   * By default, the separator is: "."
656
   *
657
   * @param string $separator <p>Separator to set.</p>
658
   *
659 1
   * @return static <p>Mutable</p>
660
   */
661 1
  public function changeSeparator($separator)
662
  {
663 1
    $this->pathSeparator = $separator;
664
665
    return $this;
666
  }
667
668
  /**
669
   * Create a chunked version of the current array.
670
   *
671
   * @param int  $size         <p>Size of each chunk.</p>
672
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
673
   *
674 4
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
675
   */
676 4
  public function chunk($size, $preserveKeys = false)
677
  {
678 4
    $result = \array_chunk($this->array, $size, $preserveKeys);
679
680
    return static::create($result);
681
  }
682
683
  /**
684
   * Clean all falsy values from the current array.
685
   *
686 8
   * @return static <p>(Immutable)</p>
687
   */
688 8
  public function clean()
689
  {
690 7
    return $this->filter(
691
        function ($value) {
692 8
          return (bool)$value;
693
        }
694
    );
695
  }
696
697
  /**
698
   * WARNING!!! -> Clear the current array.
699
   *
700 4
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
701
   */
702 4
  public function clear()
703
  {
704 4
    $this->array = array();
705
706
    return $this;
707
  }
708
709
  /**
710
   * Check if an item is in the current array.
711
   *
712
   * @param string|int|float $value
713
   * @param bool             $recursive
714 13
   * @param bool             $strict
715
   *
716 13
   * @return bool
717
   */
718
  public function contains($value, $recursive = false, $strict = true)
719
  {
720
    if ($recursive === true) {
721
      return $this->in_array_recursive($value, $this->array, $strict);
722
    }
723
724
    return \in_array($value, $this->array, $strict);
725
  }
726 13
727
  /**
728 13
   * @param mixed $needle   <p>
729 13
   *                        The searched value.
730 13
   *                        </p>
731
   *                        <p>
732 13
   *                        If needle is a string, the comparison is done
733 13
   *                        in a case-sensitive manner.
734 13
   *                        </p>
735 13
   * @param array $haystack <p>
736 13
   *                        The array.
737
   *                        </p>
738 13
   * @param bool  $strict   [optional] <p>
739
   *                        If the third parameter strict is set to true
740
   *                        then the in_array function will also check the
741
   *                        types of the
742
   *                        needle in the haystack.
743
   *                        </p>
744
   *
745
   * @return bool true if needle is found in the array, false otherwise.
746
   */
747
  protected function in_array_recursive($needle, array $haystack = null, $strict = true)
748 4
  {
749
    if ($haystack === null) {
750 4
      $haystack = $this->array;
751
    }
752
753
    foreach ($haystack as $item) {
754
755
      if (\is_array($item) === true) {
756
        $returnTmp = $this->in_array_recursive($needle, $item, $strict);
757
      } else {
758
        $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
759
      }
760 1
761
      if ($returnTmp === true) {
762 1
        return true;
763
      }
764
    }
765
766
    return false;
767
  }
768
769
  /**
770
   * Check if an (case-insensitive) string is in the current array.
771
   *
772
   * @param string $value
773
   * @param bool   $recursive
774 9
   *
775
   * @return bool
776 9
   */
777
  public function containsCaseInsensitive($value, $recursive = false)
778
  {
779
    if ($recursive === true) {
780
      return $this->in_array_recursive(
781
          UTF8::strtoupper($value),
782
          $this->walk(
783
              function (&$val) {
784
                $val = UTF8::strtoupper($val);
785
              },
786 1
              true
787
          )->getArray(),
788 1
          true
789
      );
790
    }
791
792
    return \in_array(
793
        UTF8::strtoupper($value),
794
        $this->walk(
795
            function (&$val) {
796
              $val = UTF8::strtoupper($val);
797
            },
798
            false
799
        )->getArray(),
800
        true
801
    );
802 1
  }
803
804 1
  /**
805
   * Check if the given key/index exists in the array.
806
   *
807
   * @param string|int|float $key <p>key/index to search for</p>
808
   *
809
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
810
   */
811
  public function containsKey($key)
812
  {
813
    return $this->offsetExists($key);
814 522
  }
815
816 522
  /**
817
   * Check if all given needles are present in the array as key/index.
818
   *
819
   * @param array $needles <p>The keys you are searching for.</p>
820
   * @param bool  $recursive
821
   *
822
   * @return bool <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
823
   */
824
  public function containsKeys(array $needles, $recursive = false)
825
  {
826 1
    if ($recursive === true) {
827
      return \count(\array_intersect($needles, $this->keys(true)->getArray())) === \count($needles, COUNT_RECURSIVE);
828 1
    }
829
830 1
    return \count(\array_intersect($needles, $this->keys()->getArray())) === \count($needles);
831
  }
832 1
833
  /**
834
   * Check if all given needles are present in the array as key/index.
835
   *
836
   * @param array $needles <p>The keys you are searching for.</p>
837
   *
838
   * @return bool <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
839
   */
840
  public function containsKeysRecursive(array $needles)
841
  {
842 5
    return $this->containsKeys($needles, true);
843
  }
844 5
845
  /**
846 5
   * alias: for "Arrayy->contains()"
847
   *
848
   * @see Arrayy::contains()
849
   *
850
   * @param string|int|float $value
851
   *
852
   * @return bool
853
   */
854
  public function containsValue($value)
855
  {
856 4
    return $this->contains($value);
857
  }
858 4
859 4
  /**
860
   * alias: for "Arrayy->contains($value, true)"
861 3
   *
862 4
   * @see Arrayy::contains()
863
   *
864 4
   * @param string|int|float $value
865
   *
866
   * @return bool
867
   */
868
  public function containsValueRecursive($value)
869
  {
870
    return $this->contains($value, true);
871
  }
872
873
  /**
874 5
   * Check if all given needles are present in the array.
875
   *
876 5
   * @param array $needles
877
   *
878
   * @return bool <p>Returns true if all the given values exists in the array, false otherwise.</p>
879
   */
880
  public function containsValues(array $needles)
881
  {
882
    return \count(\array_intersect($needles, $this->array)) === \count($needles);
883
  }
884
885
  /**
886
   * Counts all the values of an array
887
   *
888
   * @link http://php.net/manual/en/function.array-count-values.php
889 8
   *
890
   * @return static <p>
891 8
   *                (Immutable)
892 1
   *                An associative Arrayy-object of values from input as
893
   *                keys and their count as value.
894 1
   *                </p>
895 1
   */
896 1
  public function countValues()
897
  {
898 1
    return new static(\array_count_values($this->array));
899 7
  }
900
901
  /**
902
   * Creates an Arrayy object.
903 8
   *
904
   * @param array $array
905
   *
906
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
907 8
   */
908 8
  public static function create($array = array())
909 8
  {
910 8
    return new static($array);
911 8
  }
912
913 8
  /**
914
   * WARNING: Creates an Arrayy object by reference.
915
   *
916
   * @param array $array
917
   *
918
   * @return static <p>(Mutable) Return this Arrayy object.</p>
919
   */
920
  public function createByReference(&$array = array())
921
  {
922
    $array = $this->fallbackForArray($array);
923
924
    $this->array = &$array;
925 1
926
    return $this;
927 1
  }
928
929
  /**
930
   * Create an new Arrayy object via JSON.
931
   *
932
   * @param string $json
933
   *
934
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
935
   */
936
  public static function createFromJson($json)
937
  {
938
    $array = UTF8::json_decode($json, true);
939
940
    return static::create($array);
941 5
  }
942
943 5
  /**
944
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
945
   *
946
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
947
   *
948
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
949 5
   */
950
  public static function createFromObject(\ArrayAccess $object)
951 5
  {
952
    $array = new static();
953
    foreach ($object as $key => $value) {
954
      /** @noinspection OffsetOperationsInspection */
955
      $array[$key] = $value;
956
    }
957
958
    return $array;
959
  }
960
961
  /**
962
   * Create an new instance filled with values from an object.
963
   *
964
   * @param object $object
965 5
   *
966
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
967 5
   */
968
  public static function createFromObjectVars($object)
969
  {
970
    return new static(self::objectToArray($object));
971
  }
972
973 5
  /**
974
   * Create an new Arrayy object via string.
975 5
   *
976
   * @param string      $str       <p>The input string.</p>
977
   * @param string|null $delimiter <p>The boundary string.</p>
978
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
979
   *                               used.</p>
980
   *
981
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
982
   */
983
  public static function createFromString($str, $delimiter, $regEx = null)
984
  {
985 12
    if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
986
      \preg_match_all($regEx, $str, $array);
987 12
988
      if (!empty($array)) {
989 12
        $array = $array[0];
990
      }
991
992
    } else {
993
      $array = \explode($delimiter, $str);
994
    }
995
996
    // trim all string in the array
997
    \array_walk(
998
        $array,
999
        function (&$val) {
1000 1
          /** @noinspection ReferenceMismatchInspection */
1001
          if (\is_string($val)) {
1002 1
            $val = \trim($val);
1003
          }
1004
        }
1005
    );
1006 1
1007 1
    return static::create($array);
1008 1
  }
1009 1
1010 1
  /**
1011 1
   * Create an new instance containing a range of elements.
1012
   *
1013
   * @param mixed $low  <p>First value of the sequence.</p>
1014 1
   * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1015 1
   * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1016 1
   *
1017 1
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1018 1
   */
1019 1
  public static function createWithRange($low, $high, $step = 1)
1020 1
  {
1021 1
    return static::create(\range($low, $high, $step));
1022 1
  }
1023 1
1024 1
  /**
1025
   * Custom sort by index via "uksort".
1026 1
   *
1027 1
   * @link http://php.net/manual/en/function.uksort.php
1028
   *
1029 1
   * @param callable $function
1030
   *
1031 1
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1032
   *
1033
   * @throws \InvalidArgumentException
1034
   */
1035 View Code Duplication
  public function customSortKeys($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1036
  {
1037
    if (!\is_callable($function)) {
1038
      throw new \InvalidArgumentException(
1039
          'Passed function must be callable'
1040
      );
1041 8
    }
1042
1043 8
    \uksort($this->array, $function);
1044
1045 8
    return $this;
1046
  }
1047
1048
  /**
1049
   * Custom sort by value via "usort".
1050
   *
1051
   * @link http://php.net/manual/en/function.usort.php
1052
   *
1053 1
   * @param callable $function
1054
   *
1055 1
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1056
   *
1057 1
   * @throws \InvalidArgumentException
1058 1
   */
1059 View Code Duplication
  public function customSortValues($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1060 1
  {
1061
    if (!\is_callable($function)) {
1062
      throw new \InvalidArgumentException(
1063
          'Passed function must be callable'
1064
      );
1065
    }
1066
1067
    \usort($this->array, $function);
1068
1069
    return $this;
1070 4
  }
1071
1072 4
  /**
1073
   * Return values that are only in the current array.
1074 4
   *
1075 4
   * @param array $array
1076 4
   *
1077
   * @return static <p>(Immutable)</p>
1078 4
   */
1079
  public function diff(array $array = array())
1080
  {
1081
    $result = \array_diff($this->array, $array);
1082
1083
    return static::create($result);
1084
  }
1085
1086
  /**
1087
   * Return values that are only in the current multi-dimensional array.
1088 4
   *
1089
   * @param array      $array
1090 4
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
1091 4
   *
1092 3
   * @return static <p>(Immutable)</p>
1093 1
   */
1094 1
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
1095
  {
1096 4
    $result = array();
1097
1098 4
    if (
1099
        $helperVariableForRecursion !== null
1100
        &&
1101
        \is_array($helperVariableForRecursion)
1102
    ) {
1103
      $arrayForTheLoop = $helperVariableForRecursion;
1104
    } else {
1105
      $arrayForTheLoop = $this->array;
1106
    }
1107
1108
    foreach ($arrayForTheLoop as $key => $value) {
1109
      if (\array_key_exists($key, $array)) {
1110
        if (\is_array($value)) {
1111
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
1112
          if (!empty($recursiveDiff)) {
1113
            $result[$key] = $recursiveDiff;
1114
          }
1115
        } else {
1116
          if ($value != $array[$key]) {
1117
            $result[$key] = $value;
1118 815
          }
1119
        }
1120 815
      } else {
1121 812
        $result[$key] = $value;
1122
      }
1123
    }
1124 11
1125 1
    return static::create($result);
1126
  }
1127
1128 10
  /**
1129 6
   * Return values that are only in the new $array.
1130
   *
1131
   * @param array $array
1132 9
   *
1133
   * @return static <p>(Immutable)</p>
1134 9
   */
1135
  public function diffReverse(array $array = array())
1136
  {
1137
    $result = \array_diff($array, $this->array);
1138
1139 9
    return static::create($result);
1140
  }
1141
1142
  /**
1143 9
   * Divide an array into two arrays. One with keys and the other with values.
1144
   *
1145
   * @return static <p>(Immutable)</p>
1146
   */
1147
  public function divide()
1148
  {
1149 9
    return static::create(
1150
        array(
1151 2
            $this->keys(),
1152 9
            $this->values(),
1153 7
        )
1154
    );
1155
  }
1156 2
1157
  /**
1158 2
   * Iterate over the current array and modify the array's value.
1159
   *
1160
   * @param \Closure $closure
1161
   *
1162
   * @return static <p>(Immutable)</p>
1163
   */
1164 View Code Duplication
  public function each(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1165
  {
1166
    $array = $this->array;
1167
1168
    foreach ($array as $key => $value) {
1169
      $array[$key] = $closure($value, $key);
1170
    }
1171
1172
    return static::create($array);
1173
  }
1174
1175
  /**
1176
   * Check if a value is in the current array using a closure.
1177
   *
1178
   * @param \Closure $closure
1179
   *
1180
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
1181
   */
1182
  public function exists(\Closure $closure)
1183
  {
1184
    $isExists = false;
1185
    foreach ($this->array as $key => $value) {
1186
      if ($closure($value, $key)) {
1187
        $isExists = true;
1188
        break;
1189 9
      }
1190
    }
1191 9
1192 1
    return $isExists;
1193
  }
1194
1195 9
  /**
1196
   * create a fallback for array
1197
   *
1198
   * 1. use the current array, if it's a array
1199 9
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
1200
   * 3. fallback to empty array, if there is nothing
1201 9
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
1202
   * 5. call "__toArray()" on object, if the method exists
1203
   * 6. cast a string or object with "__toString()" into an array
1204
   * 7. throw a "InvalidArgumentException"-Exception
1205
   *
1206
   * @param $array
1207
   *
1208
   * @return array
1209
   *
1210
   * @throws \InvalidArgumentException
1211 1
   */
1212
  protected function fallbackForArray(&$array)
1213 1
  {
1214 1
    if (\is_array($array)) {
1215 1
      return $array;
1216 1
    }
1217 1
1218 1
    if ($array instanceof self) {
1219 1
      return $array->getArray();
1220 1
    }
1221 1
1222 1
    if (!$array) {
1223 1
      return array();
1224 1
    }
1225 1
1226
    $isObject = \is_object($array);
1227
1228 9
    if ($isObject && $array instanceof \ArrayAccess) {
1229
      /** @noinspection ReferenceMismatchInspection */
1230
      return static::createFromObject($array)->getArray();
1231
    }
1232
1233
    if ($isObject && $array instanceof \ArrayObject) {
1234
      return $array->getArrayCopy();
1235
    }
1236
1237
    if ($isObject && \method_exists($array, '__toArray')) {
1238
      return (array)$array->__toArray();
1239
    }
1240
1241
    /** @noinspection ReferenceMismatchInspection */
1242
    if (
1243
        \is_string($array)
1244
        ||
1245
        ($isObject && \method_exists($array, '__toString'))
1246
    ) {
1247
      return array((string)$array);
1248
    }
1249
1250
    throw new \InvalidArgumentException(
1251
        'Passed value should be a array'
1252
    );
1253 1
  }
1254
1255 1
  /**
1256 1
   * Find all items in an array that pass the truth test.
1257 1
   *
1258
   * @param \Closure|null $closure [optional] <p>
1259
   *                               The callback function to use
1260
   *                               </p>
1261 1
   *                               <p>
1262 1
   *                               If no callback is supplied, all entries of
1263
   *                               input equal to false (see
1264
   *                               converting to
1265 1
   *                               boolean) will be removed.
1266
   *                               </p>
1267
   *
1268 1
   *  * @param int $flag [optional] <p>
1269
   *                               Flag determining what arguments are sent to <i>callback</i>:
1270
   *                               </p><ul>
1271 1
   *                               <li>
1272
   *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1273 1
   *                               to <i>callback</i> instead of the value</span>
1274 1
   *                               </li>
1275
   *                               <li>
1276
   *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1277 1
   *                               arguments to <i>callback</i> instead of the value</span>
1278
   *                               </li>
1279
   *                               </ul>
1280 1
   *
1281
   * @return static <p>(Immutable)</p>
1282
   */
1283 1
  public function filter($closure = null, $flag = 0)
1284
  {
1285 1
    if (!$closure) {
1286 1
      return $this->clean();
1287
    }
1288
1289 1
    if ($flag === 0) {
1290
1291
      // working for all php-versions
1292 1
1293
      $array = \array_filter($this->array, $closure);
1294
1295 1
    } elseif ($flag !== 0 && \defined('HHVM_VERSION') === false && Bootup::is_php('5.6')) {
1296 1
1297
      // working only with php >= 5.6 and not via HHVM
1298 1
1299 1
      $array = \array_filter($this->array, $closure, $flag);
1300 1
1301
    } else {
1302 1
1303 1
      // fallback for old php-versions
1304 1
1305 1
      $array = $this->array;
1306
1307 1
      if ($flag === 2 /* ARRAY_FILTER_USE_KEY */) {
1308 1
        foreach ($array as $key => $value) {
1309 1
          if (!\call_user_func($closure, $key)) {
1310
            unset($array[$key]);
1311 1
          }
1312
        }
1313 1
      } elseif ($flag === 1 /* ARRAY_FILTER_USE_BOTH */) {
1314 1
        foreach ($array as $key => $value) {
1315
          if (!\call_user_func($closure, $key, $value)) {
1316 1
            unset($array[$key]);
1317
          }
1318
        }
1319
      }
1320
    }
1321
1322
    return static::create($array);
1323
  }
1324
1325
  /**
1326
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
1327 8
   * within that.
1328
   *
1329 8
   * @param string $property
1330 6
   * @param string $value
1331 5
   * @param string $comparisonOp
1332
   *                            <p>
1333 5
   *                            'eq' (equals),<br />
1334
   *                            'gt' (greater),<br />
1335 3
   *                            'gte' || 'ge' (greater or equals),<br />
1336
   *                            'lt' (less),<br />
1337
   *                            'lte' || 'le' (less or equals),<br />
1338
   *                            'ne' (not equals),<br />
1339
   *                            'contains',<br />
1340
   *                            'notContains',<br />
1341
   *                            'newer' (via strtotime),<br />
1342
   *                            'older' (via strtotime),<br />
1343
   *                            </p>
1344
   *
1345
   * @return static <p>(Immutable)</p>
1346
   */
1347
  public function filterBy($property, $value, $comparisonOp = null)
1348
  {
1349
    if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1350
      $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1351
    }
1352
1353
    $ops = array(
1354
        'eq'          => function ($item, $prop, $value) {
1355
          return $item[$prop] === $value;
1356
        },
1357 13
        'gt'          => function ($item, $prop, $value) {
1358
          return $item[$prop] > $value;
1359 13
        },
1360 13
        'ge'          => function ($item, $prop, $value) {
1361
          return $item[$prop] >= $value;
1362 13
        },
1363 3
        'gte'         => function ($item, $prop, $value) {
1364
          return $item[$prop] >= $value;
1365
        },
1366 10
        'lt'          => function ($item, $prop, $value) {
1367
          return $item[$prop] < $value;
1368
        },
1369
        'le'          => function ($item, $prop, $value) {
1370
          return $item[$prop] <= $value;
1371
        },
1372
        'lte'         => function ($item, $prop, $value) {
1373
          return $item[$prop] <= $value;
1374
        },
1375
        'ne'          => function ($item, $prop, $value) {
1376 28
          return $item[$prop] !== $value;
1377
        },
1378 28
        'contains'    => function ($item, $prop, $value) {
1379 7
          return \in_array($item[$prop], (array)$value, true);
1380 7
        },
1381 7
        'notContains' => function ($item, $prop, $value) {
1382 21
          return !\in_array($item[$prop], (array)$value, true);
1383 21
        },
1384 21
        'newer'       => function ($item, $prop, $value) {
1385
          return \strtotime($item[$prop]) > \strtotime($value);
1386
        },
1387 28
        'older'       => function ($item, $prop, $value) {
1388
          return \strtotime($item[$prop]) < \strtotime($value);
1389
        },
1390
    );
1391
1392
    $result = \array_values(
1393
        \array_filter(
1394
            (array)$this->array,
1395
            function ($item) use (
1396
                $property,
1397 26
                $value,
1398
                $ops,
1399 26
                $comparisonOp
1400 11
            ) {
1401 11
              $item = (array)$item;
1402 15
              $itemArrayy = new Arrayy($item);
1403 15
              $item[$property] = $itemArrayy->get($property, array());
1404
1405
              return $ops[$comparisonOp]($item, $property, $value);
1406 26
            }
1407
        )
1408
    );
1409
1410
    return static::create($result);
1411
  }
1412
1413
  /**
1414 1
   * Find the first item in an array that passes the truth test,
1415
   *  otherwise return false
1416 1
   *
1417
   * @param \Closure $closure
1418 1
   *
1419
   * @return mixed|false <p>Return false if we did not find the value.</p>
1420
   */
1421
  public function find(\Closure $closure)
1422
  {
1423
    foreach ($this->array as $key => $value) {
1424
      if ($closure($value, $key)) {
1425
        return $value;
1426
      }
1427
    }
1428
1429
    return false;
1430
  }
1431 61
1432
  /**
1433
   * find by ...
1434
   *
1435 61
   * @param string $property
1436 3
   * @param string $value
1437 61
   * @param string $comparisonOp
1438 3
   *
1439 3
   * @return static <p>(Immutable)</p>
1440 59
   */
1441
  public function findBy($property, $value, $comparisonOp = 'eq')
1442
  {
1443 61
    return $this->filterBy($property, $value, $comparisonOp);
1444 1
  }
1445
1446
  /**
1447
   * Get the first value from the current array.
1448 61
   *
1449 2
   * @return mixed <p>Return null if there wasn't a element.</p>
1450 2
   */
1451
  public function first()
1452 61
  {
1453 51
    $tmpArray = $this->array;
1454 6
    $result = \array_shift($tmpArray);
1455
1456
    if ($result === null) {
1457 47
      return null;
1458
    }
1459
1460
    return $result;
1461 20
  }
1462 20
1463 19
  /**
1464
   * Get the first value(s) from the current array.
1465
   *
1466 5
   * @param int|null $number <p>How many values you will take?</p>
1467 5
   *
1468
   * @return static <p>(Immutable)</p>
1469 5
   */
1470
  public function firstsImmutable($number = null)
1471
  {
1472
    if ($number === null) {
1473 5
      $arrayTmp = $this->array;
1474
      $array = (array)\array_shift($arrayTmp);
1475
    } else {
1476
      $number = (int)$number;
1477
      $arrayTmp = $this->array;
1478
      $array = \array_splice($arrayTmp, 0, $number, true);
1479
    }
1480
1481 536
    return static::create($array);
1482
  }
1483 536
1484
  /**
1485 536
   * Get the first value(s) from the current array.
1486
   *
1487
   * @param int|null $number <p>How many values you will take?</p>
1488
   *
1489
   * @return static <p>(Mutable)</p>
1490
   */
1491
  public function firstsMutable($number = null)
1492
  {
1493
    if ($number === null) {
1494
      $this->array = (array)\array_shift($this->array);
1495
    } else {
1496
      $number = (int)$number;
1497
      $this->array = \array_splice($this->array, 0, $number, true);
1498
    }
1499
1500 1
    return $this;
1501
  }
1502 1
1503
  /**
1504 1
   * Exchanges all keys with their associated values in an array.
1505
   *
1506
   * @return static <p>(Immutable)</p>
1507
   */
1508
  public function flip()
1509
  {
1510
    $result = \array_flip($this->array);
1511
1512
    return static::create($result);
1513
  }
1514 38
1515
  /**
1516 38
   * Get a value from an array (optional using dot-notation).
1517 10
   *
1518
   * @param string $key      <p>The key to look for.</p>
1519 10
   * @param mixed  $fallback <p>Value to fallback to.</p>
1520 2
   * @param array  $array    <p>The array to get from, if it's set to "null" we use the current array from the
1521 2
   *                         class.</p>
1522 8
   *
1523
   * @return mixed
1524 10
   */
1525
  public function get($key, $fallback = null, $array = null)
1526
  {
1527
    if ($array !== null) {
1528 38
      $usedArray = (array)$array;
1529
    } else {
1530 38
      $usedArray = $this->array;
1531
    }
1532
1533
    if ($key === null) {
1534 38
      return static::create($usedArray);
1535
    }
1536
1537
    // php cast "bool"-index into "int"-index
1538
    if ((bool)$key === $key) {
1539
      $key = (int)$key;
1540
    }
1541
1542
    if (\array_key_exists($key, $usedArray) === true) {
1543
      if (is_array($usedArray[$key])) {
1544 1
        return static::create($usedArray[$key]);
1545
      }
1546 1
1547
      return $usedArray[$key];
1548
    }
1549
1550
    // Crawl through array, get key according to object or not
1551
    foreach (\explode($this->pathSeparator, (string)$key) as $segment) {
1552
      if (!isset($usedArray[$segment])) {
1553
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1554 4
      }
1555
1556 4
      $usedArray = $usedArray[$segment];
1557
    }
1558
1559
    if (\is_array($usedArray)) {
1560
      return static::create($usedArray);
1561
    }
1562
1563
    return $usedArray;
1564
  }
1565
1566 3
  /**
1567
   * Get the current array from the "Arrayy"-object.
1568 3
   *
1569
   * @return array
1570
   */
1571
  public function getArray()
1572
  {
1573
    \array_map(array('self', 'internalGetArray'), $this->array);
1574
1575
    return $this->array;
1576
  }
1577
1578 3
  /**
1579
   * Returns the values from a single column of the input array, identified by
1580 3
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1581
   *
1582
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1583
   * array by the values from the $indexKey column in the input array.
1584
   *
1585
   * @param mixed $columnKey
1586
   * @param mixed $indexKey
1587
   *
1588
   * @return static <p>(Immutable)</p>
1589
   */
1590
  public function getColumn($columnKey = null, $indexKey = null)
1591
  {
1592 9
    $result = \array_column($this->array, $columnKey, $indexKey);
1593
1594 9
    return static::create($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by \array_column($this->arr... $columnKey, $indexKey) on line 1592 can also be of type false or null; however, Arrayy\Arrayy::create() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1595
  }
1596
1597
  /**
1598
   * Get correct PHP constant for direction.
1599
   *
1600
   * @param int|string $direction
1601
   *
1602
   * @return int
1603
   */
1604 3
  protected function getDirection($direction)
1605
  {
1606 3
    if (\is_string($direction)) {
1607
      $direction = \strtolower($direction);
1608
1609
      if ($direction === 'desc') {
1610
        $direction = SORT_DESC;
1611
      } else {
1612
        $direction = SORT_ASC;
1613
      }
1614
    }
1615
1616
    if (
1617
        $direction !== SORT_DESC
1618 6
        &&
1619
        $direction !== SORT_ASC
1620 6
    ) {
1621
      $direction = SORT_ASC;
1622
    }
1623
1624
    return $direction;
1625
  }
1626
1627
  /**
1628
   * alias: for "Arrayy->keys()"
1629
   *
1630
   * @see Arrayy::keys()
1631 3
   *
1632
   * @return static <p>(Immutable)</p>
1633 3
   */
1634 3
  public function getKeys()
1635
  {
1636
    return $this->keys();
1637 3
  }
1638
1639 3
  /**
1640 3
   * Get the current array from the "Arrayy"-object as object.
1641
   *
1642 3
   * @return \stdClass (object)
1643
   */
1644
  public function getObject()
1645
  {
1646 3
    return self::arrayToObject($this->getArray());
1647 3
  }
1648 3
1649
  /**
1650
   * alias: for "Arrayy->randomImmutable()"
1651 3
   *
1652 2
   * @see Arrayy::randomImmutable()
1653 1
   *
1654 1
   * @return static <p>(Immutable)</p>
1655 1
   */
1656 1
  public function getRandom()
1657 1
  {
1658
    return $this->randomImmutable();
1659 2
  }
1660
1661 3
  /**
1662
   * alias: for "Arrayy->randomKey()"
1663 3
   *
1664
   * @see Arrayy::randomKey()
1665
   *
1666
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1667
   */
1668
  public function getRandomKey()
1669
  {
1670
    return $this->randomKey();
1671
  }
1672
1673 22
  /**
1674
   * alias: for "Arrayy->randomKeys()"
1675
   *
1676 22
   * @see Arrayy::randomKeys()
1677
   *
1678 22
   * @param int $number
1679
   *
1680
   * @return static <p>(Immutable)</p>
1681
   */
1682
  public function getRandomKeys($number)
1683
  {
1684
    return $this->randomKeys($number);
1685
  }
1686
1687
  /**
1688 28
   * alias: for "Arrayy->randomValue()"
1689
   *
1690 28
   * @see Arrayy::randomValue()
1691
   *
1692
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1693
   */
1694
  public function getRandomValue()
1695
  {
1696
    return $this->randomValue();
1697
  }
1698
1699 28
  /**
1700
   * alias: for "Arrayy->randomValues()"
1701 28
   *
1702 28
   * @see Arrayy::randomValues()
1703
   *
1704 28
   * @param int $number
1705 28
   *
1706 28
   * @return static <p>(Immutable)</p>
1707 28
   */
1708 28
  public function getRandomValues($number)
1709
  {
1710 28
    return $this->randomValues($number);
1711 28
  }
1712
1713
  /**
1714 28
   * Group values from a array according to the results of a closure.
1715
   *
1716
   * @param string $grouper <p>A callable function name.</p>
1717
   * @param bool   $saveKeys
1718
   *
1719
   * @return static <p>(Immutable)</p>
1720
   */
1721
  public function group($grouper, $saveKeys = false)
1722
  {
1723
    $array = (array)$this->array;
1724
    $result = array();
1725
1726
    // Iterate over values, group by property/results from closure
1727
    foreach ($array as $key => $value) {
1728 3
1729
      $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1730 3
      $newValue = $this->get($groupKey, null, $result);
1731
1732 3
      if ($groupKey instanceof self) {
1733 3
        $groupKey = $groupKey->getArray();
1734 2
      }
1735 2
1736 3
      if ($newValue instanceof self) {
1737
        $newValue = $newValue->getArray();
1738 3
      }
1739
1740
      // Add to results
1741
      if ($groupKey !== null) {
1742
        if ($saveKeys) {
1743
          $result[$groupKey] = $newValue;
1744
          $result[$groupKey][$key] = $value;
1745
        } else {
1746
          $result[$groupKey] = $newValue;
1747
          $result[$groupKey][] = $value;
1748
        }
1749
      }
1750 4
1751
    }
1752 4
1753
    return static::create($result);
1754
  }
1755
1756
  /**
1757
   * Check if an array has a given key.
1758
   *
1759
   * @param mixed $key
1760
   *
1761
   * @return bool
1762 12
   */
1763
  public function has($key)
1764 12
  {
1765
    // Generate unique string to use as marker.
1766 12
    $unFound = \uniqid('arrayy', true);
1767
1768
    return $this->get($key, $unFound) !== $unFound;
1769
  }
1770
1771
  /**
1772 446
   * Implodes the keys of this array.
1773
   *
1774 446
   * @param string $glue
1775
   *
1776
   * @return string
1777
   */
1778
  public function implodeKeys($glue = '')
1779
  {
1780
    return self::implode_recursive($glue, $this->array, true);
1781
  }
1782
1783
  /**
1784 446
   * Implodes the values of this array.
1785
   *
1786
   * @param string $glue
1787
   *
1788 446
   * @return string
1789
   */
1790
  public function implode($glue = '')
1791
  {
1792
    return self::implode_recursive($glue, $this->array, false);
1793
  }
1794
1795
  /**
1796
   * @param string              $glue
1797 18
   * @param string|array|Arrayy $pieces
1798
   * @param bool                $useKeys
1799 18
   *
1800
   * @return string
1801
   */
1802 18
  protected function implode_recursive($glue = '', $pieces, $useKeys = false)
1803
  {
1804
    if ($pieces instanceof self) {
1805
      $pieces = $pieces->getArray();
1806
    }
1807
1808
    if (\is_array($pieces)) {
1809
      $pieces_count = \count($pieces);
1810
1811
      return \implode(
1812 18
          $glue,
1813
          \array_map(
1814 18
              array($this, 'implode_recursive'),
1815
              \array_fill(0, ($pieces_count > 0 ? $pieces_count : 1), $glue),
1816 18
              ($useKeys === true ? $this->array_keys_recursive($pieces) : $pieces)
1817
          )
1818
      );
1819
    }
1820
1821
    return (string)$pieces;
1822
  }
1823
1824
  /**
1825
   * Given a list and an iterate-function that returns
1826
   * a key for each element in the list (or a property name),
1827 30
   * returns an object with an index of each item.
1828
   *
1829 30
   * Just like groupBy, but for when you know your keys are unique.
1830
   *
1831
   * @param mixed $key
1832
   *
1833
   * @return static <p>(Immutable)</p>
1834 30
   */
1835 30
  public function indexBy($key)
1836
  {
1837
    $results = array();
1838 30
1839 3
    foreach ($this->array as $a) {
1840
      if (\array_key_exists($key, $a) === true) {
1841
        $results[$a[$key]] = $a;
1842
      }
1843
    }
1844 3
1845
    return static::create($results);
1846
  }
1847
1848 3
  /**
1849 3
   * alias: for "Arrayy->searchIndex()"
1850
   *
1851 30
   * @see Arrayy::searchIndex()
1852
   *
1853 30
   * @param mixed $value <p>The value to search for.</p>
1854
   *
1855
   * @return mixed
1856
   */
1857
  public function indexOf($value)
1858
  {
1859
    return $this->searchIndex($value);
1860
  }
1861
1862
  /**
1863 2
   * Get everything but the last..$to items.
1864
   *
1865 2
   * @param int $to
1866
   *
1867
   * @return static <p>(Immutable)</p>
1868
   */
1869
  public function initial($to = 1)
1870
  {
1871
    $slice = \count($this->array) - $to;
1872
1873
    return $this->firstsImmutable($slice);
1874
  }
1875 1
1876
  /**
1877 1
   * @param mixed $value
1878
   */
1879
  protected function internalGetArray(&$value)
1880
  {
1881
    if ($value instanceof self) {
1882
1883
      $valueTmp = $value->getArray();
1884
      if (\count($valueTmp) === 0) {
1885
        $value = array();
1886
      } else {
1887
        /** @noinspection PhpUnusedLocalVariableInspection */
1888 1
        $value = &$valueTmp;
1889
      }
1890
1891 1
    } elseif ($value instanceof \JsonSerializable) {
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1892 1
      /** @noinspection PhpUnusedLocalVariableInspection */
1893 1
      $value = &$value->jsonSerialize();
1894
    }
1895
  }
1896 1
1897 1
  /**
1898 1
   * Internal mechanics of remove method.
1899 1
   *
1900
   * @param string $key
1901
   *
1902 1
   * @return boolean
1903
   */
1904
  protected function internalRemove($key)
1905
  {
1906
    $path = \explode($this->pathSeparator, (string)$key);
1907
1908
    // Crawl though the keys
1909
    while (\count($path) > 1) {
1910 15
      $key = \array_shift($path);
1911
1912 15
      if (!$this->has($key)) {
1913 3
        return false;
1914
      }
1915
1916 13
      $this->array = &$this->array[$key];
1917 13
    }
1918 11
1919
    $key = \array_shift($path);
1920 3
1921
    unset($this->array[$key]);
1922 3
1923
    return true;
1924
  }
1925
1926
  /**
1927
   * Internal mechanic of set method.
1928
   *
1929
   * @param string $key
1930 88
   * @param mixed  $value
1931
   *
1932 88
   * @return bool
1933
   */
1934
  protected function internalSet($key, $value)
1935
  {
1936
    if ($key === null) {
1937
      return false;
1938
    }
1939
1940
    // init
1941
    $array =& $this->array;
1942
    $path = \explode($this->pathSeparator, (string)$key);
1943
1944
    // Crawl through the keys
1945
    while (count($path) > 1) {
1946
      $key = \array_shift($path);
1947
1948
      // If the key doesn't exist at this depth, we will just create an empty array
1949
      // to hold the next value, allowing us to create the arrays to hold final
1950
      // values at the correct depth. Then we'll keep digging into the array.
1951
      if (!isset($array[$key]) || !\is_array($array[$key])) {
1952 14
        $array[$key] = static::create(array());
1953
      }
1954 14
1955
      $array =& $array[$key];
1956
    }
1957
1958
    $array[\array_shift($path)] = $value;
1959
1960
    return true;
1961
  }
1962 5
1963
  /**
1964 5
   * Return an array with all elements found in input array.
1965 2
   *
1966
   * @param array $search
1967
   *
1968 4
   * @return static <p>(Immutable)</p>
1969 4
   */
1970 2
  public function intersection(array $search)
1971
  {
1972 3
    return static::create(\array_values(\array_intersect($this->array, $search)));
1973
  }
1974 2
1975
  /**
1976
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1977
   *
1978
   * @param array $search
1979
   *
1980
   * @return bool
1981
   */
1982 1
  public function intersects(array $search)
1983
  {
1984 1
    return \count($this->intersection($search)->array) > 0;
1985
  }
1986
1987
  /**
1988
   * Invoke a function on all of an array's values.
1989
   *
1990
   * @param mixed $callable
1991
   * @param mixed $arguments
1992
   *
1993
   * @return static <p>(Immutable)</p>
1994
   */
1995
  public function invoke($callable, $arguments = array())
1996
  {
1997
    // If one argument given for each iteration, create an array for it.
1998
    if (!\is_array($arguments)) {
1999
      $arguments = StaticArrayy::repeat($arguments, \count($this->array))->getArray();
2000 25
    }
2001
2002 25
    // If the callable has arguments, pass them.
2003
    if ($arguments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arguments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2004
      $array = \array_map($callable, $this->array, $arguments);
2005
    } else {
2006
      $array = \array_map($callable, $this->array);
2007
    }
2008
2009
    return static::create($array);
2010
  }
2011
2012
  /**
2013
   * Check whether array is associative or not.
2014
   *
2015
   * @param bool $recursive
2016 4
   *
2017
   * @return bool <p>Returns true if associative, false otherwise.</p>
2018 4
   */
2019
  public function isAssoc($recursive = false)
2020 4
  {
2021
    if ($this->isEmpty()) {
2022
      return false;
2023
    }
2024
2025
    foreach ($this->keys($recursive)->getArray() as $key) {
2026
      if (!is_string($key)) {
2027
        return false;
2028 4
      }
2029
    }
2030 4
2031
    return true;
2032
  }
2033
2034
  /**
2035
   * Check whether the array is empty or not.
2036
   *
2037
   * @return bool <p>Returns true if empty, false otherwise.</p>
2038
   */
2039
  public function isEmpty()
2040 13
  {
2041
    return !$this->array;
2042 13
  }
2043 1
2044
  /**
2045
   * Check if the current array is equal to the given "$array" or not.
2046 12
   *
2047 8
   * @param array $array
2048
   *
2049 8
   * @return bool
2050 1
   */
2051 1
  public function isEqual(array $array)
2052 7
  {
2053
    return ($this->array === $array);
2054
  }
2055 8
2056 8
  /**
2057 4
   * Check if the current array is a multi-array.
2058 4
   *
2059
   * @return bool
2060
   */
2061 12
  public function isMultiArray()
2062
  {
2063
    return !(\count($this->array) === \count($this->array, COUNT_RECURSIVE));
2064
  }
2065
2066
  /**
2067
   * Check whether array is numeric or not.
2068
   *
2069
   * @return bool <p>Returns true if numeric, false otherwise.</p>
2070
   */
2071 13
  public function isNumeric()
2072
  {
2073 13
    if ($this->isEmpty()) {
2074 1
      return false;
2075
    }
2076
2077 12
    foreach ($this->keys() as $key) {
2078 8
      if (!is_int($key)) {
2079
        return false;
2080 8
      }
2081 1
    }
2082 1
2083 7
    return true;
2084
  }
2085
2086 8
  /**
2087 8
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2088 4
   *
2089 4
   * @param bool $recursive
2090
   *
2091
   * @return bool
2092 12
   */
2093
  public function isSequential($recursive = false)
2094
  {
2095
    if ($recursive === true) {
2096
      return $this->array_keys_recursive($this->array) === range(0, count($this->array, COUNT_RECURSIVE) - 1);
2097
    }
2098
2099
    return \array_keys($this->array) === range(0, count($this->array) - 1);
2100
  }
2101
2102
  /**
2103
   * @return array
2104 10
   */
2105
  public function jsonSerialize()
2106 10
  {
2107
    return $this->getArray();
2108
  }
2109
2110
  /**
2111
   * Get all keys from the current array.
2112
   *
2113
   * @param bool  $recursive    [optional] <p>
2114
   *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2115
   *                            </p>
2116
   * @param mixed $search_value [optional] <p>
2117 4
   *                            If specified, then only keys containing these values are returned.
2118
   *                            </p>
2119 4
   * @param bool  $strict       [optional] <p>
2120
   *                            Determines if strict comparison (===) should be used during the search.
2121 4
   *                            </p>
2122
   *
2123
   * @return static <p>(Immutable) An array of all the keys in input.</p>
2124
   */
2125
  public function keys($recursive = false, $search_value = null, $strict = true)
2126
  {
2127
    if ($recursive === true) {
2128
      if ($search_value === null) {
2129
        $array = $this->array_keys_recursive($this->array);
2130
      } else {
2131 15
        $array = $this->array_keys_recursive($this->array, $search_value, $strict);
2132
      }
2133 15
    } else {
2134 2
      if ($search_value === null) {
2135
        $array = \array_keys($this->array);
2136
      } else {
2137
        $array = \array_keys($this->array, $search_value, $strict);
2138 13
      }
2139
    }
2140 13
2141 13
    return static::create($array);
2142
  }
2143 13
2144 7
  /**
2145
   * @param array $input        <p>
2146 9
   *                            An array containing keys to return.
2147
   *                            </p>
2148 7
   * @param mixed $search_value [optional] <p>
2149
   *                            If specified, then only keys containing these values are returned.
2150
   *                            </p>
2151
   * @param bool  $strict       [optional] <p>
2152
   *                            Determines if strict comparison (===) should be used during the search.
2153
   *                            </p>
2154
   *
2155
   * @return array an array of all the keys in input.
2156
   */
2157
  protected function array_keys_recursive(array $input = null, $search_value = null, $strict = true)
2158 14
  {
2159
    // init
2160 14
    $keys = array();
2161 2
2162
    if ($input === null) {
2163
      $input = $this->array;
2164
    }
2165 12
2166
    foreach ($input as $key => $value) {
2167 12
2168 12
      if (
2169
          $search_value === null
2170 12
          ||
2171 9
          (
2172
              \is_array($search_value) === true
2173 5
              &&
2174
              \in_array($key, $search_value, $strict)
2175 4
          )
2176
      ) {
2177
        $keys[] = $key;
2178
      }
2179
2180
      // recursive needed?
2181
      if (\is_array($value) === true) {
2182
        $keys = \array_merge($keys, $this->array_keys_recursive($value));
2183 10
      }
2184
    }
2185 10
2186 1
    return $keys;
2187
  }
2188
2189 9
  /**
2190
   * Sort an array by key in reverse order.
2191
   *
2192
   * @param int $sort_flags [optional] <p>
2193
   *                        You may modify the behavior of the sort using the optional
2194
   *                        parameter sort_flags, for details
2195
   *                        see sort.
2196
   *                        </p>
2197
   *
2198
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2199
   */
2200
  public function krsort($sort_flags = null)
2201
  {
2202 25
    krsort($this->array, $sort_flags);
2203
2204 25
    return $this;
2205 4
  }
2206 4
2207 21
  /**
2208
   * Get the last value from the current array.
2209
   *
2210 25
   * @return mixed <p>Return null if there wasn't a element.</p>
2211
   */
2212
  public function last()
2213
  {
2214
    return $this->pop();
2215
  }
2216
2217
  /**
2218
   * Get the last value(s) from the current array.
2219
   *
2220
   * @param int|null $number
2221
   *
2222
   * @return static <p>(Immutable)</p>
2223
   */
2224 16
  public function lastsImmutable($number = null)
2225
  {
2226 16
    if ($this->isEmpty()) {
2227 4
      return static::create();
2228 4
    }
2229 12
2230
    if ($number === null) {
2231
      $poppedValue = $this->pop();
2232 16
2233
      if ($poppedValue === null) {
2234
        $poppedValue = array($poppedValue);
2235
      } else {
2236
        $poppedValue = (array)$poppedValue;
2237
      }
2238
2239
      $arrayy = static::create($poppedValue);
2240
    } else {
2241
      $number = (int)$number;
2242
      $arrayy = $this->rest(-$number);
2243
    }
2244
2245 16
    return $arrayy;
2246
  }
2247 16
2248 4
  /**
2249 4
   * Get the last value(s) from the current array.
2250 12
   *
2251
   * @param int|null $number
2252
   *
2253 16
   * @return static <p>(Mutable)</p>
2254
   */
2255
  public function lastsMutable($number = null)
2256
  {
2257
    if ($this->isEmpty()) {
2258
      return $this;
2259
    }
2260
2261
    if ($number === null) {
2262
      $poppedValue = $this->pop();
2263
2264
      if ($poppedValue === null) {
2265
        $poppedValue = array($poppedValue);
2266
      } else {
2267 17
        $poppedValue = (array)$poppedValue;
2268
      }
2269 17
2270 4
      $this->array = static::create($poppedValue)->array;
2271 4
    } else {
2272 13
      $number = (int)$number;
2273
      $this->array = $this->rest(-$number)->array;
2274
    }
2275 17
2276
    return $this;
2277
  }
2278
2279
  /**
2280
   * Count the values from the current array.
2281
   *
2282
   * alias: for "Arrayy->size()"
2283 10
   *
2284
   * @see Arrayy::size()
2285 10
   *
2286 1
   * @param int $mode
2287
   *
2288
   * @return int
2289 9
   */
2290
  public function length($mode = COUNT_NORMAL)
2291
  {
2292
    return $this->size($mode);
2293
  }
2294
2295
  /**
2296
   * Apply the given function to the every element of the array,
2297
   * collecting the results.
2298
   *
2299
   * @param callable $callable
2300
   *
2301
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
2302 1
   */
2303
  public function map($callable)
2304 1
  {
2305
    $result = \array_map($callable, $this->array);
2306 1
2307 1
    return static::create($result);
2308 1
  }
2309 1
2310 1
  /**
2311 1
   * Check if all items in current array match a truth test.
2312 1
   *
2313 1
   * @param \Closure $closure
2314 1
   *
2315 1
   * @return bool
2316 1
   */
2317 1 View Code Duplication
  public function matches(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2318 1
  {
2319 1
    if (\count($this->array) === 0) {
2320 1
      return false;
2321 1
    }
2322 1
2323 1
    // init
2324
    $array = $this->array;
2325
2326
    foreach ($array as $key => $value) {
2327 1
      $value = $closure($value, $key);
2328
2329
      if ($value === false) {
2330
        return false;
2331
      }
2332
    }
2333
2334
    return true;
2335
  }
2336
2337 5
  /**
2338
   * Check if any item in the current array matches a truth test.
2339 5
   *
2340 4
   * @param \Closure $closure
2341
   *
2342
   * @return bool
2343 5
   */
2344 5 View Code Duplication
  public function matchesAny(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2345 5
  {
2346
    if (\count($this->array) === 0) {
2347 5
      return false;
2348
    }
2349
2350
    // init
2351
    $array = $this->array;
2352
2353
    foreach ($array as $key => $value) {
2354
      $value = $closure($value, $key);
2355
2356
      if ($value === true) {
2357
        return true;
2358
      }
2359
    }
2360
2361
    return false;
2362
  }
2363
2364
  /**
2365
   * Get the max value from an array.
2366
   *
2367
   * @return mixed
2368
   */
2369
  public function max()
2370
  {
2371
    if ($this->count() === 0) {
2372 4
      return false;
2373
    }
2374 4
2375
    return max($this->array);
2376 4
  }
2377
2378
  /**
2379
   * Merge the new $array into the current array.
2380
   *
2381
   * - keep key,value from the current array, also if the index is in the new $array
2382
   *
2383
   * @param array $array
2384 16
   * @param bool  $recursive
2385
   *
2386 16
   * @return static <p>(Immutable)</p>
2387
   */
2388 View Code Duplication
  public function mergeAppendKeepIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2389
  {
2390
    if (true === $recursive) {
2391
      $result = \array_replace_recursive($this->array, $array);
2392
    } else {
2393
      $result = \array_replace($this->array, $array);
2394
    }
2395
2396
    return static::create($result);
2397 8
  }
2398
2399 8
  /**
2400 8
   * Merge the new $array into the current array.
2401 8
   *
2402
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2403 1
   * - create new indexes
2404
   *
2405
   * @param array $array
2406 8
   * @param bool  $recursive
2407
   *
2408
   * @return static <p>(Immutable)</p>
2409
   */
2410 View Code Duplication
  public function mergeAppendNewIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2411
  {
2412
    if (true === $recursive) {
2413
      $result = \array_merge_recursive($this->array, $array);
2414
    } else {
2415
      $result = \array_merge($this->array, $array);
2416 10
    }
2417
2418 10
    return static::create($result);
2419 10
  }
2420 9
2421
  /**
2422 9
   * Merge the the current array into the $array.
2423
   *
2424
   * - use key,value from the new $array, also if the index is in the current array
2425 9
   *
2426
   * @param array $array
2427
   * @param bool  $recursive
2428 10
   *
2429
   * @return static <p>(Immutable)</p>
2430 10
   */
2431 View Code Duplication
  public function mergePrependKeepIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2432
  {
2433
    if (true === $recursive) {
2434
      $result = \array_replace_recursive($array, $this->array);
2435
    } else {
2436
      $result = \array_replace($array, $this->array);
2437
    }
2438
2439
    return static::create($result);
2440 10
  }
2441
2442 10
  /**
2443 10
   * Merge the current array into the new $array.
2444 9
   *
2445
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
2446 9
   * - create new indexes
2447
   *
2448 9
   * @param array $array
2449 1
   * @param bool  $recursive
2450 1
   *
2451 8
   * @return static <p>(Immutable)</p>
2452
   */
2453 10 View Code Duplication
  public function mergePrependNewIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2454
  {
2455 10
    if (true === $recursive) {
2456
      $result = \array_merge_recursive($array, $this->array);
2457
    } else {
2458
      $result = \array_merge($array, $this->array);
2459
    }
2460
2461
    return static::create($result);
2462
  }
2463 4
2464
  /**
2465 4
   * Get the min value from an array.
2466 4
   *
2467 4
   * @return mixed
2468 4
   */
2469
  public function min()
2470 4
  {
2471
    if ($this->count() === 0) {
2472
      return false;
2473
    }
2474
2475
    return min($this->array);
2476
  }
2477
2478
  /**
2479
   * Move an array element to a new index.
2480 17
   *
2481
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2482 17
   *
2483
   * @param int|string $from
2484
   * @param int|string $to
2485
   *
2486 17
   * @return static <p>(Immutable)</p>
2487 14
   */
2488
  public function moveElement($from, $to)
2489 14
  {
2490
    $array = $this->array;
2491
2492 5
    if (is_int($from)) {
2493 5
      $tmp = \array_splice($array, $from, 1);
2494
      \array_splice($array, $to, 0, $tmp);
2495 5
      $output = $array;
2496
    } elseif (is_string($from)) {
2497
      $indexToMove = \array_search($from, \array_keys($array), true);
2498
      $itemToMove = $array[$from];
2499
      \array_splice($array, $indexToMove, 1);
2500
      $i = 0;
2501
      $output = array();
2502
      foreach ($array as $key => $item) {
2503
        if ($i == $to) {
2504
          $output[$from] = $itemToMove;
2505 4
        }
2506
        $output[$key] = $item;
2507 4
        $i++;
2508
      }
2509 4
    } else {
2510
      $output = array();
2511
    }
2512
2513 4
    return static::create($output);
2514
  }
2515
2516
  /**
2517
   * Convert a object into an array.
2518
   *
2519
   * @param object $object
2520
   *
2521
   * @return mixed
2522
   */
2523
  protected static function objectToArray($object)
2524
  {
2525 14
    if (!\is_object($object)) {
2526
      return $object;
2527 14
    }
2528 14
2529
    if (\is_object($object)) {
2530 14
      $object = \get_object_vars($object);
2531 3
    }
2532 3
2533 3
    return \array_map(array('self', 'objectToArray'), $object);
2534 3
  }
2535
2536 3
  /**
2537 3
   * Get a subset of the items from the given array.
2538
   *
2539
   * @param mixed[] $keys
2540 11
   *
2541
   * @return static <p>(Immutable)</p>
2542 11
   */
2543
  public function only(array $keys)
2544
  {
2545
    $array = $this->array;
2546
2547
    return static::create(\array_intersect_key($array, \array_flip($keys)));
2548
  }
2549
2550
  /**
2551
   * Pad array to the specified size with a given value.
2552 17
   *
2553
   * @param int   $size  <p>Size of the result array.</p>
2554 17
   * @param mixed $value <p>Empty value by default.</p>
2555
   *
2556
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
2557
   */
2558 17
  public function pad($size, $value)
2559 7
  {
2560 7
    $result = \array_pad($this->array, $size, $value);
2561
2562 7
    return static::create($result);
2563
  }
2564
2565 11
  /**
2566
   * Pop a specified value off the end of the current array.
2567 11
   *
2568
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
2569
   */
2570
  public function pop()
2571
  {
2572
    return \array_pop($this->array);
2573
  }
2574
2575 4
  /**
2576
   * Prepend a (key) + value to the current array.
2577 4
   *
2578
   * @param mixed $value
2579 4
   * @param mixed $key
2580
   *
2581
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2582
   */
2583 4
  public function prepend($value, $key = null)
2584
  {
2585
    if ($key === null) {
2586
      \array_unshift($this->array, $value);
2587
    } else {
2588
      /** @noinspection AdditionOperationOnArraysInspection */
2589
      $this->array = array($key => $value) + $this->array;
2590
    }
2591
2592
    return $this;
2593 7
  }
2594
2595 7
  /**
2596
   * Add a suffix to each key.
2597 7
   *
2598
   * @param string $suffix
2599
   *
2600
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2601
   */
2602 View Code Duplication
  public function prependToEachKey($suffix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2603
  {
2604
    $result = array();
2605
    foreach ($this->array as $key => $item) {
2606
      if ($item instanceof self) {
2607
        $result[$key] = $item->prependToEachKey($suffix);
2608
      } elseif (\is_array($item)) {
2609
        $result[$key] = self::create($item)->prependToEachKey($suffix)->toArray();
2610 9
      } else {
2611
        $result[$key . $suffix] = $item;
2612 9
      }
2613 9
2614 9
    }
2615 2
2616 1
    return self::create($result);
2617 1
  }
2618 2
2619 9
  /**
2620
   * Add a suffix to each value.
2621 9
   *
2622
   * @param mixed $suffix
2623
   *
2624
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2625
   */
2626 View Code Duplication
  public function prependToEachValue($suffix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2627
  {
2628
    $result = array();
2629
    foreach ($this->array as $key => $item) {
2630
      if ($item instanceof self) {
2631
        $result[$key] = $item->prependToEachValue($suffix);
2632 4
      } elseif (\is_array($item)) {
2633
        $result[$key] = self::create($item)->prependToEachValue($suffix)->toArray();
2634 4
      } elseif (\is_object($item)) {
2635
        $result[$key] = $item;
2636 4
      } else {
2637
        $result[$key] = $item . $suffix;
2638
      }
2639 4
    }
2640
2641
    return self::create($result);
2642 4
  }
2643
2644
  /**
2645
   * Push one or more values onto the end of array at once.
2646
   *
2647
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2648
   */
2649 View Code Duplication
  public function push(/* variadic arguments allowed */)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2650 9
  {
2651
    if (\func_num_args()) {
2652 9
      $args = \array_merge(array(&$this->array), \func_get_args());
2653
      \call_user_func_array('array_push', $args);
2654 9
    }
2655
2656
    return $this;
2657
  }
2658
2659
  /**
2660
   * Get a random value from the current array.
2661
   *
2662
   * @param null|int $number <p>How many values you will take?</p>
2663
   *
2664 1
   * @return static <p>(Immutable)</p>
2665
   */
2666 1
  public function randomImmutable($number = null)
2667
  {
2668 1
    if ($this->count() === 0) {
2669 1
      return static::create();
2670 1
    }
2671 1
2672 1 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2673
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2674 1
2675
      return static::create($arrayRandValue);
2676
    }
2677
2678
    $arrayTmp = $this->array;
2679
    \shuffle($arrayTmp);
2680
2681
    return static::create($arrayTmp)->firstsImmutable($number);
2682
  }
2683
2684 18
  /**
2685
   * Pick a random key/index from the keys of this array.
2686
   *
2687 18
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
2688
   *
2689
   * @throws \RangeException If array is empty
2690
   */
2691
  public function randomKey()
2692
  {
2693
    $result = $this->randomKeys(1);
2694
2695 18
    if (!isset($result[0])) {
2696
      $result[0] = null;
2697 18
    }
2698
2699
    return $result[0];
2700
  }
2701
2702
  /**
2703
   * Pick a given number of random keys/indexes out of this array.
2704
   *
2705 7
   * @param int $number <p>The number of keys/indexes (should be <= $this->count())</p>
2706
   *
2707 7
   * @return static <p>(Immutable)</p>
2708 7
   *
2709
   * @throws \RangeException If array is empty
2710 7
   */
2711
  public function randomKeys($number)
2712
  {
2713
    $number = (int)$number;
2714
    $count = $this->count();
2715
2716
    if ($number === 0 || $number > $count) {
2717
      throw new \RangeException(
2718 7
          \sprintf(
2719
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2720 7
              $number,
2721 7
              $count
2722
          )
2723 7
      );
2724
    }
2725
2726
    $result = (array)\array_rand($this->array, $number);
2727
2728
    return static::create($result);
2729
  }
2730
2731
  /**
2732
   * Get a random value from the current array.
2733 7
   *
2734
   * @param null|int $number <p>How many values you will take?</p>
2735 7
   *
2736 7
   * @return static <p>(Mutable)</p>
2737 6
   */
2738 6
  public function randomMutable($number = null)
2739
  {
2740
    if ($this->count() === 0) {
2741 6
      return static::create();
2742 6
    }
2743 7
2744 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2745 7
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2746 7
      $this->array = $arrayRandValue;
2747 7
2748
      return $this;
2749 7
    }
2750
2751
    \shuffle($this->array);
2752
2753
    return $this->firstsMutable($number);
2754
  }
2755
2756
  /**
2757
   * Pick a random value from the values of this array.
2758
   *
2759 1
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2760
   */
2761 1
  public function randomValue()
2762 1
  {
2763
    $result = $this->randomImmutable();
2764
2765 1
    if (!isset($result[0])) {
2766
      $result[0] = null;
2767
    }
2768
2769
    return $result[0];
2770
  }
2771
2772
  /**
2773
   * Pick a given number of random values out of this array.
2774
   *
2775
   * @param int $number
2776
   *
2777 2
   * @return static <p>(Mutable)</p>
2778
   */
2779 2
  public function randomValues($number)
2780
  {
2781 2
    $number = (int)$number;
2782
2783
    return $this->randomMutable($number);
2784
  }
2785
2786
  /**
2787
   * Get a random value from an array, with the ability to skew the results.
2788
   *
2789
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2790
   *
2791 2
   * @param array    $array
2792
   * @param null|int $number <p>How many values you will take?</p>
2793 2
   *
2794
   * @return static <p>(Immutable)</p>
2795 2
   */
2796
  public function randomWeighted(array $array, $number = null)
2797
  {
2798
    $options = array();
2799
    foreach ($array as $option => $weight) {
2800
      if ($this->searchIndex($option) !== false) {
2801
        for ($i = 0; $i < $weight; ++$i) {
2802
          $options[] = $option;
2803
        }
2804
      }
2805 2
    }
2806
2807 2
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2808
  }
2809 2
2810
  /**
2811
   * Reduce the current array via callable e.g. anonymous-function.
2812
   *
2813
   * @param mixed $callable
2814
   * @param array $init
2815
   *
2816
   * @return static <p>(Immutable)</p>
2817
   */
2818
  public function reduce($callable, array $init = array())
2819 1
  {
2820
    $result = \array_reduce($this->array, $callable, $init);
2821 1
2822 1
    if ($result === null) {
2823
      $this->array = array();
2824 1
    } else {
2825
      $this->array = (array)$result;
2826
    }
2827
2828
    return static::create($this->array);
2829
  }
2830
2831
  /**
2832
   * Create a numerically re-indexed Arrayy object.
2833
   *
2834
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2835 3
   */
2836
  public function reindex()
2837 3
  {
2838 3
    $this->array = \array_values($this->array);
2839
2840 3
    return $this;
2841 3
  }
2842 3
2843
  /**
2844 3
   * Return all items that fail the truth test.
2845
   *
2846
   * @param \Closure $closure
2847
   *
2848
   * @return static <p>(Immutable)</p>
2849
   */
2850 View Code Duplication
  public function reject(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2851
  {
2852
    $filtered = array();
2853
2854
    foreach ($this->array as $key => $value) {
2855 1
      if (!$closure($value, $key)) {
2856
        $filtered[$key] = $value;
2857 1
      }
2858
    }
2859 1
2860
    return static::create($filtered);
2861 1
  }
2862
2863 1
  /**
2864
   * Remove a value from the current array (optional using dot-notation).
2865
   *
2866
   * @param mixed $key
2867
   *
2868
   * @return static <p>(Immutable)</p>
2869
   */
2870
  public function remove($key)
2871
  {
2872
    // recursive call
2873 15
    if (\is_array($key)) {
2874
      foreach ($key as $k) {
2875 15
        $this->internalRemove($k);
2876
      }
2877 15
2878
      return static::create($this->array);
2879
    }
2880
2881
    $this->internalRemove($key);
2882
2883
    return static::create($this->array);
2884
  }
2885 8
2886
  /**
2887 8
   * Remove the first value from the current array.
2888
   *
2889 8
   * @return static <p>(Immutable)</p>
2890
   */
2891
  public function removeFirst()
2892
  {
2893
    $tmpArray = $this->array;
2894
    \array_shift($tmpArray);
2895
2896
    return static::create($tmpArray);
2897
  }
2898
2899
  /**
2900
   * Remove the last value from the current array.
2901
   *
2902
   * @return static <p>(Immutable)</p>
2903 4
   */
2904
  public function removeLast()
2905 4
  {
2906
    $tmpArray = $this->array;
2907 4
    \array_pop($tmpArray);
2908
2909
    return static::create($tmpArray);
2910
  }
2911
2912
  /**
2913
   * Removes a particular value from an array (numeric or associative).
2914
   *
2915
   * @param mixed $value
2916
   *
2917 20
   * @return static <p>(Immutable)</p>
2918
   */
2919 20
  public function removeValue($value)
2920
  {
2921
    $isNumericArray = true;
2922
    foreach ($this->array as $key => $item) {
2923
      if ($item === $value) {
2924
        if (!\is_int($key)) {
2925
          $isNumericArray = false;
2926
        }
2927
        unset($this->array[$key]);
2928
      }
2929 9
    }
2930
2931
    if ($isNumericArray) {
2932 9
      $this->array = \array_values($this->array);
2933
    }
2934 9
2935
    return static::create($this->array);
2936
  }
2937
2938
  /**
2939 9
   * Generate array of repeated arrays.
2940 1
   *
2941 1
   * @param int $times <p>How many times has to be repeated.</p>
2942
   *
2943 9
   * @return Arrayy
2944 7
   */
2945 7
  public function repeat($times)
2946
  {
2947
    if ($times === 0) {
2948 9
      return new static();
2949
    }
2950
2951
    return static::create(\array_fill(0, (int)$times, $this->array));
2952
  }
2953
2954
  /**
2955
   * Replace a key with a new key/value pair.
2956
   *
2957
   * @param $replace
2958
   * @param $key
2959 17
   * @param $value
2960
   *
2961 17
   * @return static <p>(Immutable)</p>
2962
   */
2963 17
  public function replace($replace, $key, $value)
2964
  {
2965
    $this->remove($replace);
2966
2967
    return $this->set($key, $value);
2968
  }
2969
2970
  /**
2971
   * Create an array using the current array as values and the other array as keys.
2972
   *
2973
   * @param array $keys <p>An array of keys.</p>
2974
   *
2975
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
2976 11
   */
2977
  public function replaceAllKeys(array $keys)
2978
  {
2979 11
    $result = \array_combine($keys, $this->array);
2980 4
2981 4
    return static::create($result);
2982
  }
2983 11
2984
  /**
2985
   * Create an array using the current array as keys and the other array as values.
2986
   *
2987
   * @param array $array <p>An array o values.</p>
2988
   *
2989
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
2990
   */
2991 4
  public function replaceAllValues(array $array)
2992
  {
2993 4
    $result = \array_combine($this->array, $array);
2994
2995
    return static::create($result);
2996
  }
2997
2998
  /**
2999
   * Replace the keys in an array with another set.
3000
   *
3001
   * @param array $keys <p>An array of keys matching the array's size</p>
3002
   *
3003 1
   * @return static <p>(Immutable)</p>
3004
   */
3005 1
  public function replaceKeys(array $keys)
3006
  {
3007 1
    $values = \array_values($this->array);
3008 1
    $result = \array_combine($keys, $values);
3009 1
3010 1
    return static::create($result);
3011 1
  }
3012 1
3013 1
  /**
3014 1
   * Replace the first matched value in an array.
3015 1
   *
3016 1
   * @param mixed $search
3017 1
   * @param mixed $replacement
3018 1
   *
3019 1
   * @return static <p>(Immutable)</p>
3020
   */
3021
  public function replaceOneValue($search, $replacement = '')
3022 1
  {
3023
    $array = $this->array;
3024
    $key = \array_search($search, $array, true);
3025 1
3026
    if ($key !== false) {
3027
      $array[$key] = $replacement;
3028
    }
3029
3030
    return static::create($array);
3031
  }
3032
3033 93
  /**
3034
   * Replace values in the current array.
3035 93
   *
3036
   * @param string $search      <p>The string to replace.</p>
3037
   * @param string $replacement <p>What to replace it with.</p>
3038
   *
3039
   * @return static <p>(Immutable)</p>
3040
   */
3041
  public function replaceValues($search, $replacement = '')
3042
  {
3043
    $array = $this->each(
3044
        function ($value) use ($search, $replacement) {
3045
          return UTF8::str_replace($search, $replacement, $value);
3046
        }
3047 4
    );
3048
3049 4
    return $array;
3050
  }
3051 4
3052
  /**
3053
   * Get the last elements from index $from until the end of this array.
3054
   *
3055
   * @param int $from
3056
   *
3057
   * @return static <p>(Immutable)</p>
3058
   */
3059
  public function rest($from = 1)
3060
  {
3061
    $tmpArray = $this->array;
3062
3063
    return static::create(\array_splice($tmpArray, $from));
3064 19
  }
3065
3066 19
  /**
3067
   * Return the array in the reverse order.
3068 19
   *
3069
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3070
   */
3071
  public function reverse()
3072
  {
3073
    $this->array = \array_reverse($this->array);
3074
3075
    return $this;
3076
  }
3077
3078
  /**
3079
   * Sort an array in reverse order.
3080
   *
3081
   * @param int $sort_flags [optional] <p>
3082
   *                        You may modify the behavior of the sort using the optional
3083 18
   *                        parameter sort_flags, for details
3084
   *                        see sort.
3085 18
   *                        </p>
3086
   *
3087 18
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3088
   */
3089
  public function rsort($sort_flags = null)
3090
  {
3091
    \rsort($this->array, $sort_flags);
3092
3093
    return $this;
3094
  }
3095
3096
  /**
3097
   * Search for the first index of the current array via $value.
3098 1
   *
3099
   * @param mixed $value
3100 1
   *
3101
   * @return int|float|string
3102
   */
3103
  public function searchIndex($value)
3104
  {
3105
    return \array_search($value, $this->array, true);
3106
  }
3107
3108
  /**
3109
   * Search for the value of the current array via $index.
3110
   *
3111 1
   * @param mixed $index
3112
   *
3113 1
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3114
   */
3115
  public function searchValue($index)
3116
  {
3117
    // init
3118
    $return = array();
3119
3120
    if ($this->isEmpty()) {
3121
      return static::create();
3122
    }
3123
3124
    // php cast "bool"-index into "int"-index
3125
    if ((bool)$index === $index) {
3126
      $index = (int)$index;
3127
    }
3128
3129 1
    if (\array_key_exists($index, $this->array) === true) {
3130
      $return = array($this->array[$index]);
3131 1
    }
3132 1
3133
3134
    return static::create($return);
3135 1
  }
3136 1
3137
  /**
3138 1
   * Set a value for the current array (optional using dot-notation).
3139 1
   *
3140
   * @param string $key   <p>The key to set.</p>
3141 1
   * @param mixed  $value <p>Its value.</p>
3142
   *
3143 1
   * @return static <p>(Immutable)</p>
3144
   */
3145 1
  public function set($key, $value)
3146 1
  {
3147 1
    $this->internalSet($key, $value);
3148
3149
    return static::create($this->array);
3150
  }
3151 1
3152
  /**
3153 1
   * Get a value from a array and set it if it was not.
3154
   *
3155
   * WARNING: this method only set the value, if the $key is not already set
3156
   *
3157
   * @param string $key      <p>The key</p>
3158
   * @param mixed  $fallback <p>The default value to set if it isn't.</p>
3159
   *
3160
   * @return mixed <p>(Mutable)</p>
3161
   */
3162
  public function setAndGet($key, $fallback = null)
3163
  {
3164
    // If the key doesn't exist, set it.
3165 18
    if (!$this->has($key)) {
3166
      $this->array = $this->set($key, $fallback)->getArray();
3167 18
    }
3168
3169
    return $this->get($key);
3170 18
  }
3171 18
3172 6
  /**
3173 6
   * Shifts a specified value off the beginning of array.
3174 13
   *
3175 13
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
3176 13
   */
3177 13
  public function shift()
3178 13
  {
3179
    return \array_shift($this->array);
3180 18
  }
3181
3182
  /**
3183
   * Shuffle the current array.
3184
   *
3185
   * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3186
   * @param array $array  [optional]
3187
   *
3188
   * @return static <p>(Immutable)</p>
3189
   */
3190
  public function shuffle($secure = false, array $array = null)
3191
  {
3192 19
    if ($array === null) {
3193
      $array = $this->array;
3194 19
    }
3195
3196 19
    if ($secure !== true) {
3197 19
      \shuffle($array);
3198 19
    } else {
3199
      $size = \count($array);
3200
      $keys = \array_keys($array);
3201 19
      for ($i = $size - 1; $i > 0; --$i) {
3202 19
        $r = \random_int(0, $i);
3203 9
        if ($r !== $i) {
3204 5
          $temp = $array[$keys[$r]];
3205 5
          $array[$keys[$r]] = $array[$keys[$i]];
3206 4
          $array[$keys[$i]] = $temp;
3207
        }
3208 9
      }
3209 10
3210 10
      // Reset indices
3211 10
      $array = \array_values($array);
3212 10
    }
3213 4
3214 4
    foreach ($array as $key => $value) {
3215 6
      // recursive needed?
3216
      if (\is_array($value) === true) {
3217 10
        $array[$key] = $this->shuffle($secure, $value);
3218
      }
3219 19
    }
3220
3221
    return static::create($array);
3222
  }
3223
3224
  /**
3225
   * Counts all elements in an array, or something in an object.
3226
   * <p>For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3227
   * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3228
   * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3229
   * implemented and used in PHP.
3230 1
   *
3231
   * @return int the number of elements in var, which is
3232 1
   * typically an array, since anything else will have one
3233
   * element.
3234 1
   * </p>
3235 1
   * <p>
3236 1
   * If var is not an array or an object with
3237 1
   * implemented Countable interface,
3238 1
   * 1 will be returned.
3239 1
   * There is one exception, if var is &null;,
3240
   * 0 will be returned.
3241
   * </p>
3242 1
   * <p>
3243
   * Caution: count may return 0 for a variable that isn't set,
3244
   * but it may also return 0 for a variable that has been initialized with an
3245
   * empty array. Use isset to test if a variable is set.
3246
   *
3247
   * @return int
3248
   */
3249
  public function sizeRecursive()
3250 1
  {
3251
    return \count($this->array, COUNT_RECURSIVE);
3252 1
  }
3253
3254 1
  /**
3255 1
   * Counts all elements in an array, or something in an object.
3256
   * <p>For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3257
   * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3258 1
   * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3259
   * implemented and used in PHP.
3260 1
   *
3261
   * @link http://php.net/manual/en/function.count.php
3262
   *
3263
   * @param int $mode [optional] If the optional mode parameter is set to
3264
   *                  COUNT_RECURSIVE (or 1), count
3265
   *                  will recursively count the array. This is particularly useful for
3266
   *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
3267
   *
3268
   * @return int the number of elements in var, which is
3269
   * typically an array, since anything else will have one
3270
   * element.
3271 1
   * </p>
3272
   * <p>
3273 1
   * If var is not an array or an object with
3274
   * implemented Countable interface,
3275 1
   * 1 will be returned.
3276
   * There is one exception, if var is &null;,
3277 1
   * 0 will be returned.
3278
   * </p>
3279
   * <p>
3280
   * Caution: count may return 0 for a variable that isn't set,
3281
   * but it may also return 0 for a variable that has been initialized with an
3282
   * empty array. Use isset to test if a variable is set.
3283
   *
3284
   * @return int
3285 186
   */
3286
  public function size($mode = COUNT_NORMAL)
3287 186
  {
3288
    return \count($this->array, $mode);
3289
  }
3290
3291
  /**
3292
   * Extract a slice of the array.
3293
   *
3294
   * @param int      $offset       <p>Slice begin index.</p>
3295
   * @param int|null $length       <p>Length of the slice.</p>
3296
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3297
   *
3298 6
   * @return static <p>A slice of the original array with length $length.</p>
3299
   */
3300 6
  public function slice($offset, $length = null, $preserveKeys = false)
3301
  {
3302
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
3303
3304
    return static::create($result);
3305
  }
3306
3307
  /**
3308
   * Sort the current array and optional you can keep the keys.
3309
   *
3310 19
   * @param integer $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3311
   * @param integer $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3312 19
   *                           <strong>SORT_NATURAL</strong></p>
3313
   * @param bool    $keepKeys
3314
   *
3315
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3316
   */
3317
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
3318
  {
3319
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
3320 9
3321
    return $this;
3322
  }
3323
3324 9
  /**
3325 9
   * Sort the current array by key.
3326
   *
3327 8
   * @link http://php.net/manual/en/function.ksort.php
3328 8
   * @link http://php.net/manual/en/function.krsort.php
3329 8
   *
3330
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3331 8
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3332 9
   *                              <strong>SORT_NATURAL</strong></p>
3333 9
   *
3334 9
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3335
   */
3336 9
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
3337
  {
3338
    $this->sorterKeys($this->array, $direction, $strategy);
3339 9
3340
    return $this;
3341
  }
3342 9
3343
  /**
3344
   * Sort the current array by value.
3345
   *
3346
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3347
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
3348
   *
3349
   * @return static <p>(Mutable)</p>
3350 9
   */
3351
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
3352
  {
3353
    return $this->sort($direction, $strategy, true);
3354
  }
3355 9
3356
  /**
3357 9
   * Sort the current array by value.
3358 9
   *
3359 9
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3360 8
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
3361 8
   *
3362 8
   * @return static <p>(Mutable)</p>
3363
   */
3364 8
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
3365 9
  {
3366 9
    return $this->sort($direction, $strategy, false);
3367 9
  }
3368
3369 9
  /**
3370
   * Sort a array by value, by a closure or by a property.
3371
   *
3372 9
   * - If the sorter is null, the array is sorted naturally.
3373
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3374
   *
3375 9
   * @param null       $sorter
3376
   * @param string|int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3377
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3378
   *                              <strong>SORT_NATURAL</strong></p>
3379
   *
3380
   * @return static <p>(Immutable)</p>
3381
   */
3382
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
3383
  {
3384
    $array = (array)$this->array;
3385 9
    $direction = $this->getDirection($direction);
3386
3387 9
    // Transform all values into their results.
3388
    if ($sorter) {
3389
      $arrayy = static::create($array);
3390
3391
      $that = $this;
3392
      $results = $arrayy->each(
3393
          function ($value) use ($sorter, $that) {
3394
            return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3395 4
          }
3396
      );
3397 4
3398 4
      $results = $results->getArray();
3399 4
    } else {
3400 4
      $results = $array;
3401
    }
3402 4
3403
    // Sort by the results and replace by original values
3404
    \array_multisort($results, $direction, $strategy, $array);
3405
3406
    return static::create($array);
3407
  }
3408
3409
  /**
3410 2
   * sorting keys
3411
   *
3412 2
   * @param array $elements
3413
   * @param int   $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3414
   * @param int   $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
3415
   *
3416
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3417
   */
3418
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
3419
  {
3420
    $direction = $this->getDirection($direction);
3421
3422
    switch ($direction) {
3423 9
      case 'desc':
3424
      case SORT_DESC:
3425 9
        \krsort($elements, $strategy);
3426 4
        break;
3427 4
      case 'asc':
3428 5
      case SORT_ASC:
3429
      default:
3430
        \ksort($elements, $strategy);
3431 9
    }
3432
3433
    return $this;
3434
  }
3435
3436
  /**
3437
   * @param array      &$elements
3438
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3439
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3440
   *                              <strong>SORT_NATURAL</strong></p>
3441
   * @param bool       $keepKeys
3442
   *
3443
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3444
   */
3445
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
3446
  {
3447
    $direction = $this->getDirection($direction);
3448
3449
    if (!$strategy) {
3450
      $strategy = SORT_REGULAR;
3451
    }
3452
3453
    switch ($direction) {
3454
      case 'desc':
3455
      case SORT_DESC:
3456
        if ($keepKeys) {
3457
          arsort($elements, $strategy);
3458
        } else {
3459
          \rsort($elements, $strategy);
3460
        }
3461
        break;
3462
      case 'asc':
3463
      case SORT_ASC:
3464
      default:
3465
        if ($keepKeys) {
3466
          \asort($elements, $strategy);
3467
        } else {
3468
          \sort($elements, $strategy);
3469
        }
3470
    }
3471
3472
    return $this;
3473
  }
3474
3475
  /**
3476
   * Split an array in the given amount of pieces.
3477
   *
3478
   * @param int  $numberOfPieces
3479
   * @param bool $keepKeys
3480
   *
3481
   * @return static <p>(Immutable)</p>
3482
   */
3483
  public function split($numberOfPieces = 2, $keepKeys = false)
3484
  {
3485
    $arrayCount = $this->count();
3486
3487
    if ($arrayCount === 0) {
3488
      $result = array();
3489
    } else {
3490
      $numberOfPieces = (int)$numberOfPieces;
3491
      $splitSize = (int)\ceil($arrayCount / $numberOfPieces);
3492
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
3493
    }
3494
3495
    return static::create($result);
3496
  }
3497
3498
  /**
3499
   * Stripe all empty items.
3500
   *
3501
   * @return static <p>(Immutable)</p>
3502
   */
3503
  public function stripEmpty()
3504
  {
3505
    return $this->filter(
3506
        function ($item) {
3507
          if ($item === null) {
3508
            return false;
3509
          }
3510
3511
          return (bool)\trim((string)$item);
3512
        }
3513
    );
3514
  }
3515
3516
  /**
3517
   * Swap two values between positions by key.
3518
   *
3519
   * @param string|int $swapA <p>a key in the array</p>
3520
   * @param string|int $swapB <p>a key in the array</p>
3521
   *
3522
   * @return static <p>(Immutable)</p>
3523
   */
3524
  public function swap($swapA, $swapB)
3525
  {
3526
    $array = $this->array;
3527
3528
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
3529
3530
    return static::create($array);
3531
  }
3532
3533
  /**
3534
   * alias: for "Arrayy->getArray()"
3535
   *
3536
   * @see Arrayy::getArray()
3537
   */
3538
  public function toArray()
3539
  {
3540
    return $this->getArray();
3541
  }
3542
3543
  /**
3544
   * Convert the current array to JSON.
3545
   *
3546
   * @param null|int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3547
   * @param int      $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3548
   *
3549
   * @return string
3550
   */
3551
  public function toJson($options = null, $depth = 512)
3552
  {
3553
    return UTF8::json_encode($this->array, $options, $depth);
3554
  }
3555
3556
  /**
3557
   * Implodes array to a string with specified separator.
3558
   *
3559
   * @param string $separator [optional] <p>The element's separator.</p>
3560
   *
3561
   * @return string <p>The string representation of array, separated by ",".</p>
3562
   */
3563
  public function toString($separator = ',')
3564
  {
3565
    return $this->implode($separator);
3566
  }
3567
3568
  /**
3569
   * Return a duplicate free copy of the current array.
3570
   *
3571
   * @return static <p>(Mutable)</p>
3572
   */
3573
  public function unique()
3574
  {
3575
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3576
3577
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce($this->arr...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
3578
        $this->array,
3579
        function ($resultArray, $value) {
3580
          if (!in_array($value, $resultArray, true)) {
3581
            $resultArray[] = $value;
3582
          }
3583
3584
          return $resultArray;
3585
        },
3586
        array()
3587
    );
3588
3589 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3590
      $this->array = array();
3591
    } else {
3592
      $this->array = (array)$this->array;
3593
    }
3594
3595
    return $this;
3596
  }
3597
3598
  /**
3599
   * Return a duplicate free copy of the current array. (with the old keys)
3600
   *
3601
   * @return static <p>(Mutable)</p>
3602
   */
3603
  public function uniqueKeepIndex()
3604
  {
3605
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3606
3607
    // init
3608
    $array = $this->array;
3609
3610
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce(\array_key...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
3611
        \array_keys($array),
3612
        function ($resultArray, $key) use ($array) {
3613
          if (!in_array($array[$key], $resultArray, true)) {
3614
            $resultArray[$key] = $array[$key];
3615
          }
3616
3617
          return $resultArray;
3618
        },
3619
        array()
3620
    );
3621
3622 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3623
      $this->array = array();
3624
    } else {
3625
      $this->array = (array)$this->array;
3626
    }
3627
3628
    return $this;
3629
  }
3630
3631
  /**
3632
   * alias: for "Arrayy->unique()"
3633
   *
3634
   * @see Arrayy::unique()
3635
   *
3636
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3637
   */
3638
  public function uniqueNewIndex()
3639
  {
3640
    return $this->unique();
3641
  }
3642
3643
  /**
3644
   * Prepends one or more values to the beginning of array at once.
3645
   *
3646
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3647
   */
3648 View Code Duplication
  public function unshift(/* variadic arguments allowed */)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3649
  {
3650
    if (\func_num_args()) {
3651
      $args = \array_merge(array(&$this->array), \func_get_args());
3652
      \call_user_func_array('array_unshift', $args);
3653
    }
3654
3655
    return $this;
3656
  }
3657
3658
  /**
3659
   * Get all values from a array.
3660
   *
3661
   * @return static <p>(Immutable)</p>
3662
   */
3663
  public function values()
3664
  {
3665
    return static::create(\array_values((array)$this->array));
3666
  }
3667
3668
  /**
3669
   * Apply the given function to every element in the array, discarding the results.
3670
   *
3671
   * @param callable $callable
3672
   * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
3673
   *
3674
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3675
   */
3676
  public function walk($callable, $recursive = false)
3677
  {
3678
    if (true === $recursive) {
3679
      \array_walk_recursive($this->array, $callable);
3680
    } else {
3681
      \array_walk($this->array, $callable);
3682
    }
3683
3684
    return $this;
3685
  }
3686
}
3687