Completed
Push — master ( 8d4dce...b437a6 )
by Lars
03:41
created

Arrayy::shuffle()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4.2084

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 2
nop 1
dl 0
loc 24
ccs 13
cts 17
cp 0.7647
crap 4.2084
rs 8.6845
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
   * @return int
188
   */
189 93
  public function count()
190
  {
191 93
    return $this->size();
192
  }
193
194
  /**
195
   * Exchange the array for another one.
196
   *
197
   * @param array|Arrayy $data
198
   *
199
   * @return array
200
   */
201 1
  public function exchangeArray($data)
202
  {
203 1
    $this->array = $this->fallbackForArray($data);
204
205 1
    return $this->array;
206
  }
207
208
  /**
209
   * Creates a copy of the ArrayyObject.
210
   *
211
   * @return array
212
   */
213 1
  public function getArrayCopy()
214
  {
215 1
    return $this->array;
216
  }
217
218
  /**
219
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
220
   *
221
   * @return ArrayyIterator <p>An iterator for the values in the array.</p>
222
   */
223 20
  public function getIterator()
224
  {
225 20
    $iterator = $this->getIteratorClass();
226
227 20
    return new $iterator($this->array);
228
  }
229
230
  /**
231
   * Gets the iterator classname for the ArrayObject.
232
   *
233
   * @return string
234
   */
235 20
  public function getIteratorClass()
236
  {
237 20
    return $this->iteratorClass;
238
  }
239
240
  /**
241
   * Sort the entries by key
242
   *
243
   * @param int $sort_flags [optional] <p>
244
   *                        You may modify the behavior of the sort using the optional
245
   *                        parameter sort_flags, for details
246
   *                        see sort.
247
   *                        </p>
248
   *
249
   * @return static <p>(Mutable) Return this Arrayy object.</p>
250
   */
251 4
  public function ksort($sort_flags = null)
252
  {
253 4
    ksort($this->array, $sort_flags);
254
255 4
    return $this;
256
  }
257
258
  /**
259
   * Sort an array using a case insensitive "natural order" algorithm
260
   *
261
   * @return static <p>(Mutable) Return this Arrayy object.</p>
262
   */
263
  public function natcasesort()
264
  {
265
    natcasesort($this->array);
266
267
    return $this;
268
  }
269
270
  /**
271
   * Sort entries using a "natural order" algorithm
272
   *
273
   * @return static <p>(Mutable) Return this Arrayy object.</p>
274
   */
275 1
  public function natsort()
276
  {
277 1
    natsort($this->array);
278
279 1
    return $this;
280
  }
281
282
  /**
283
   * Whether or not an offset exists.
284
   *
285
   * @param int|float|string $offset
286
   *
287
   * @return bool
288
   */
289 40
  public function offsetExists($offset)
290
  {
291 40
    if ($this->isEmpty()) {
292 4
      return false;
293
    }
294
295
    // php cast "bool"-index into "int"-index
296 36
    if ((bool)$offset === $offset) {
297 1
      $offset = (int)$offset;
298 1
    }
299
300 36
    $tmpReturn = \array_key_exists($offset, $this->array);
301
302
    if (
303
        $tmpReturn === true
304 36
        ||
305
        (
306
            $tmpReturn === false
307 12
            &&
308 12
            strpos((string)$offset, $this->pathSeparator) === false
309 12
        )
310 36
    ) {
311 34
      return $tmpReturn;
312
    }
313
314 3
    $offsetExists = false;
315
316 3
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
317
318 3
      $offsetExists = false;
319 3
      $explodedPath = explode($this->pathSeparator, (string)$offset);
320 3
      $lastOffset = \array_pop($explodedPath);
321 3
      $containerPath = implode($this->pathSeparator, $explodedPath);
322
323 3
      $this->callAtPath(
324 3
          $containerPath,
325
          function ($container) use ($lastOffset, &$offsetExists) {
326 3
            $offsetExists = \array_key_exists($lastOffset, $container);
327 3
          }
328 3
      );
329 3
    }
330
331 3
    return $offsetExists;
332
  }
333
334
  /**
335
   * Returns the value at specified offset.
336
   *
337
   * @param mixed $offset
338
   *
339
   * @return mixed <p>Will return null if the offset did not exists.</p>
340
   */
341 26
  public function offsetGet($offset)
342
  {
343 26
    return $this->offsetExists($offset) ? $this->get($offset) : null;
344
  }
345
346
  /**
347
   * Assigns a value to the specified offset.
348
   *
349
   * @param mixed $offset
350
   * @param mixed $value
351
   */
352 17
  public function offsetSet($offset, $value)
353
  {
354 17
    if ($offset === null) {
355 4
      $this->array[] = $value;
356 4
    } else {
357 13
      $this->internalSet($offset, $value);
358
    }
359 17
  }
360
361
  /**
362
   * Unset an offset.
363
   *
364
   * @param mixed $offset
365
   */
366 7
  public function offsetUnset($offset)
367
  {
368 7
    if ($this->isEmpty()) {
369 1
      return;
370
    }
371
372 6
    if (\array_key_exists($offset, $this->array)) {
373 4
      unset($this->array[$offset]);
374
375 4
      return;
376
    }
377
378 3
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
379
380 2
      $path = explode($this->pathSeparator, (string)$offset);
381 2
      $pathToUnset = \array_pop($path);
382
383 2
      $this->callAtPath(
384 2
          implode($this->pathSeparator, $path),
385
          function (&$offset) use ($pathToUnset) {
386 2
            unset($offset[$pathToUnset]);
387 2
          }
388 2
      );
389
390 2
    }
391 3
  }
392
393
  /**
394
   * Serialize the current "Arrayy"-object.
395
   *
396
   * @return string
397
   */
398 1
  public function serialize()
399
  {
400 1
    return parent::serialize();
401
  }
402
403
  /**
404
   * Sets the iterator classname for the current "Arrayy"-object.
405
   *
406
   * @param  string $class
407
   *
408
   * @return void
409
   *
410
   * @throws \InvalidArgumentException
411
   */
412 813
  public function setIteratorClass($class)
413
  {
414 813
    if (class_exists($class)) {
415 813
      $this->iteratorClass = $class;
416
417 813
      return;
418
    }
419
420
    if (strpos($class, '\\') === 0) {
421
      $class = '\\' . $class;
422
      if (class_exists($class)) {
423
        $this->iteratorClass = $class;
424
425
        return;
426
      }
427
    }
428
429
    throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
430
  }
431
432
  /**
433
   * Sort the entries with a user-defined comparison function and maintain key association.
434
   *
435
   * @param callable $function
436
   *
437
   * @return static <p>(Mutable) Return this Arrayy object.</p>
438
   *
439
   * @throws \InvalidArgumentException
440
   */
441 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...
442
  {
443
    if (!is_callable($function)) {
444
      throw new \InvalidArgumentException(
445
          'Passed function must be callable'
446
      );
447
    }
448
449
    uasort($this->array, $function);
450
451
    return $this;
452
  }
453
454
  /**
455
   * Sort the entries by keys using a user-defined comparison function.
456
   *
457
   * @param callable $function
458
   *
459
   * @return static <p>(Mutable) Return this Arrayy object.</p>
460
   *
461
   * @throws \InvalidArgumentException
462
   */
463 5
  public function uksort($function)
464
  {
465 5
    return $this->customSortKeys($function);
466
  }
467
468
  /**
469
   * Unserialize an string and return this object.
470
   *
471
   * @param string $string
472
   *
473
   * @return static <p>(Mutable)</p>
474
   */
475 1
  public function unserialize($string)
476
  {
477 1
    parent::unserialize($string);
478
479 1
    return $this;
480
  }
481
482
  /**
483
   * Add a suffix to each key.
484
   *
485
   * @param string $prefix
486
   *
487
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
488
   */
489 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...
490
  {
491 10
    $result = array();
492 10
    foreach ($this->array as $key => $item) {
493 9
      if ($item instanceof self) {
494
        $result[$prefix . $key] = $item->appendToEachKey($prefix);
495 9
      } elseif (is_array($item)) {
496
        $result[$prefix . $key] = self::create($item)->appendToEachKey($prefix)->toArray();
497
      } else {
498 9
        $result[$prefix . $key] = $item;
499
      }
500 10
    }
501
502 10
    return self::create($result);
503
  }
504
505
  /**
506
   * Add a prefix to each value.
507
   *
508
   * @param mixed $prefix
509
   *
510
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
511
   */
512 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...
513
  {
514 10
    $result = array();
515 10
    foreach ($this->array as $key => $item) {
516 9
      if ($item instanceof self) {
517
        $result[$key] = $item->appendToEachValue($prefix);
518 9
      } elseif (is_array($item)) {
519
        $result[$key] = self::create($item)->appendToEachValue($prefix)->toArray();
520 9
      } elseif (is_object($item)) {
521 1
        $result[$key] = $item;
522 1
      } else {
523 8
        $result[$key] = $prefix . $item;
524
      }
525 10
    }
526
527 10
    return self::create($result);
528
  }
529
530
  /**
531
   * Convert an array into a object.
532
   *
533
   * @param array $array PHP array
534
   *
535
   * @return \stdClass (object)
536
   */
537 4
  protected static function arrayToObject(array $array = array())
538
  {
539 4
    $object = new \stdClass();
540
541 4
    if (!is_array($array) || count($array) < 1) {
542 1
      return $object;
543
    }
544
545 3
    foreach ($array as $name => $value) {
546 3
      if (is_array($value)) {
547 1
        $object->$name = self::arrayToObject($value);
548 1
        continue;
549
      }
550 3
      $object->{$name} = $value;
551 3
    }
552
553 3
    return $object;
554
  }
555
556
  /**
557
   * Sort an array in reverse order and maintain index association.
558
   *
559
   * @return static <p>(Mutable) Return this Arrayy object.</p>
560
   */
561 4
  public function arsort()
562
  {
563 4
    arsort($this->array);
564
565 4
    return $this;
566
  }
567
568
  /**
569
   * Iterate over the current array and execute a callback for each loop.
570
   *
571
   * @param \Closure $closure
572
   *
573
   * @return static <p>(Immutable)</p>
574
   */
575 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...
576
  {
577 2
    $array = $this->array;
578
579 2
    foreach ($array as $key => $value) {
580 2
      $closure($value, $key);
581 2
    }
582
583 2
    return static::create($array);
584
  }
585
586
  /**
587
   * Returns the average value of the current array.
588
   *
589
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
590
   *
591
   * @return int|double <p>The average value.</p>
592
   */
593 10
  public function average($decimals = 0)
594
  {
595 10
    $count = $this->count();
596
597 10
    if (!$count) {
598 2
      return 0;
599
    }
600
601 8
    if (!is_int($decimals)) {
602 3
      $decimals = 0;
603 3
    }
604
605 8
    return round(\array_sum($this->array) / $count, $decimals);
606
  }
607
608
  /**
609
   * @param mixed      $path
610
   * @param callable   $callable
611
   * @param null|array $currentOffset
612
   */
613 4
  protected function callAtPath($path, $callable, &$currentOffset = null)
614
  {
615 4
    if ($currentOffset === null) {
616 4
      $currentOffset = &$this->array;
617 4
    }
618
619 4
    $explodedPath = explode($this->pathSeparator, $path);
620 4
    $nextPath = \array_shift($explodedPath);
621
622 4
    if (!isset($currentOffset[$nextPath])) {
623
      return;
624
    }
625
626 4
    if (!empty($explodedPath)) {
627 1
      $this->callAtPath(
628 1
          implode($this->pathSeparator, $explodedPath),
629 1
          $callable,
630 1
          $currentOffset[$nextPath]
631 1
      );
632 1
    } else {
633 4
      $callable($currentOffset[$nextPath]);
634
    }
635 4
  }
636
637
  /**
638
   * Changes all keys in an array.
639
   *
640
   * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
641
   *                  or <strong>CASE_LOWER</strong> (default)</p>
642
   *
643
   * @return static <p>(Immutable)</p>
644
   */
645 1
  public function changeKeyCase($case = CASE_LOWER)
646
  {
647 1
    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...
648
  }
649
650
  /**
651
   * Change the path separator of the array wrapper.
652
   *
653
   * By default, the separator is: "."
654
   *
655
   * @param string $separator <p>Separator to set.</p>
656
   *
657
   * @return static <p>Mutable</p>
658
   */
659 1
  public function changeSeparator($separator)
660
  {
661 1
    $this->pathSeparator = $separator;
662
663 1
    return $this;
664
  }
665
666
  /**
667
   * Create a chunked version of the current array.
668
   *
669
   * @param int  $size         <p>Size of each chunk.</p>
670
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
671
   *
672
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
673
   */
674 4
  public function chunk($size, $preserveKeys = false)
675
  {
676 4
    $result = \array_chunk($this->array, $size, $preserveKeys);
677
678 4
    return static::create($result);
679
  }
680
681
  /**
682
   * Clean all falsy values from the current array.
683
   *
684
   * @return static <p>(Immutable)</p>
685
   */
686 8
  public function clean()
687
  {
688 8
    return $this->filter(
689
        function ($value) {
690 7
          return (bool)$value;
691
        }
692 8
    );
693
  }
694
695
  /**
696
   * WARNING!!! -> Clear the current array.
697
   *
698
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
699
   */
700 4
  public function clear()
701
  {
702 4
    $this->array = array();
703
704 4
    return $this;
705
  }
706
707
  /**
708
   * Check if an item is in the current array.
709
   *
710
   * @param string|int|float $value
711
   *
712
   * @return bool
713
   */
714 13
  public function contains($value)
715
  {
716 13
    return in_array($value, $this->array, true);
717
  }
718
719
  /**
720
   * Check if an (case-insensitive) string is in the current array.
721
   *
722
   * @param string $value
723
   *
724
   * @return bool
725
   */
726 13
  public function containsCaseInsensitive($value)
727
  {
728 13
    return in_array(
729 13
        UTF8::strtolower($value),
730 13
        \array_map(
731
            array(
732 13
                new UTF8(),
733 13
                'strtolower',
734 13
            ),
735 13
            $this->array
736 13
        ),
737
        true
738 13
    );
739
  }
740
741
  /**
742
   * Check if the given key/index exists in the array.
743
   *
744
   * @param string|int|float $key <p>key/index to search for</p>
745
   *
746
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
747
   */
748 4
  public function containsKey($key)
749
  {
750 4
    return $this->offsetExists($key);
751
  }
752
753
  /**
754
   * Check if all given needles are present in the array as key/index.
755
   *
756
   * @param array $needles
757
   *
758
   * @return bool <p>Returns true if the given keys/indexes exists in the array, false otherwise.</p>
759
   */
760 1
  public function containsKeys(array $needles)
761
  {
762 1
    return count(\array_intersect($needles, $this->keys()->getArray())) === count($needles);
763
  }
764
765
  /**
766
   * alias: for "Arrayy->contains()"
767
   *
768
   * @see Arrayy::contains()
769
   *
770
   * @param string|int|float $value
771
   *
772
   * @return bool
773
   */
774 9
  public function containsValue($value)
775
  {
776 9
    return $this->contains($value);
777
  }
778
779
  /**
780
   * Check if all given needles are present in the array.
781
   *
782
   * @param array $needles
783
   *
784
   * @return bool <p>Returns true if the given values exists in the array, false otherwise.</p>
785
   */
786 1
  public function containsValues(array $needles)
787
  {
788 1
    return count(\array_intersect($needles, $this->array)) === count($needles);
789
  }
790
791
  /**
792
   * Counts all the values of an array
793
   *
794
   * @link http://php.net/manual/en/function.array-count-values.php
795
   *
796
   * @return static <p>
797
   *                (Immutable)
798
   *                An associative Arrayy-object of values from input as
799
   *                keys and their count as value.
800
   *                </p>
801
   */
802 1
  public function countValues()
803
  {
804 1
    return new static(\array_count_values($this->array));
805
  }
806
807
  /**
808
   * Creates an Arrayy object.
809
   *
810
   * @param array $array
811
   *
812
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
813
   */
814 522
  public static function create($array = array())
815
  {
816 522
    return new static($array);
817
  }
818
819
  /**
820
   * WARNING: Creates an Arrayy object by reference.
821
   *
822
   * @param array $array
823
   *
824
   * @return static <p>(Mutable) Return this Arrayy object.</p>
825
   */
826 1
  public function createByReference(&$array = array())
827
  {
828 1
    $array = $this->fallbackForArray($array);
829
830 1
    $this->array = &$array;
831
832 1
    return $this;
833
  }
834
835
  /**
836
   * Create an new Arrayy object via JSON.
837
   *
838
   * @param string $json
839
   *
840
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
841
   */
842 5
  public static function createFromJson($json)
843
  {
844 5
    $array = UTF8::json_decode($json, true);
845
846 5
    return static::create($array);
847
  }
848
849
  /**
850
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
851
   *
852
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
853
   *
854
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
855
   */
856 4
  public static function createFromObject(\ArrayAccess $object)
857
  {
858 4
    $array = new static();
859 4
    foreach ($object as $key => $value) {
860
      /** @noinspection OffsetOperationsInspection */
861 3
      $array[$key] = $value;
862 4
    }
863
864 4
    return $array;
865
  }
866
867
  /**
868
   * Create an new instance filled with values from an object.
869
   *
870
   * @param object $object
871
   *
872
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
873
   */
874 5
  public static function createFromObjectVars($object)
875
  {
876 5
    return new static(self::objectToArray($object));
877
  }
878
879
  /**
880
   * Create an new Arrayy object via string.
881
   *
882
   * @param string      $str       <p>The input string.</p>
883
   * @param string|null $delimiter <p>The boundary string.</p>
884
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
885
   *                               used.</p>
886
   *
887
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
888
   */
889 8
  public static function createFromString($str, $delimiter, $regEx = null)
890
  {
891 8
    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...
892 1
      preg_match_all($regEx, $str, $array);
893
894 1
      if (!empty($array)) {
895 1
        $array = $array[0];
896 1
      }
897
898 1
    } else {
899 7
      $array = explode($delimiter, $str);
900
    }
901
902
    // trim all string in the array
903 8
    \array_walk(
904
        $array,
905
        function (&$val) {
906
          /** @noinspection ReferenceMismatchInspection */
907 8
          if (is_string($val)) {
908 8
            $val = trim($val);
909 8
          }
910 8
        }
911 8
    );
912
913 8
    return static::create($array);
914
  }
915
916
  /**
917
   * Create an new instance containing a range of elements.
918
   *
919
   * @param mixed $low  <p>First value of the sequence.</p>
920
   * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
921
   * @param int   $step <p>Used as the increment between elements in the sequence.</p>
922
   *
923
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
924
   */
925 1
  public static function createWithRange($low, $high, $step = 1)
926
  {
927 1
    return static::create(range($low, $high, $step));
928
  }
929
930
  /**
931
   * Custom sort by index via "uksort".
932
   *
933
   * @link http://php.net/manual/en/function.uksort.php
934
   *
935
   * @param callable $function
936
   *
937
   * @return static <p>(Mutable) Return this Arrayy object.</p>
938
   *
939
   * @throws \InvalidArgumentException
940
   */
941 5 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...
942
  {
943 5
    if (!is_callable($function)) {
944
      throw new \InvalidArgumentException(
945
          'Passed function must be callable'
946
      );
947
    }
948
949 5
    uksort($this->array, $function);
950
951 5
    return $this;
952
  }
953
954
  /**
955
   * Custom sort by value via "usort".
956
   *
957
   * @link http://php.net/manual/en/function.usort.php
958
   *
959
   * @param callable $function
960
   *
961
   * @return static <p>(Mutable) Return this Arrayy object.</p>
962
   *
963
   * @throws \InvalidArgumentException
964
   */
965 5 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...
966
  {
967 5
    if (!is_callable($function)) {
968
      throw new \InvalidArgumentException(
969
          'Passed function must be callable'
970
      );
971
    }
972
973 5
    usort($this->array, $function);
974
975 5
    return $this;
976
  }
977
978
  /**
979
   * Return values that are only in the current array.
980
   *
981
   * @param array $array
982
   *
983
   * @return static <p>(Immutable)</p>
984
   */
985 12
  public function diff(array $array = array())
986
  {
987 12
    $result = \array_diff($this->array, $array);
988
989 12
    return static::create($result);
990
  }
991
992
  /**
993
   * Return values that are only in the current multi-dimensional array.
994
   *
995
   * @param array      $array
996
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
997
   *
998
   * @return static <p>(Immutable)</p>
999
   */
1000 1
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
1001
  {
1002 1
    $result = array();
1003
1004
    if (
1005
        $helperVariableForRecursion !== null
1006 1
        &&
1007 1
        is_array($helperVariableForRecursion)
1008 1
    ) {
1009 1
      $arrayForTheLoop = $helperVariableForRecursion;
1010 1
    } else {
1011 1
      $arrayForTheLoop = $this->array;
1012
    }
1013
1014 1
    foreach ($arrayForTheLoop as $key => $value) {
1015 1
      if (\array_key_exists($key, $array)) {
1016 1
        if (is_array($value)) {
1017 1
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
1018 1
          if (!empty($recursiveDiff)) {
1019 1
            $result[$key] = $recursiveDiff;
1020 1
          }
1021 1
        } else {
1022 1
          if ($value != $array[$key]) {
1023 1
            $result[$key] = $value;
1024 1
          }
1025
        }
1026 1
      } else {
1027 1
        $result[$key] = $value;
1028
      }
1029 1
    }
1030
1031 1
    return static::create($result);
1032
  }
1033
1034
  /**
1035
   * Return values that are only in the new $array.
1036
   *
1037
   * @param array $array
1038
   *
1039
   * @return static <p>(Immutable)</p>
1040
   */
1041 8
  public function diffReverse(array $array = array())
1042
  {
1043 8
    $result = \array_diff($array, $this->array);
1044
1045 8
    return static::create($result);
1046
  }
1047
1048
  /**
1049
   * Divide an array into two arrays. One with keys and the other with values.
1050
   *
1051
   * @return static <p>(Immutable)</p>
1052
   */
1053 1
  public function divide()
1054
  {
1055 1
    return static::create(
1056
        array(
1057 1
            $this->keys(),
1058 1
            $this->values(),
1059
        )
1060 1
    );
1061
  }
1062
1063
  /**
1064
   * Iterate over the current array and modify the array's value.
1065
   *
1066
   * @param \Closure $closure
1067
   *
1068
   * @return static <p>(Immutable)</p>
1069
   */
1070 4 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...
1071
  {
1072 4
    $array = $this->array;
1073
1074 4
    foreach ($array as $key => $value) {
1075 4
      $array[$key] = $closure($value, $key);
1076 4
    }
1077
1078 4
    return static::create($array);
1079
  }
1080
1081
  /**
1082
   * Check if a value is in the current array using a closure.
1083
   *
1084
   * @param \Closure $closure
1085
   *
1086
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
1087
   */
1088 4
  public function exists(\Closure $closure)
1089
  {
1090 4
    $isExists = false;
1091 4
    foreach ($this->array as $key => $value) {
1092 3
      if ($closure($value, $key)) {
1093 1
        $isExists = true;
1094 1
        break;
1095
      }
1096 4
    }
1097
1098 4
    return $isExists;
1099
  }
1100
1101
  /**
1102
   * create a fallback for array
1103
   *
1104
   * 1. use the current array, if it's a array
1105
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
1106
   * 3. fallback to empty array, if there is nothing
1107
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
1108
   * 5. call "__toArray()" on object, if the method exists
1109
   * 6. cast a string or object with "__toString()" into an array
1110
   * 7. throw a "InvalidArgumentException"-Exception
1111
   *
1112
   * @param $array
1113
   *
1114
   * @return array
1115
   *
1116
   * @throws \InvalidArgumentException
1117
   */
1118 815
  protected function fallbackForArray(&$array)
1119
  {
1120 815
    if (is_array($array)) {
1121 812
      return $array;
1122
    }
1123
1124 11
    if ($array instanceof self) {
1125 1
      return $array->getArray();
1126
    }
1127
1128 10
    if (!$array) {
1129 6
      return array();
1130
    }
1131
1132 9
    $isObject = is_object($array);
1133
1134 9
    if ($isObject && $array instanceof \ArrayAccess) {
1135
      /** @noinspection ReferenceMismatchInspection */
1136
      return static::createFromObject($array)->getArray();
1137
    }
1138
1139 9
    if ($isObject && $array instanceof \ArrayObject) {
1140
      return $array->getArrayCopy();
1141
    }
1142
1143 9
    if ($isObject && method_exists($array, '__toArray')) {
1144
      return (array)$array->__toArray();
1145
    }
1146
1147
    /** @noinspection ReferenceMismatchInspection */
1148
    if (
1149 9
        is_string($array)
1150
        ||
1151 2
        ($isObject && method_exists($array, '__toString'))
1152 9
    ) {
1153 7
      return array((string)$array);
1154
    }
1155
1156 2
    throw new \InvalidArgumentException(
1157
        'Passed value should be a array'
1158 2
    );
1159
  }
1160
1161
  /**
1162
   * Find all items in an array that pass the truth test.
1163
   *
1164
   * @param \Closure|null $closure [optional] <p>
1165
   *                               The callback function to use
1166
   *                               </p>
1167
   *                               <p>
1168
   *                               If no callback is supplied, all entries of
1169
   *                               input equal to false (see
1170
   *                               converting to
1171
   *                               boolean) will be removed.
1172
   *                               </p>
1173
   *
1174
   *  * @param int $flag [optional] <p>
1175
   *                               Flag determining what arguments are sent to <i>callback</i>:
1176
   *                               </p><ul>
1177
   *                               <li>
1178
   *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1179
   *                               to <i>callback</i> instead of the value</span>
1180
   *                               </li>
1181
   *                               <li>
1182
   *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1183
   *                               arguments to <i>callback</i> instead of the value</span>
1184
   *                               </li>
1185
   *                               </ul>
1186
   *
1187
   * @return static <p>(Immutable)</p>
1188
   */
1189 9
  public function filter($closure = null, $flag = 0)
1190
  {
1191 9
    if (!$closure) {
1192 1
      return $this->clean();
1193
    }
1194
1195 9
    if ($flag === 0) {
1196
1197
      // working for all php-versions
1198
1199 9
      $array = \array_filter($this->array, $closure);
1200
1201 9
    } elseif ($flag !== 0 && defined('HHVM_VERSION') === false && Bootup::is_php('5.6')) {
1202
1203
      // working only with php >= 5.6 and not via HHVM
1204
1205
      $array = \array_filter($this->array, $closure, $flag);
1206
1207
    } else {
1208
1209
      // fallback for old php-versions
1210
1211 1
      $array = $this->array;
1212
1213 1
      if ($flag === 2 /* ARRAY_FILTER_USE_KEY */) {
1214 1
        foreach ($array as $key => $value) {
1215 1
          if (!call_user_func($closure, $key)) {
1216 1
            unset($array[$key]);
1217 1
          }
1218 1
        }
1219 1
      } elseif ($flag === 1 /* ARRAY_FILTER_USE_BOTH */) {
1220 1
        foreach ($array as $key => $value) {
1221 1
          if (!call_user_func($closure, $key, $value)) {
1222 1
            unset($array[$key]);
1223 1
          }
1224 1
        }
1225 1
      }
1226
    }
1227
1228 9
    return static::create($array);
1229
  }
1230
1231
  /**
1232
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
1233
   * within that.
1234
   *
1235
   * @param string $property
1236
   * @param string $value
1237
   * @param string $comparisonOp
1238
   *                            <p>
1239
   *                            'eq' (equals),<br />
1240
   *                            'gt' (greater),<br />
1241
   *                            'gte' || 'ge' (greater or equals),<br />
1242
   *                            'lt' (less),<br />
1243
   *                            'lte' || 'le' (less or equals),<br />
1244
   *                            'ne' (not equals),<br />
1245
   *                            'contains',<br />
1246
   *                            'notContains',<br />
1247
   *                            'newer' (via strtotime),<br />
1248
   *                            'older' (via strtotime),<br />
1249
   *                            </p>
1250
   *
1251
   * @return static <p>(Immutable)</p>
1252
   */
1253 1
  public function filterBy($property, $value, $comparisonOp = null)
1254
  {
1255 1
    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...
1256 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
1257 1
    }
1258
1259
    $ops = array(
1260
        'eq'          => function ($item, $prop, $value) {
1261 1
          return $item[$prop] === $value;
1262 1
        },
1263
        'gt'          => function ($item, $prop, $value) {
1264
          return $item[$prop] > $value;
1265 1
        },
1266
        'ge'          => function ($item, $prop, $value) {
1267
          return $item[$prop] >= $value;
1268 1
        },
1269
        'gte'         => function ($item, $prop, $value) {
1270
          return $item[$prop] >= $value;
1271 1
        },
1272
        'lt'          => function ($item, $prop, $value) {
1273 1
          return $item[$prop] < $value;
1274 1
        },
1275
        'le'          => function ($item, $prop, $value) {
1276
          return $item[$prop] <= $value;
1277 1
        },
1278
        'lte'         => function ($item, $prop, $value) {
1279
          return $item[$prop] <= $value;
1280 1
        },
1281
        'ne'          => function ($item, $prop, $value) {
1282
          return $item[$prop] !== $value;
1283 1
        },
1284
        'contains'    => function ($item, $prop, $value) {
1285 1
          return in_array($item[$prop], (array)$value, true);
1286 1
        },
1287
        'notContains' => function ($item, $prop, $value) {
1288
          return !in_array($item[$prop], (array)$value, true);
1289 1
        },
1290
        'newer'       => function ($item, $prop, $value) {
1291
          return strtotime($item[$prop]) > strtotime($value);
1292 1
        },
1293
        'older'       => function ($item, $prop, $value) {
1294
          return strtotime($item[$prop]) < strtotime($value);
1295 1
        },
1296 1
    );
1297
1298 1
    $result = \array_values(
1299 1
        \array_filter(
1300 1
            (array)$this->array,
1301
            function ($item) use (
1302 1
                $property,
1303 1
                $value,
1304 1
                $ops,
1305 1
                $comparisonOp
1306
            ) {
1307 1
              $item = (array)$item;
1308 1
              $itemArrayy = new Arrayy($item);
1309 1
              $item[$property] = $itemArrayy->get($property, array());
1310
1311 1
              return $ops[$comparisonOp]($item, $property, $value);
1312
            }
1313 1
        )
1314 1
    );
1315
1316 1
    return static::create($result);
1317
  }
1318
1319
  /**
1320
   * Find the first item in an array that passes the truth test,
1321
   *  otherwise return false
1322
   *
1323
   * @param \Closure $closure
1324
   *
1325
   * @return mixed|false <p>Return false if we did not find the value.</p>
1326
   */
1327 8
  public function find(\Closure $closure)
1328
  {
1329 8
    foreach ($this->array as $key => $value) {
1330 6
      if ($closure($value, $key)) {
1331 5
        return $value;
1332
      }
1333 5
    }
1334
1335 3
    return false;
1336
  }
1337
1338
  /**
1339
   * find by ...
1340
   *
1341
   * @param string $property
1342
   * @param string $value
1343
   * @param string $comparisonOp
1344
   *
1345
   * @return static <p>(Immutable)</p>
1346
   */
1347
  public function findBy($property, $value, $comparisonOp = 'eq')
1348
  {
1349
    return $this->filterBy($property, $value, $comparisonOp);
1350
  }
1351
1352
  /**
1353
   * Get the first value from the current array.
1354
   *
1355
   * @return mixed <p>Return null if there wasn't a element.</p>
1356
   */
1357 13
  public function first()
1358
  {
1359 13
    $tmpArray = $this->array;
1360 13
    $result = \array_shift($tmpArray);
1361
1362 13
    if ($result === null) {
1363 3
      return null;
1364
    }
1365
1366 10
    return $result;
1367
  }
1368
1369
  /**
1370
   * Get the first value(s) from the current array.
1371
   *
1372
   * @param int|null $number <p>How many values you will take?</p>
1373
   *
1374
   * @return static <p>(Immutable)</p>
1375
   */
1376 28
  public function firstsImmutable($number = null)
1377
  {
1378 28
    if ($number === null) {
1379 7
      $arrayTmp = $this->array;
1380 7
      $array = (array)\array_shift($arrayTmp);
1381 7
    } else {
1382 21
      $number = (int)$number;
1383 21
      $arrayTmp = $this->array;
1384 21
      $array = \array_splice($arrayTmp, 0, $number, true);
1385
    }
1386
1387 28
    return static::create($array);
1388
  }
1389
1390
  /**
1391
   * Get the first value(s) from the current array.
1392
   *
1393
   * @param int|null $number <p>How many values you will take?</p>
1394
   *
1395
   * @return static <p>(Mutable)</p>
1396
   */
1397 26
  public function firstsMutable($number = null)
1398
  {
1399 26
    if ($number === null) {
1400 11
      $this->array = (array)\array_shift($this->array);
1401 11
    } else {
1402 15
      $number = (int)$number;
1403 15
      $this->array = \array_splice($this->array, 0, $number, true);
1404
    }
1405
1406 26
    return $this;
1407
  }
1408
1409
  /**
1410
   * Exchanges all keys with their associated values in an array.
1411
   *
1412
   * @return static <p>(Immutable)</p>
1413
   */
1414 1
  public function flip()
1415
  {
1416 1
    $result = \array_flip($this->array);
1417
1418 1
    return static::create($result);
1419
  }
1420
1421
  /**
1422
   * Get a value from an array (optional using dot-notation).
1423
   *
1424
   * @param string $key      <p>The key to look for.</p>
1425
   * @param mixed  $fallback <p>Value to fallback to.</p>
1426
   * @param array  $array    <p>The array to get from, if it's set to "null" we use the current array from the
1427
   *                         class.</p>
1428
   *
1429
   * @return mixed
1430
   */
1431 61
  public function get($key, $fallback = null, $array = null)
1432
  {
1433
    if (
1434
        $array !== null
1435 61
        &&
1436 3
        is_array($array)
1437 61
    ) {
1438 3
      $usedArray = $array;
1439 3
    } else {
1440 59
      $usedArray = $this->array;
1441
    }
1442
1443 61
    if ($key === null) {
1444 1
      return static::create($usedArray);
1445
    }
1446
1447
    // php cast "bool"-index into "int"-index
1448 61
    if ((bool)$key === $key) {
1449 2
      $key = (int)$key;
1450 2
    }
1451
1452 61
    if (\array_key_exists($key, $usedArray) === true) {
1453 51
      if (is_array($usedArray[$key])) {
1454 7
        return static::create($usedArray[$key]);
1455
      }
1456
1457 46
      return $usedArray[$key];
1458
    }
1459
1460
    // Crawl through array, get key according to object or not
1461 20
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1462 20
      if (!isset($usedArray[$segment])) {
1463 19
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1464
      }
1465
1466 5
      $usedArray = $usedArray[$segment];
1467 5
    }
1468
1469 5
    if (is_array($usedArray)) {
1470
      return static::create($usedArray);
1471
    }
1472
1473 5
    return $usedArray;
1474
  }
1475
1476
  /**
1477
   * Get the current array from the "Arrayy"-object.
1478
   *
1479
   * @return array
1480
   */
1481 536
  public function getArray()
1482
  {
1483 536
    \array_map(array('self', 'internalGetArray'), $this->array);
1484
1485 536
    return $this->array;
1486
  }
1487
1488
  /**
1489
   * Returns the values from a single column of the input array, identified by
1490
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1491
   *
1492
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1493
   * array by the values from the $indexKey column in the input array.
1494
   *
1495
   * @param mixed $columnKey
1496
   * @param mixed $indexKey
1497
   *
1498
   * @return static <p>(Immutable)</p>
1499
   */
1500 1
  public function getColumn($columnKey = null, $indexKey = null)
1501
  {
1502 1
    $result = \array_column($this->array, $columnKey, $indexKey);
1503
1504 1
    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 1502 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...
1505
  }
1506
1507
  /**
1508
   * Get correct PHP constant for direction.
1509
   *
1510
   * @param int|string $direction
1511
   *
1512
   * @return int
1513
   */
1514 38
  protected function getDirection($direction)
1515
  {
1516 38
    if (is_string($direction)) {
1517 10
      $direction = strtolower($direction);
1518
1519 10
      if ($direction === 'desc') {
1520 2
        $direction = SORT_DESC;
1521 2
      } else {
1522 8
        $direction = SORT_ASC;
1523
      }
1524 10
    }
1525
1526
    if (
1527
        $direction !== SORT_DESC
1528 38
        &&
1529
        $direction !== SORT_ASC
1530 38
    ) {
1531
      $direction = SORT_ASC;
1532
    }
1533
1534 38
    return $direction;
1535
  }
1536
1537
  /**
1538
   * alias: for "Arrayy->keys()"
1539
   *
1540
   * @see Arrayy::keys()
1541
   *
1542
   * @return static <p>(Immutable)</p>
1543
   */
1544 1
  public function getKeys()
1545
  {
1546 1
    return $this->keys();
1547
  }
1548
1549
  /**
1550
   * Get the current array from the "Arrayy"-object as object.
1551
   *
1552
   * @return \stdClass (object)
1553
   */
1554 4
  public function getObject()
1555
  {
1556 4
    return self::arrayToObject($this->getArray());
1557
  }
1558
1559
  /**
1560
   * alias: for "Arrayy->randomImmutable()"
1561
   *
1562
   * @see Arrayy::randomImmutable()
1563
   *
1564
   * @return static <p>(Immutable)</p>
1565
   */
1566 3
  public function getRandom()
1567
  {
1568 3
    return $this->randomImmutable();
1569
  }
1570
1571
  /**
1572
   * alias: for "Arrayy->randomKey()"
1573
   *
1574
   * @see Arrayy::randomKey()
1575
   *
1576
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1577
   */
1578 3
  public function getRandomKey()
1579
  {
1580 3
    return $this->randomKey();
1581
  }
1582
1583
  /**
1584
   * alias: for "Arrayy->randomKeys()"
1585
   *
1586
   * @see Arrayy::randomKeys()
1587
   *
1588
   * @param int $number
1589
   *
1590
   * @return static <p>(Immutable)</p>
1591
   */
1592 9
  public function getRandomKeys($number)
1593
  {
1594 9
    return $this->randomKeys($number);
1595
  }
1596
1597
  /**
1598
   * alias: for "Arrayy->randomValue()"
1599
   *
1600
   * @see Arrayy::randomValue()
1601
   *
1602
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1603
   */
1604 3
  public function getRandomValue()
1605
  {
1606 3
    return $this->randomValue();
1607
  }
1608
1609
  /**
1610
   * alias: for "Arrayy->randomValues()"
1611
   *
1612
   * @see Arrayy::randomValues()
1613
   *
1614
   * @param int $number
1615
   *
1616
   * @return static <p>(Immutable)</p>
1617
   */
1618 6
  public function getRandomValues($number)
1619
  {
1620 6
    return $this->randomValues($number);
1621
  }
1622
1623
  /**
1624
   * Group values from a array according to the results of a closure.
1625
   *
1626
   * @param string $grouper <p>A callable function name.</p>
1627
   * @param bool   $saveKeys
1628
   *
1629
   * @return static <p>(Immutable)</p>
1630
   */
1631 3
  public function group($grouper, $saveKeys = false)
1632
  {
1633 3
    $array = (array)$this->array;
1634 3
    $result = array();
1635
1636
    // Iterate over values, group by property/results from closure
1637 3
    foreach ($array as $key => $value) {
1638
1639 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1640 3
      $newValue = $this->get($groupKey, null, $result);
1641
1642 3
      if ($groupKey instanceof self) {
1643
        $groupKey = $groupKey->getArray();
1644
      }
1645
1646 3
      if ($newValue instanceof self) {
1647 3
        $newValue = $newValue->getArray();
1648 3
      }
1649
1650
      // Add to results
1651 3
      if ($groupKey !== null) {
1652 2
        if ($saveKeys) {
1653 1
          $result[$groupKey] = $newValue;
1654 1
          $result[$groupKey][$key] = $value;
1655 1
        } else {
1656 1
          $result[$groupKey] = $newValue;
1657 1
          $result[$groupKey][] = $value;
1658
        }
1659 2
      }
1660
1661 3
    }
1662
1663 3
    return static::create($result);
1664
  }
1665
1666
  /**
1667
   * Check if an array has a given key.
1668
   *
1669
   * @param mixed $key
1670
   *
1671
   * @return bool
1672
   */
1673 22
  public function has($key)
1674
  {
1675
    // Generate unique string to use as marker.
1676 22
    $unFound = (string)uniqid('arrayy', true);
1677
1678 22
    return $this->get($key, $unFound) !== $unFound;
1679
  }
1680
1681
  /**
1682
   * Implodes an array.
1683
   *
1684
   * @param string $glue
1685
   *
1686
   * @return string
1687
   */
1688 28
  public function implode($glue = '')
1689
  {
1690 28
    return self::implode_recursive($glue, $this->array);
1691
  }
1692
1693
  /**
1694
   * @param string       $glue
1695
   * @param string|array $pieces
1696
   *
1697
   * @return string
1698
   */
1699 28
  protected static function implode_recursive($glue = '', $pieces)
1700
  {
1701 28
    if (is_array($pieces)) {
1702 28
      $pieces_count = count($pieces);
1703
1704 28
      return implode(
1705 28
          $glue,
1706 28
          array_map(
1707 28
              array('self', 'implode_recursive'),
1708 28
              array_fill(0, ($pieces_count > 0 ? $pieces_count : 1), $glue),
1709
              $pieces
1710 28
          )
1711 28
      );
1712
    }
1713
1714 28
    return $pieces;
1715
  }
1716
1717
  /**
1718
   * Given a list and an iterate-function that returns
1719
   * a key for each element in the list (or a property name),
1720
   * returns an object with an index of each item.
1721
   *
1722
   * Just like groupBy, but for when you know your keys are unique.
1723
   *
1724
   * @param mixed $key
1725
   *
1726
   * @return static <p>(Immutable)</p>
1727
   */
1728 3
  public function indexBy($key)
1729
  {
1730 3
    $results = array();
1731
1732 3
    foreach ($this->array as $a) {
1733 3
      if (\array_key_exists($key, $a) === true) {
1734 2
        $results[$a[$key]] = $a;
1735 2
      }
1736 3
    }
1737
1738 3
    return static::create($results);
1739
  }
1740
1741
  /**
1742
   * alias: for "Arrayy->searchIndex()"
1743
   *
1744
   * @see Arrayy::searchIndex()
1745
   *
1746
   * @param mixed $value <p>The value to search for.</p>
1747
   *
1748
   * @return mixed
1749
   */
1750 4
  public function indexOf($value)
1751
  {
1752 4
    return $this->searchIndex($value);
1753
  }
1754
1755
  /**
1756
   * Get everything but the last..$to items.
1757
   *
1758
   * @param int $to
1759
   *
1760
   * @return static <p>(Immutable)</p>
1761
   */
1762 12
  public function initial($to = 1)
1763
  {
1764 12
    $slice = count($this->array) - $to;
1765
1766 12
    return $this->firstsImmutable($slice);
1767
  }
1768
1769
  /**
1770
   * @param mixed $value
1771
   */
1772 446
  protected function internalGetArray(&$value)
1773
  {
1774 446
    if ($value instanceof self) {
1775
1776
      $valueTmp = $value->getArray();
1777
      if (count($valueTmp) === 0) {
1778
        $value = array();
1779
      } else {
1780
        /** @noinspection PhpUnusedLocalVariableInspection */
1781
        $value = &$valueTmp;
1782
      }
1783
1784 446
    } 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...
1785
      /** @noinspection PhpUnusedLocalVariableInspection */
1786
      $value = &$value->jsonSerialize();
1787
    }
1788 446
  }
1789
1790
  /**
1791
   * Internal mechanics of remove method.
1792
   *
1793
   * @param string $key
1794
   *
1795
   * @return boolean
1796
   */
1797 18
  protected function internalRemove($key)
1798
  {
1799 18
    $path = explode($this->pathSeparator, (string)$key);
1800
1801
    // Crawl though the keys
1802 18
    while (count($path) > 1) {
1803
      $key = \array_shift($path);
1804
1805
      if (!$this->has($key)) {
1806
        return false;
1807
      }
1808
1809
      $this->array = &$this->array[$key];
1810
    }
1811
1812 18
    $key = \array_shift($path);
1813
1814 18
    unset($this->array[$key]);
1815
1816 18
    return true;
1817
  }
1818
1819
  /**
1820
   * Internal mechanic of set method.
1821
   *
1822
   * @param string $key
1823
   * @param mixed  $value
1824
   *
1825
   * @return bool
1826
   */
1827 30
  protected function internalSet($key, $value)
1828
  {
1829 30
    if ($key === null) {
1830
      return false;
1831
    }
1832
1833
    // init
1834 30
    $array =& $this->array;
1835 30
    $path = explode($this->pathSeparator, (string)$key);
1836
1837
    // Crawl through the keys
1838 30
    while (count($path) > 1) {
1839 3
      $key = \array_shift($path);
1840
1841
      // If the key doesn't exist at this depth, we will just create an empty array
1842
      // to hold the next value, allowing us to create the arrays to hold final
1843
      // values at the correct depth. Then we'll keep digging into the array.
1844 3
      if (!isset($array[$key]) || !is_array($array[$key])) {
1845
        $array[$key] = static::create(array());
1846
      }
1847
1848 3
      $array =& $array[$key];
1849 3
    }
1850
1851 30
    $array[\array_shift($path)] = $value;
1852
1853 30
    return true;
1854
  }
1855
1856
  /**
1857
   * Return an array with all elements found in input array.
1858
   *
1859
   * @param array $search
1860
   *
1861
   * @return static <p>(Immutable)</p>
1862
   */
1863 2
  public function intersection(array $search)
1864
  {
1865 2
    return static::create(\array_values(\array_intersect($this->array, $search)));
1866
  }
1867
1868
  /**
1869
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1870
   *
1871
   * @param array $search
1872
   *
1873
   * @return bool
1874
   */
1875 1
  public function intersects(array $search)
1876
  {
1877 1
    return count($this->intersection($search)->array) > 0;
1878
  }
1879
1880
  /**
1881
   * Invoke a function on all of an array's values.
1882
   *
1883
   * @param mixed $callable
1884
   * @param mixed $arguments
1885
   *
1886
   * @return static <p>(Immutable)</p>
1887
   */
1888 1
  public function invoke($callable, $arguments = array())
1889
  {
1890
    // If one argument given for each iteration, create an array for it.
1891 1
    if (!is_array($arguments)) {
1892 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1893 1
    }
1894
1895
    // If the callable has arguments, pass them.
1896 1
    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...
1897 1
      $array = \array_map($callable, $this->array, $arguments);
1898 1
    } else {
1899 1
      $array = \array_map($callable, $this->array);
1900
    }
1901
1902 1
    return static::create($array);
1903
  }
1904
1905
  /**
1906
   * Check whether array is associative or not.
1907
   *
1908
   * @return bool <p>Returns true if associative, false otherwise.</p>
1909
   */
1910 15
  public function isAssoc()
1911
  {
1912 15
    if ($this->isEmpty()) {
1913 3
      return false;
1914
    }
1915
1916 13
    foreach ($this->keys()->getArray() as $key) {
1917 13
      if (!is_string($key)) {
1918 11
        return false;
1919
      }
1920 3
    }
1921
1922 3
    return true;
1923
  }
1924
1925
  /**
1926
   * Check whether the array is empty or not.
1927
   *
1928
   * @return bool <p>Returns true if empty, false otherwise.</p>
1929
   */
1930 88
  public function isEmpty()
1931
  {
1932 88
    return !$this->array;
1933
  }
1934
1935
  /**
1936
   * Check if the current array is equal to the given "$array" or not.
1937
   *
1938
   * @param array $array
1939
   *
1940
   * @return bool
1941
   */
1942
  public function isEqual(array $array)
1943
  {
1944
    return ($this->array === $array);
1945
  }
1946
1947
  /**
1948
   * Check if the current array is a multi-array.
1949
   *
1950
   * @return bool
1951
   */
1952 14
  public function isMultiArray()
1953
  {
1954 14
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1955
  }
1956
1957
  /**
1958
   * Check whether array is numeric or not.
1959
   *
1960
   * @return bool <p>Returns true if numeric, false otherwise.</p>
1961
   */
1962 5
  public function isNumeric()
1963
  {
1964 5
    if ($this->isEmpty()) {
1965 2
      return false;
1966
    }
1967
1968 4
    foreach ($this->keys() as $key) {
1969 4
      if (!is_int($key)) {
1970 2
        return false;
1971
      }
1972 3
    }
1973
1974 2
    return true;
1975
  }
1976
1977
  /**
1978
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1979
   *
1980
   * @return bool
1981
   */
1982 1
  public function isSequential()
1983
  {
1984 1
    return \array_keys($this->array) === range(0, count($this->array) - 1);
1985
  }
1986
1987
  /**
1988
   * @return array
1989
   */
1990
  public function jsonSerialize()
1991
  {
1992
    return $this->getArray();
1993
  }
1994
1995
  /**
1996
   * Get all keys from the current array.
1997
   *
1998
   * @return static <p>(Immutable)</p>
1999
   */
2000 25
  public function keys()
2001
  {
2002 25
    return static::create(\array_keys($this->array));
2003
  }
2004
2005
  /**
2006
   * Sort an array by key in reverse order.
2007
   *
2008
   * @param int $sort_flags [optional] <p>
2009
   *                        You may modify the behavior of the sort using the optional
2010
   *                        parameter sort_flags, for details
2011
   *                        see sort.
2012
   *                        </p>
2013
   *
2014
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2015
   */
2016 4
  public function krsort($sort_flags = null)
2017
  {
2018 4
    krsort($this->array, $sort_flags);
2019
2020 4
    return $this;
2021
  }
2022
2023
  /**
2024
   * Get the last value from the current array.
2025
   *
2026
   * @return mixed <p>Return null if there wasn't a element.</p>
2027
   */
2028 4
  public function last()
2029
  {
2030 4
    return $this->pop();
2031
  }
2032
2033
  /**
2034
   * Get the last value(s) from the current array.
2035
   *
2036
   * @param int|null $number
2037
   *
2038
   * @return static <p>(Immutable)</p>
2039
   */
2040 13
  public function lastsImmutable($number = null)
2041
  {
2042 13
    if ($this->isEmpty()) {
2043 1
      return static::create();
2044
    }
2045
2046 12
    if ($number === null) {
2047 8
      $poppedValue = $this->pop();
2048
2049 8
      if ($poppedValue === null) {
2050 1
        $poppedValue = array($poppedValue);
2051 1
      } else {
2052 7
        $poppedValue = (array)$poppedValue;
2053
      }
2054
2055 8
      $arrayy = static::create($poppedValue);
2056 8
    } else {
2057 4
      $number = (int)$number;
2058 4
      $arrayy = $this->rest(-$number);
2059
    }
2060
2061 12
    return $arrayy;
2062
  }
2063
2064
  /**
2065
   * Get the last value(s) from the current array.
2066
   *
2067
   * @param int|null $number
2068
   *
2069
   * @return static <p>(Mutable)</p>
2070
   */
2071 13
  public function lastsMutable($number = null)
2072
  {
2073 13
    if ($this->isEmpty()) {
2074 1
      return $this;
2075
    }
2076
2077 12
    if ($number === null) {
2078 8
      $poppedValue = $this->pop();
2079
2080 8
      if ($poppedValue === null) {
2081 1
        $poppedValue = array($poppedValue);
2082 1
      } else {
2083 7
        $poppedValue = (array)$poppedValue;
2084
      }
2085
2086 8
      $this->array = static::create($poppedValue)->array;
2087 8
    } else {
2088 4
      $number = (int)$number;
2089 4
      $this->array = $this->rest(-$number)->array;
2090
    }
2091
2092 12
    return $this;
2093
  }
2094
2095
  /**
2096
   * Count the values from the current array.
2097
   *
2098
   * alias: for "Arrayy->size()"
2099
   *
2100
   * @see Arrayy::size()
2101
   *
2102
   * @return int
2103
   */
2104 10
  public function length()
2105
  {
2106 10
    return $this->size();
2107
  }
2108
2109
  /**
2110
   * Apply the given function to the every element of the array,
2111
   * collecting the results.
2112
   *
2113
   * @param callable $callable
2114
   *
2115
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
2116
   */
2117 4
  public function map($callable)
2118
  {
2119 4
    $result = \array_map($callable, $this->array);
2120
2121 4
    return static::create($result);
2122
  }
2123
2124
  /**
2125
   * Check if all items in current array match a truth test.
2126
   *
2127
   * @param \Closure $closure
2128
   *
2129
   * @return bool
2130
   */
2131 15 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...
2132
  {
2133 15
    if (count($this->array) === 0) {
2134 2
      return false;
2135
    }
2136
2137
    // init
2138 13
    $array = $this->array;
2139
2140 13
    foreach ($array as $key => $value) {
2141 13
      $value = $closure($value, $key);
2142
2143 13
      if ($value === false) {
2144 7
        return false;
2145
      }
2146 9
    }
2147
2148 7
    return true;
2149
  }
2150
2151
  /**
2152
   * Check if any item in the current array matches a truth test.
2153
   *
2154
   * @param \Closure $closure
2155
   *
2156
   * @return bool
2157
   */
2158 14 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...
2159
  {
2160 14
    if (count($this->array) === 0) {
2161 2
      return false;
2162
    }
2163
2164
    // init
2165 12
    $array = $this->array;
2166
2167 12
    foreach ($array as $key => $value) {
2168 12
      $value = $closure($value, $key);
2169
2170 12
      if ($value === true) {
2171 9
        return true;
2172
      }
2173 5
    }
2174
2175 4
    return false;
2176
  }
2177
2178
  /**
2179
   * Get the max value from an array.
2180
   *
2181
   * @return mixed
2182
   */
2183 10
  public function max()
2184
  {
2185 10
    if ($this->count() === 0) {
2186 1
      return false;
2187
    }
2188
2189 9
    return max($this->array);
2190
  }
2191
2192
  /**
2193
   * Merge the new $array into the current array.
2194
   *
2195
   * - keep key,value from the current array, also if the index is in the new $array
2196
   *
2197
   * @param array $array
2198
   * @param bool  $recursive
2199
   *
2200
   * @return static <p>(Immutable)</p>
2201
   */
2202 25 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...
2203
  {
2204 25
    if (true === $recursive) {
2205 4
      $result = \array_replace_recursive($this->array, $array);
2206 4
    } else {
2207 21
      $result = \array_replace($this->array, $array);
2208
    }
2209
2210 25
    return static::create($result);
2211
  }
2212
2213
  /**
2214
   * Merge the new $array into the current array.
2215
   *
2216
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2217
   * - create new indexes
2218
   *
2219
   * @param array $array
2220
   * @param bool  $recursive
2221
   *
2222
   * @return static <p>(Immutable)</p>
2223
   */
2224 16 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...
2225
  {
2226 16
    if (true === $recursive) {
2227 4
      $result = \array_merge_recursive($this->array, $array);
2228 4
    } else {
2229 12
      $result = \array_merge($this->array, $array);
2230
    }
2231
2232 16
    return static::create($result);
2233
  }
2234
2235
  /**
2236
   * Merge the the current array into the $array.
2237
   *
2238
   * - use key,value from the new $array, also if the index is in the current array
2239
   *
2240
   * @param array $array
2241
   * @param bool  $recursive
2242
   *
2243
   * @return static <p>(Immutable)</p>
2244
   */
2245 16 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...
2246
  {
2247 16
    if (true === $recursive) {
2248 4
      $result = \array_replace_recursive($array, $this->array);
2249 4
    } else {
2250 12
      $result = \array_replace($array, $this->array);
2251
    }
2252
2253 16
    return static::create($result);
2254
  }
2255
2256
  /**
2257
   * Merge the current array into the new $array.
2258
   *
2259
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
2260
   * - create new indexes
2261
   *
2262
   * @param array $array
2263
   * @param bool  $recursive
2264
   *
2265
   * @return static <p>(Immutable)</p>
2266
   */
2267 17 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...
2268
  {
2269 17
    if (true === $recursive) {
2270 4
      $result = \array_merge_recursive($array, $this->array);
2271 4
    } else {
2272 13
      $result = \array_merge($array, $this->array);
2273
    }
2274
2275 17
    return static::create($result);
2276
  }
2277
2278
  /**
2279
   * Get the min value from an array.
2280
   *
2281
   * @return mixed
2282
   */
2283 10
  public function min()
2284
  {
2285 10
    if ($this->count() === 0) {
2286 1
      return false;
2287
    }
2288
2289 9
    return min($this->array);
2290
  }
2291
2292
  /**
2293
   * Move an array element to a new index.
2294
   *
2295
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2296
   *
2297
   * @param int|string $from
2298
   * @param int|string $to
2299
   *
2300
   * @return static <p>(Immutable)</p>
2301
   */
2302 1
  public function moveElement($from, $to)
2303
  {
2304 1
    $array = $this->array;
2305
2306 1
    if (is_int($from)) {
2307 1
      $tmp = \array_splice($array, $from, 1);
2308 1
      \array_splice($array, $to, 0, $tmp);
2309 1
      $output = $array;
2310 1
    } elseif (is_string($from)) {
2311 1
      $indexToMove = \array_search($from, \array_keys($array), true);
2312 1
      $itemToMove = $array[$from];
2313 1
      \array_splice($array, $indexToMove, 1);
2314 1
      $i = 0;
2315 1
      $output = array();
2316 1
      foreach ($array as $key => $item) {
2317 1
        if ($i == $to) {
2318 1
          $output[$from] = $itemToMove;
2319 1
        }
2320 1
        $output[$key] = $item;
2321 1
        $i++;
2322 1
      }
2323 1
    } else {
2324
      $output = array();
2325
    }
2326
2327 1
    return static::create($output);
2328
  }
2329
2330
  /**
2331
   * Convert a object into an array.
2332
   *
2333
   * @param object $object
2334
   *
2335
   * @return mixed
2336
   */
2337 5
  protected static function objectToArray($object)
2338
  {
2339 5
    if (!is_object($object)) {
2340 4
      return $object;
2341
    }
2342
2343 5
    if (is_object($object)) {
2344 5
      $object = get_object_vars($object);
2345 5
    }
2346
2347 5
    return array_map(array('self', 'objectToArray'), $object);
2348
  }
2349
2350
  /**
2351
   * Get a subset of the items from the given array.
2352
   *
2353
   * @param mixed[] $keys
2354
   *
2355
   * @return static <p>(Immutable)</p>
2356
   */
2357
  public function only(array $keys)
2358
  {
2359
    $array = $this->array;
2360
2361
    return static::create(\array_intersect_key($array, \array_flip($keys)));
2362
  }
2363
2364
  /**
2365
   * Pad array to the specified size with a given value.
2366
   *
2367
   * @param int   $size  <p>Size of the result array.</p>
2368
   * @param mixed $value <p>Empty value by default.</p>
2369
   *
2370
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
2371
   */
2372 4
  public function pad($size, $value)
2373
  {
2374 4
    $result = \array_pad($this->array, $size, $value);
2375
2376 4
    return static::create($result);
2377
  }
2378
2379
  /**
2380
   * Pop a specified value off the end of the current array.
2381
   *
2382
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
2383
   */
2384 16
  public function pop()
2385
  {
2386 16
    return \array_pop($this->array);
2387
  }
2388
2389
  /**
2390
   * Prepend a (key) + value to the current array.
2391
   *
2392
   * @param mixed $value
2393
   * @param mixed $key
2394
   *
2395
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2396
   */
2397 8
  public function prepend($value, $key = null)
2398
  {
2399 8
    if ($key === null) {
2400 8
      \array_unshift($this->array, $value);
2401 8
    } else {
2402
      /** @noinspection AdditionOperationOnArraysInspection */
2403 1
      $this->array = array($key => $value) + $this->array;
2404
    }
2405
2406 8
    return $this;
2407
  }
2408
2409
  /**
2410
   * Add a suffix to each key.
2411
   *
2412
   * @param string $suffix
2413
   *
2414
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2415
   */
2416 10 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...
2417
  {
2418 10
    $result = array();
2419 10
    foreach ($this->array as $key => $item) {
2420 9
      if ($item instanceof self) {
2421
        $result[$key] = $item->prependToEachKey($suffix);
2422 9
      } elseif (is_array($item)) {
2423
        $result[$key] = self::create($item)->prependToEachKey($suffix)->toArray();
2424
      } else {
2425 9
        $result[$key . $suffix] = $item;
2426
      }
2427
2428 10
    }
2429
2430 10
    return self::create($result);
2431
  }
2432
2433
  /**
2434
   * Add a suffix to each value.
2435
   *
2436
   * @param mixed $suffix
2437
   *
2438
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2439
   */
2440 10 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...
2441
  {
2442 10
    $result = array();
2443 10
    foreach ($this->array as $key => $item) {
2444 9
      if ($item instanceof self) {
2445
        $result[$key] = $item->prependToEachValue($suffix);
2446 9
      } elseif (is_array($item)) {
2447
        $result[$key] = self::create($item)->prependToEachValue($suffix)->toArray();
2448 9
      } elseif (is_object($item)) {
2449 1
        $result[$key] = $item;
2450 1
      } else {
2451 8
        $result[$key] = $item . $suffix;
2452
      }
2453 10
    }
2454
2455 10
    return self::create($result);
2456
  }
2457
2458
  /**
2459
   * Push one or more values onto the end of array at once.
2460
   *
2461
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2462
   */
2463 4 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...
2464
  {
2465 4
    if (func_num_args()) {
2466 4
      $args = \array_merge(array(&$this->array), func_get_args());
2467 4
      call_user_func_array('array_push', $args);
2468 4
    }
2469
2470 4
    return $this;
2471
  }
2472
2473
  /**
2474
   * Get a random value from the current array.
2475
   *
2476
   * @param null|int $number <p>How many values you will take?</p>
2477
   *
2478
   * @return static <p>(Immutable)</p>
2479
   */
2480 17
  public function randomImmutable($number = null)
2481
  {
2482 17
    if ($this->count() === 0) {
2483
      return static::create();
2484
    }
2485
2486 17 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...
2487 14
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2488
2489 14
      return static::create($arrayRandValue);
2490
    }
2491
2492 5
    $arrayTmp = $this->array;
2493 5
    shuffle($arrayTmp);
2494
2495 5
    return static::create($arrayTmp)->firstsImmutable($number);
2496
  }
2497
2498
  /**
2499
   * Pick a random key/index from the keys of this array.
2500
   *
2501
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
2502
   *
2503
   * @throws \RangeException If array is empty
2504
   */
2505 4
  public function randomKey()
2506
  {
2507 4
    $result = $this->randomKeys(1);
2508
2509 4
    if (!isset($result[0])) {
2510
      $result[0] = null;
2511
    }
2512
2513 4
    return $result[0];
2514
  }
2515
2516
  /**
2517
   * Pick a given number of random keys/indexes out of this array.
2518
   *
2519
   * @param int $number <p>The number of keys/indexes (should be <= $this->count())</p>
2520
   *
2521
   * @return static <p>(Immutable)</p>
2522
   *
2523
   * @throws \RangeException If array is empty
2524
   */
2525 14
  public function randomKeys($number)
2526
  {
2527 14
    $number = (int)$number;
2528 14
    $count = $this->count();
2529
2530 14
    if ($number === 0 || $number > $count) {
2531 3
      throw new \RangeException(
2532 3
          sprintf(
2533 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2534 3
              $number,
2535
              $count
2536 3
          )
2537 3
      );
2538
    }
2539
2540 11
    $result = (array)\array_rand($this->array, $number);
2541
2542 11
    return static::create($result);
2543
  }
2544
2545
  /**
2546
   * Get a random value from the current array.
2547
   *
2548
   * @param null|int $number <p>How many values you will take?</p>
2549
   *
2550
   * @return static <p>(Mutable)</p>
2551
   */
2552 17
  public function randomMutable($number = null)
2553
  {
2554 17
    if ($this->count() === 0) {
2555
      return static::create();
2556
    }
2557
2558 17 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...
2559 7
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2560 7
      $this->array = $arrayRandValue;
2561
2562 7
      return $this;
2563
    }
2564
2565 11
    shuffle($this->array);
2566
2567 11
    return $this->firstsMutable($number);
2568
  }
2569
2570
  /**
2571
   * Pick a random value from the values of this array.
2572
   *
2573
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2574
   */
2575 4
  public function randomValue()
2576
  {
2577 4
    $result = $this->randomImmutable();
2578
2579 4
    if (!isset($result[0])) {
2580
      $result[0] = null;
2581
    }
2582
2583 4
    return $result[0];
2584
  }
2585
2586
  /**
2587
   * Pick a given number of random values out of this array.
2588
   *
2589
   * @param int $number
2590
   *
2591
   * @return static <p>(Mutable)</p>
2592
   */
2593 7
  public function randomValues($number)
2594
  {
2595 7
    $number = (int)$number;
2596
2597 7
    return $this->randomMutable($number);
2598
  }
2599
2600
  /**
2601
   * Get a random value from an array, with the ability to skew the results.
2602
   *
2603
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2604
   *
2605
   * @param array    $array
2606
   * @param null|int $number <p>How many values you will take?</p>
2607
   *
2608
   * @return static <p>(Immutable)</p>
2609
   */
2610 9
  public function randomWeighted(array $array, $number = null)
2611
  {
2612 9
    $options = array();
2613 9
    foreach ($array as $option => $weight) {
2614 9
      if ($this->searchIndex($option) !== false) {
2615 2
        for ($i = 0; $i < $weight; ++$i) {
2616 1
          $options[] = $option;
2617 1
        }
2618 2
      }
2619 9
    }
2620
2621 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2622
  }
2623
2624
  /**
2625
   * Reduce the current array via callable e.g. anonymous-function.
2626
   *
2627
   * @param mixed $callable
2628
   * @param array $init
2629
   *
2630
   * @return static <p>(Immutable)</p>
2631
   */
2632 4
  public function reduce($callable, array $init = array())
2633
  {
2634 4
    $result = \array_reduce($this->array, $callable, $init);
2635
2636 4
    if ($result === null) {
2637
      $this->array = array();
2638
    } else {
2639 4
      $this->array = (array)$result;
2640
    }
2641
2642 4
    return static::create($this->array);
2643
  }
2644
2645
  /**
2646
   * Create a numerically re-indexed Arrayy object.
2647
   *
2648
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2649
   */
2650 9
  public function reindex()
2651
  {
2652 9
    $this->array = \array_values($this->array);
2653
2654 9
    return $this;
2655
  }
2656
2657
  /**
2658
   * Return all items that fail the truth test.
2659
   *
2660
   * @param \Closure $closure
2661
   *
2662
   * @return static <p>(Immutable)</p>
2663
   */
2664 1 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...
2665
  {
2666 1
    $filtered = array();
2667
2668 1
    foreach ($this->array as $key => $value) {
2669 1
      if (!$closure($value, $key)) {
2670 1
        $filtered[$key] = $value;
2671 1
      }
2672 1
    }
2673
2674 1
    return static::create($filtered);
2675
  }
2676
2677
  /**
2678
   * Remove a value from the current array (optional using dot-notation).
2679
   *
2680
   * @param mixed $key
2681
   *
2682
   * @return static <p>(Immutable)</p>
2683
   */
2684 18
  public function remove($key)
2685
  {
2686
    // Recursive call
2687 18
    if (is_array($key)) {
2688
      foreach ($key as $k) {
2689
        $this->internalRemove($k);
2690
      }
2691
2692
      return static::create($this->array);
2693
    }
2694
2695 18
    $this->internalRemove($key);
2696
2697 18
    return static::create($this->array);
2698
  }
2699
2700
  /**
2701
   * Remove the first value from the current array.
2702
   *
2703
   * @return static <p>(Immutable)</p>
2704
   */
2705 7
  public function removeFirst()
2706
  {
2707 7
    $tmpArray = $this->array;
2708 7
    \array_shift($tmpArray);
2709
2710 7
    return static::create($tmpArray);
2711
  }
2712
2713
  /**
2714
   * Remove the last value from the current array.
2715
   *
2716
   * @return static <p>(Immutable)</p>
2717
   */
2718 7
  public function removeLast()
2719
  {
2720 7
    $tmpArray = $this->array;
2721 7
    \array_pop($tmpArray);
2722
2723 7
    return static::create($tmpArray);
2724
  }
2725
2726
  /**
2727
   * Removes a particular value from an array (numeric or associative).
2728
   *
2729
   * @param mixed $value
2730
   *
2731
   * @return static <p>(Immutable)</p>
2732
   */
2733 7
  public function removeValue($value)
2734
  {
2735 7
    $isNumericArray = true;
2736 7
    foreach ($this->array as $key => $item) {
2737 6
      if ($item === $value) {
2738 6
        if (!is_int($key)) {
2739
          $isNumericArray = false;
2740
        }
2741 6
        unset($this->array[$key]);
2742 6
      }
2743 7
    }
2744
2745 7
    if ($isNumericArray) {
2746 7
      $this->array = \array_values($this->array);
2747 7
    }
2748
2749 7
    return static::create($this->array);
2750
  }
2751
2752
  /**
2753
   * Generate array of repeated arrays.
2754
   *
2755
   * @param int $times <p>How many times has to be repeated.</p>
2756
   *
2757
   * @return Arrayy
2758
   */
2759 1
  public function repeat($times)
2760
  {
2761 1
    if ($times === 0) {
2762 1
      return new static();
2763
    }
2764
2765 1
    return static::create(\array_fill(0, (int)$times, $this->array));
2766
  }
2767
2768
  /**
2769
   * Replace a key with a new key/value pair.
2770
   *
2771
   * @param $replace
2772
   * @param $key
2773
   * @param $value
2774
   *
2775
   * @return static <p>(Immutable)</p>
2776
   */
2777 2
  public function replace($replace, $key, $value)
2778
  {
2779 2
    $this->remove($replace);
2780
2781 2
    return $this->set($key, $value);
2782
  }
2783
2784
  /**
2785
   * Create an array using the current array as values and the other array as keys.
2786
   *
2787
   * @param array $keys <p>An array of keys.</p>
2788
   *
2789
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
2790
   */
2791 2
  public function replaceAllKeys(array $keys)
2792
  {
2793 2
    $result = \array_combine($keys, $this->array);
2794
2795 2
    return static::create($result);
2796
  }
2797
2798
  /**
2799
   * Create an array using the current array as keys and the other array as values.
2800
   *
2801
   * @param array $array <p>An array o values.</p>
2802
   *
2803
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
2804
   */
2805 2
  public function replaceAllValues(array $array)
2806
  {
2807 2
    $result = \array_combine($this->array, $array);
2808
2809 2
    return static::create($result);
2810
  }
2811
2812
  /**
2813
   * Replace the keys in an array with another set.
2814
   *
2815
   * @param array $keys <p>An array of keys matching the array's size</p>
2816
   *
2817
   * @return static <p>(Immutable)</p>
2818
   */
2819 1
  public function replaceKeys(array $keys)
2820
  {
2821 1
    $values = \array_values($this->array);
2822 1
    $result = \array_combine($keys, $values);
2823
2824 1
    return static::create($result);
2825
  }
2826
2827
  /**
2828
   * Replace the first matched value in an array.
2829
   *
2830
   * @param mixed $search
2831
   * @param mixed $replacement
2832
   *
2833
   * @return static <p>(Immutable)</p>
2834
   */
2835 3
  public function replaceOneValue($search, $replacement = '')
2836
  {
2837 3
    $array = $this->array;
2838 3
    $key = \array_search($search, $array, true);
2839
2840 3
    if ($key !== false) {
2841 3
      $array[$key] = $replacement;
2842 3
    }
2843
2844 3
    return static::create($array);
2845
  }
2846
2847
  /**
2848
   * Replace values in the current array.
2849
   *
2850
   * @param string $search      <p>The string to replace.</p>
2851
   * @param string $replacement <p>What to replace it with.</p>
2852
   *
2853
   * @return static <p>(Immutable)</p>
2854
   */
2855 1
  public function replaceValues($search, $replacement = '')
2856
  {
2857 1
    $array = $this->each(
2858
        function ($value) use ($search, $replacement) {
2859 1
          return UTF8::str_replace($search, $replacement, $value);
2860
        }
2861 1
    );
2862
2863 1
    return $array;
2864
  }
2865
2866
  /**
2867
   * Get the last elements from index $from until the end of this array.
2868
   *
2869
   * @param int $from
2870
   *
2871
   * @return static <p>(Immutable)</p>
2872
   */
2873 15
  public function rest($from = 1)
2874
  {
2875 15
    $tmpArray = $this->array;
2876
2877 15
    return static::create(\array_splice($tmpArray, $from));
2878
  }
2879
2880
  /**
2881
   * Return the array in the reverse order.
2882
   *
2883
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2884
   */
2885 8
  public function reverse()
2886
  {
2887 8
    $this->array = \array_reverse($this->array);
2888
2889 8
    return $this;
2890
  }
2891
2892
  /**
2893
   * Sort an array in reverse order.
2894
   *
2895
   * @param int $sort_flags [optional] <p>
2896
   *                        You may modify the behavior of the sort using the optional
2897
   *                        parameter sort_flags, for details
2898
   *                        see sort.
2899
   *                        </p>
2900
   *
2901
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2902
   */
2903 4
  public function rsort($sort_flags = null)
2904
  {
2905 4
    rsort($this->array, $sort_flags);
2906
2907 4
    return $this;
2908
  }
2909
2910
  /**
2911
   * Search for the first index of the current array via $value.
2912
   *
2913
   * @param mixed $value
2914
   *
2915
   * @return int|float|string
2916
   */
2917 20
  public function searchIndex($value)
2918
  {
2919 20
    return \array_search($value, $this->array, true);
2920
  }
2921
2922
  /**
2923
   * Search for the value of the current array via $index.
2924
   *
2925
   * @param mixed $index
2926
   *
2927
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
2928
   */
2929 9
  public function searchValue($index)
2930
  {
2931
    // init
2932 9
    $return = array();
2933
2934 9
    if ($this->isEmpty()) {
2935
      return static::create();
2936
    }
2937
2938
    // php cast "bool"-index into "int"-index
2939 9
    if ((bool)$index === $index) {
2940 1
      $index = (int)$index;
2941 1
    }
2942
2943 9
    if (\array_key_exists($index, $this->array) === true) {
2944 7
      $return = array($this->array[$index]);
2945 7
    }
2946
2947
2948 9
    return static::create($return);
2949
  }
2950
2951
  /**
2952
   * Set a value for the current array (optional using dot-notation).
2953
   *
2954
   * @param string $key   <p>The key to set.</p>
2955
   * @param mixed  $value <p>Its value.</p>
2956
   *
2957
   * @return static <p>(Immutable)</p>
2958
   */
2959 17
  public function set($key, $value)
2960
  {
2961 17
    $this->internalSet($key, $value);
2962
2963 17
    return static::create($this->array);
2964
  }
2965
2966
  /**
2967
   * Get a value from a array and set it if it was not.
2968
   *
2969
   * WARNING: this method only set the value, if the $key is not already set
2970
   *
2971
   * @param string $key      <p>The key</p>
2972
   * @param mixed  $fallback <p>The default value to set if it isn't.</p>
2973
   *
2974
   * @return mixed <p>(Mutable)</p>
2975
   */
2976 11
  public function setAndGet($key, $fallback = null)
2977
  {
2978
    // If the key doesn't exist, set it.
2979 11
    if (!$this->has($key)) {
2980 4
      $this->array = $this->set($key, $fallback)->getArray();
2981 4
    }
2982
2983 11
    return $this->get($key);
2984
  }
2985
2986
  /**
2987
   * Shifts a specified value off the beginning of array.
2988
   *
2989
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
2990
   */
2991 4
  public function shift()
2992
  {
2993 4
    return \array_shift($this->array);
2994
  }
2995
2996
  /**
2997
   * Shuffle the current array.
2998
   *
2999
   * @param bool $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3000
   *
3001
   * @return static <p>(Immutable)</p>
3002
   */
3003 1
  public function shuffle($secure = false)
3004
  {
3005 1
    $array = $this->array;
3006
3007 1
    if ($secure !== true) {
3008 1
      \shuffle($array);
3009 1
    } else {
3010 1
      $size = \count($array);
3011 1
      $keys = \array_keys($array);
3012 1
      for ($i = $size - 1; $i > 0; --$i) {
3013 1
        $r = \random_int(0, $i);
3014 1
        if ($r !== $i) {
3015
          $temp = $array[$keys[$r]];
3016
          $array[$keys[$r]] = $array[$keys[$i]];
3017
          $array[$keys[$i]] = $temp;
3018
        }
3019 1
      }
3020
3021
      // Reset indices
3022 1
      $array = \array_values($array);
3023
    }
3024
3025 1
    return static::create($array);
3026
  }
3027
3028
  /**
3029
   * Get the size of an array.
3030
   *
3031
   * @return int
3032
   */
3033 93
  public function size()
3034
  {
3035 93
    return count($this->array);
3036
  }
3037
3038
  /**
3039
   * Extract a slice of the array.
3040
   *
3041
   * @param int      $offset       <p>Slice begin index.</p>
3042
   * @param int|null $length       <p>Length of the slice.</p>
3043
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3044
   *
3045
   * @return static <p>A slice of the original array with length $length.</p>
3046
   */
3047 4
  public function slice($offset, $length = null, $preserveKeys = false)
3048
  {
3049 4
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
3050
3051 4
    return static::create($result);
3052
  }
3053
3054
  /**
3055
   * Sort the current array and optional you can keep the keys.
3056
   *
3057
   * @param integer $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3058
   * @param integer $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3059
   *                           <strong>SORT_NATURAL</strong></p>
3060
   * @param bool    $keepKeys
3061
   *
3062
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3063
   */
3064 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
3065
  {
3066 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
3067
3068 19
    return $this;
3069
  }
3070
3071
  /**
3072
   * Sort the current array by key.
3073
   *
3074
   * @link http://php.net/manual/en/function.ksort.php
3075
   * @link http://php.net/manual/en/function.krsort.php
3076
   *
3077
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3078
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3079
   *                              <strong>SORT_NATURAL</strong></p>
3080
   *
3081
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3082
   */
3083 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
3084
  {
3085 18
    $this->sorterKeys($this->array, $direction, $strategy);
3086
3087 18
    return $this;
3088
  }
3089
3090
  /**
3091
   * Sort the current array by value.
3092
   *
3093
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3094
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
3095
   *
3096
   * @return static <p>(Mutable)</p>
3097
   */
3098 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
3099
  {
3100 1
    return $this->sort($direction, $strategy, true);
3101
  }
3102
3103
  /**
3104
   * Sort the current array by value.
3105
   *
3106
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3107
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
3108
   *
3109
   * @return static <p>(Mutable)</p>
3110
   */
3111 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
3112
  {
3113 1
    return $this->sort($direction, $strategy, false);
3114
  }
3115
3116
  /**
3117
   * Sort a array by value, by a closure or by a property.
3118
   *
3119
   * - If the sorter is null, the array is sorted naturally.
3120
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3121
   *
3122
   * @param null       $sorter
3123
   * @param string|int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3124
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3125
   *                              <strong>SORT_NATURAL</strong></p>
3126
   *
3127
   * @return static <p>(Immutable)</p>
3128
   */
3129 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
3130
  {
3131 1
    $array = (array)$this->array;
3132 1
    $direction = $this->getDirection($direction);
3133
3134
    // Transform all values into their results.
3135 1
    if ($sorter) {
3136 1
      $arrayy = static::create($array);
3137
3138 1
      $that = $this;
3139 1
      $results = $arrayy->each(
3140
          function ($value) use ($sorter, $that) {
3141 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3142
          }
3143 1
      );
3144
3145 1
      $results = $results->getArray();
3146 1
    } else {
3147 1
      $results = $array;
3148
    }
3149
3150
    // Sort by the results and replace by original values
3151 1
    \array_multisort($results, $direction, $strategy, $array);
3152
3153 1
    return static::create($array);
3154
  }
3155
3156
  /**
3157
   * sorting keys
3158
   *
3159
   * @param array $elements
3160
   * @param int   $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3161
   * @param int   $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
3162
   *
3163
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3164
   */
3165 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
3166
  {
3167 18
    $direction = $this->getDirection($direction);
3168
3169
    switch ($direction) {
3170 18
      case 'desc':
3171 18
      case SORT_DESC:
3172 6
        krsort($elements, $strategy);
3173 6
        break;
3174 13
      case 'asc':
3175 13
      case SORT_ASC:
3176 13
      default:
3177 13
        ksort($elements, $strategy);
3178 13
    }
3179
3180 18
    return $this;
3181
  }
3182
3183
  /**
3184
   * @param array      &$elements
3185
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3186
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3187
   *                              <strong>SORT_NATURAL</strong></p>
3188
   * @param bool       $keepKeys
3189
   *
3190
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3191
   */
3192 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
3193
  {
3194 19
    $direction = $this->getDirection($direction);
3195
3196 19
    if (!$strategy) {
3197 19
      $strategy = SORT_REGULAR;
3198 19
    }
3199
3200
    switch ($direction) {
3201 19
      case 'desc':
3202 19
      case SORT_DESC:
3203 9
        if ($keepKeys) {
3204 5
          arsort($elements, $strategy);
3205 5
        } else {
3206 4
          rsort($elements, $strategy);
3207
        }
3208 9
        break;
3209 10
      case 'asc':
3210 10
      case SORT_ASC:
3211 10
      default:
3212 10
        if ($keepKeys) {
3213 4
          asort($elements, $strategy);
3214 4
        } else {
3215 6
          sort($elements, $strategy);
3216
        }
3217 10
    }
3218
3219 19
    return $this;
3220
  }
3221
3222
  /**
3223
   * Split an array in the given amount of pieces.
3224
   *
3225
   * @param int  $numberOfPieces
3226
   * @param bool $keepKeys
3227
   *
3228
   * @return static <p>(Immutable)</p>
3229
   */
3230 1
  public function split($numberOfPieces = 2, $keepKeys = false)
3231
  {
3232 1
    $arrayCount = $this->count();
3233
3234 1
    if ($arrayCount === 0) {
3235 1
      $result = array();
3236 1
    } else {
3237 1
      $numberOfPieces = (int)$numberOfPieces;
3238 1
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
3239 1
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
3240
    }
3241
3242 1
    return static::create($result);
3243
  }
3244
3245
  /**
3246
   * Stripe all empty items.
3247
   *
3248
   * @return static <p>(Immutable)</p>
3249
   */
3250 1
  public function stripEmpty()
3251
  {
3252 1
    return $this->filter(
3253
        function ($item) {
3254 1
          if ($item === null) {
3255 1
            return false;
3256
          }
3257
3258 1
          return (bool)trim((string)$item);
3259
        }
3260 1
    );
3261
  }
3262
3263
  /**
3264
   * Swap two values between positions by key.
3265
   *
3266
   * @param string|int $swapA <p>a key in the array</p>
3267
   * @param string|int $swapB <p>a key in the array</p>
3268
   *
3269
   * @return static <p>(Immutable)</p>
3270
   */
3271 1
  public function swap($swapA, $swapB)
3272
  {
3273 1
    $array = $this->array;
3274
3275 1
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
3276
3277 1
    return static::create($array);
3278
  }
3279
3280
  /**
3281
   * alias: for "Arrayy->getArray()"
3282
   *
3283
   * @see Arrayy::getArray()
3284
   */
3285 186
  public function toArray()
3286
  {
3287 186
    return $this->getArray();
3288
  }
3289
3290
  /**
3291
   * Convert the current array to JSON.
3292
   *
3293
   * @param null|int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3294
   * @param int      $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3295
   *
3296
   * @return string
3297
   */
3298 6
  public function toJson($options = null, $depth = 512)
3299
  {
3300 6
    return UTF8::json_encode($this->array, $options, $depth);
3301
  }
3302
3303
  /**
3304
   * Implodes array to a string with specified separator.
3305
   *
3306
   * @param string $separator [optional] <p>The element's separator.</p>
3307
   *
3308
   * @return string <p>The string representation of array, separated by ",".</p>
3309
   */
3310 19
  public function toString($separator = ',')
3311
  {
3312 19
    return $this->implode($separator);
3313
  }
3314
3315
  /**
3316
   * Return a duplicate free copy of the current array.
3317
   *
3318
   * @return static <p>(Mutable)</p>
3319
   */
3320 9
  public function unique()
3321
  {
3322
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3323
3324 9
    $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...
3325 9
        $this->array,
3326
        function ($resultArray, $value) {
3327 8
          if (!in_array($value, $resultArray, true)) {
3328 8
            $resultArray[] = $value;
3329 8
          }
3330
3331 8
          return $resultArray;
3332 9
        },
3333 9
        array()
3334 9
    );
3335
3336 9 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...
3337
      $this->array = array();
3338
    } else {
3339 9
      $this->array = (array)$this->array;
3340
    }
3341
3342 9
    return $this;
3343
  }
3344
3345
  /**
3346
   * Return a duplicate free copy of the current array. (with the old keys)
3347
   *
3348
   * @return static <p>(Mutable)</p>
3349
   */
3350 9
  public function uniqueKeepIndex()
3351
  {
3352
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3353
3354
    // init
3355 9
    $array = $this->array;
3356
3357 9
    $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...
3358 9
        \array_keys($array),
3359 9
        function ($resultArray, $key) use ($array) {
3360 8
          if (!in_array($array[$key], $resultArray, true)) {
3361 8
            $resultArray[$key] = $array[$key];
3362 8
          }
3363
3364 8
          return $resultArray;
3365 9
        },
3366 9
        array()
3367 9
    );
3368
3369 9 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...
3370
      $this->array = array();
3371
    } else {
3372 9
      $this->array = (array)$this->array;
3373
    }
3374
3375 9
    return $this;
3376
  }
3377
3378
  /**
3379
   * alias: for "Arrayy->unique()"
3380
   *
3381
   * @see Arrayy::unique()
3382
   *
3383
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3384
   */
3385 9
  public function uniqueNewIndex()
3386
  {
3387 9
    return $this->unique();
3388
  }
3389
3390
  /**
3391
   * Prepends one or more values to the beginning of array at once.
3392
   *
3393
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3394
   */
3395 4 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...
3396
  {
3397 4
    if (func_num_args()) {
3398 4
      $args = \array_merge(array(&$this->array), func_get_args());
3399 4
      call_user_func_array('array_unshift', $args);
3400 4
    }
3401
3402 4
    return $this;
3403
  }
3404
3405
  /**
3406
   * Get all values from a array.
3407
   *
3408
   * @return static <p>(Immutable)</p>
3409
   */
3410 2
  public function values()
3411
  {
3412 2
    return static::create(\array_values((array)$this->array));
3413
  }
3414
3415
  /**
3416
   * Apply the given function to every element in the array, discarding the results.
3417
   *
3418
   * @param callable $callable
3419
   * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
3420
   *
3421
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3422
   */
3423 9
  public function walk($callable, $recursive = false)
3424
  {
3425 9
    if (true === $recursive) {
3426 4
      \array_walk_recursive($this->array, $callable);
3427 4
    } else {
3428 5
      \array_walk($this->array, $callable);
3429
    }
3430
3431 9
    return $this;
3432
  }
3433
}
3434