Completed
Push — master ( 52ac1c...1ecdba )
by Lars
06:16 queued 01:21
created

Arrayy::randomMutable()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 6
Ratio 35.29 %

Code Coverage

Tests 8
CRAP Score 3.0123

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 6
loc 17
ccs 8
cts 9
cp 0.8889
crap 3.0123
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Arrayy;
4
5
use voku\helper\UTF8;
6
7
/** @noinspection ClassReImplementsParentInterfaceInspection */
8
9
/**
10
 * Methods to manage arrays.
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
class Arrayy extends \ArrayObject implements \ArrayAccess, \Serializable, \Countable
16
{
17
  /**
18
   * @var array
19
   */
20
  protected $array = array();
21
22
  /**
23
   * @var string
24
   */
25
  protected $pathSeparator = '.';
26
27
  /** @noinspection MagicMethodsValidityInspection */
28
  /**
29
   * Initializes
30
   *
31
   * @param array $array
32
   */
33 737
  public function __construct($array = array())
34
  {
35 737
    $array = $this->fallbackForArray($array);
36
37 735
    $this->array = $array;
38 735
  }
39
40
  /**
41
   * Get a value by key.
42
   *
43
   * @param $key
44
   *
45
   * @return mixed Get a Value from the current array.
46
   */
47 1
  public function __get($key)
48
  {
49 1
    $return = $this->get($key);
50
51 1
    if (is_array($return)) {
52
      return self::create($return);
53
    }
54
55 1
    return $return;
56
  }
57
58
  /**
59
   * Call object as function.
60
   *
61
   * @param mixed $key
62
   *
63
   * @return mixed
64
   */
65
  public function __invoke($key = null)
66
  {
67
    if ($key !== null) {
68
      if (isset($this->array[$key])) {
69
        return $this->array[$key];
70
      } else {
71
        return false;
72
      }
73
    }
74
75
    return (array)$this->array;
76
  }
77
78
  /**
79
   * Whether or not an element exists by key.
80
   *
81
   * @param mixed $key
82
   *
83
   * @return bool True is the key/index exists, otherwise false.
84
   */
85
  public function __isset($key)
86
  {
87
    return $this->offsetExists($key);
88
  }
89
90
  /**
91
   * Assigns a value to the specified element.
92
   *
93
   * @param mixed $key
94
   * @param mixed $value
95
   */
96 2
  public function __set($key, $value)
97
  {
98 2
    $this->internalSet($key, $value);
99 2
  }
100
101
  /**
102
   * magic to string
103
   *
104
   * @return string
105
   */
106 16
  public function __toString()
107
  {
108 16
    return $this->toString();
109
  }
110
111
  /**
112
   * Unset element by key.
113
   *
114
   * @param mixed $key
115
   */
116
  public function __unset($key)
117
  {
118
    unset($this->array[$key]);
119
  }
120
121
  /**
122
   * alias: for "Arrayy->append()"
123
   *
124
   * @see Arrayy::append()
125
   *
126
   * @param mixed $value
127
   *
128
   * @return self (Mutable) Return this Arrayy object, with the appended values.
129
   */
130 1
  public function add($value)
131
  {
132 1
    return $this->append($value);
133
  }
134
135
  /**
136
   * Append a value to the current array.
137
   *
138
   * @param mixed $value
139
   *
140
   * @return self (Mutable) Return this Arrayy object, with the appended values.
141
   */
142 9
  public function append($value)
143
  {
144 9
    $this->array[] = $value;
145
146 9
    return $this;
147
  }
148
149
  /**
150
   * Count the values from the current array.
151
   *
152
   * alias: for "Arrayy->size()"
153
   *
154
   * @see Arrayy::size()
155
   *
156
   * @return int
157
   */
158 111
  public function count()
159
  {
160 111
    return $this->size();
161
  }
162
163
  /**
164
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
165
   *
166
   * @return ArrayyIterator An iterator for the values in the array.
167
   */
168 19
  public function getIterator()
169
  {
170 19
    return new ArrayyIterator($this->array);
171
  }
172
173
  /**
174
   * Whether or not an offset exists.
175
   *
176
   * @param int|float|string $offset
177
   *
178
   * @return bool
179
   */
180 38
  public function offsetExists($offset)
181
  {
182 38
    if ($this->isEmpty()) {
183 4
      return false;
184
    }
185
186
    // php cast "bool"-index into "int"-index
187 34
    if ((bool)$offset === $offset) {
188 1
      $offset = (int)$offset;
189 1
    }
190
191 34
    $tmpReturn = array_key_exists($offset, $this->array);
192
193
    if (
194
        $tmpReturn === true
195 34
        ||
196
        (
197
            $tmpReturn === false
198 11
            &&
199 11
            strpos((string)$offset, $this->pathSeparator) === false
200 11
        )
201 34
    ) {
202
203 32
      return $tmpReturn;
204
205
    } else {
206
207 2
      $offsetExists = false;
208
209 2
      if (strpos((string)$offset, $this->pathSeparator) !== false) {
210
211 2
        $offsetExists = false;
212 2
        $explodedPath = explode($this->pathSeparator, (string)$offset);
213 2
        $lastOffset = array_pop($explodedPath);
214 2
        $containerPath = implode($this->pathSeparator, $explodedPath);
215
216 2
        $this->callAtPath(
217 2
            $containerPath,
218
            function ($container) use ($lastOffset, &$offsetExists) {
219 2
              $offsetExists = array_key_exists($lastOffset, $container);
220 2
            }
221 2
        );
222 2
      }
223
224 2
      return $offsetExists;
225
    }
226
  }
227
228
  /**
229
   * Returns the value at specified offset.
230
   *
231
   * @param mixed $offset
232
   *
233
   * @return mixed return null if the offset did not exists
234
   */
235 24
  public function offsetGet($offset)
236
  {
237 24
    return $this->offsetExists($offset) ? $this->get($offset) : null;
238
  }
239
240
  /**
241
   * Assigns a value to the specified offset.
242
   *
243
   * @param mixed $offset
244
   * @param mixed $value
245
   */
246 15
  public function offsetSet($offset, $value)
247
  {
248 15
    if ($offset === null) {
249 4
      $this->array[] = $value;
250 4
    } else {
251 11
      $this->internalSet($offset, $value);
252
    }
253 15
  }
254
255
  /**
256
   * Unset an offset.
257
   *
258
   * @param mixed $offset
259
   */
260 6
  public function offsetUnset($offset)
261
  {
262 6
    if ($this->isEmpty()) {
263 1
      return;
264
    }
265
266 5
    if (array_key_exists($offset, $this->array)) {
267 3
      unset($this->array[$offset]);
268
269 3
      return;
270
    }
271
272 2
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
273
274 1
      $path = explode($this->pathSeparator, (string)$offset);
275 1
      $pathToUnset = array_pop($path);
276
277 1
      $this->callAtPath(
278 1
          implode($this->pathSeparator, $path),
279
          function (&$offset) use (&$pathToUnset) {
280 1
            unset($offset[$pathToUnset]);
281 1
          }
282 1
      );
283
284 1
    }
285 2
  }
286
287
  /**
288
   * Serialize the current array.
289
   *
290
   * @return string
291
   */
292 2
  public function serialize()
293
  {
294 2
    return serialize($this->array);
295
  }
296
297
  /**
298
   * Unserialize an string and return this object.
299
   *
300
   * @param string $string
301
   *
302
   * @return self (Mutable)
303
   */
304 2
  public function unserialize($string)
305
  {
306 2
    $this->array = unserialize($string);
307
308 2
    return $this;
309
  }
310
311
  /**
312
   * Iterate over the current array and execute a callback for each loop.
313
   *
314
   * @param \Closure $closure
315
   *
316
   * @return Arrayy (Immutable)
317
   */
318 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...
319
  {
320 2
    $array = $this->array;
321
322 2
    foreach ($array as $key => $value) {
323 2
      $closure($value, $key);
324 2
    }
325
326 2
    return static::create($array);
327
  }
328
329
  /**
330
   * Returns the average value of the current array.
331
   *
332
   * @param int $decimals The number of decimals to return
333
   *
334
   * @return int|double The average value
335
   */
336 10
  public function average($decimals = 0)
337
  {
338 10
    $count = $this->count();
339
340 10
    if (!$count) {
341 2
      return 0;
342
    }
343
344 8
    if (!is_int($decimals)) {
345 3
      $decimals = 0;
346 3
    }
347
348 8
    return round(array_sum($this->array) / $count, $decimals);
349
  }
350
351
  /**
352
   * @param mixed      $path
353
   * @param callable   $callable
354
   * @param null|array $currentOffset
355
   */
356 2
  protected function callAtPath($path, $callable, &$currentOffset = null)
357
  {
358 2
    if ($currentOffset === null) {
359 2
      $currentOffset = &$this->array;
360 2
    }
361
362 2
    $explodedPath = explode($this->pathSeparator, $path);
363 2
    $nextPath = array_shift($explodedPath);
364
365 2
    if (!isset($currentOffset[$nextPath])) {
366
      return;
367
    }
368
369 2
    if (!empty($explodedPath)) {
370
      $this->callAtPath(
371
          implode($this->pathSeparator, $explodedPath),
372
          $callable,
373
          $currentOffset[$nextPath]
374
      );
375
    } else {
376 2
      $callable($currentOffset[$nextPath]);
377
    }
378 2
  }
379
380
  /**
381
   * Change the path separator of the array wrapper.
382
   *
383
   * By default, the separator is: .
384
   *
385
   * @param string $separator Separator to set.
386
   *
387
   * @return Arrayy Current instance.
388
   */
389
  public function changeSeparator($separator)
390
  {
391
    $this->pathSeparator = $separator;
392
393
    return $this;
394
  }
395
396
  /**
397
   * Create a chunked version of the current array.
398
   *
399
   * @param int  $size         Size of each chunk
400
   * @param bool $preserveKeys Whether array keys are preserved or no
401
   *
402
   * @return Arrayy (Immutable) A new array of chunks from the original array.
403
   */
404 4
  public function chunk($size, $preserveKeys = false)
405
  {
406 4
    $result = array_chunk($this->array, $size, $preserveKeys);
407
408 4
    return static::create($result);
409
  }
410
411
  /**
412
   * Clean all falsy values from the current array.
413
   *
414
   * @return Arrayy (Immutable)
415
   */
416 8
  public function clean()
417
  {
418 8
    return $this->filter(
419
        function ($value) {
420 7
          return (bool)$value;
421
        }
422 8
    );
423
  }
424
425
  /**
426
   * WARNING!!! -> Clear the current array.
427
   *
428
   * @return self (Mutable) Return this Arrayy object, with an empty array.
429
   */
430 4
  public function clear()
431
  {
432 4
    $this->array = array();
433
434 4
    return $this;
435
  }
436
437
  /**
438
   * Check if an item is in the current array.
439
   *
440
   * @param string|int|float $value
441
   *
442
   * @return bool
443
   */
444 13
  public function contains($value)
445
  {
446 13
    return in_array($value, $this->array, true);
447
  }
448
449
  /**
450
   * Check if an (case-insensitive) string is in the current array.
451
   *
452
   * @param string $value
453
   *
454
   * @return bool
455
   */
456 13
  public function containsCaseInsensitive($value)
457
  {
458 13
    return in_array(
459 13
        UTF8::strtolower($value),
460 13
        array_map(
461
            array(
462 13
                new UTF8(),
463 13
                'strtolower',
464 13
            ),
465 13
            $this->array
466 13
        ),
467
        true
468 13
    );
469
  }
470
471
  /**
472
   * Check if the given key/index exists in the array.
473
   *
474
   * @param string|int|float $key key/index to search for
475
   *
476
   * @return bool Returns true if the given key/index exists in the array, false otherwise
477
   */
478 4
  public function containsKey($key)
479
  {
480 4
    return $this->offsetExists($key);
481
  }
482
483
  /**
484
   * Check if all given needles are present in the array as key/index.
485
   *
486
   * @param array $needles
487
   *
488
   * @return bool Returns true if the given keys/indexes exists in the array, false otherwise
489
   */
490 1
  public function containsKeys(array $needles)
491
  {
492 1
    return count(array_intersect($needles, $this->keys()->getArray())) === count($needles);
493
  }
494
495
  /**
496
   * alias: for "Arrayy->contains()"
497
   *
498
   * @see Arrayy::contains()
499
   *
500
   * @param string|int|float $value
501
   *
502
   * @return bool
503
   */
504
  public function containsValue($value)
505
  {
506
    return $this->contains($value);
507
  }
508
509
  /**
510
   * Check if all given needles are present in the array.
511
   *
512
   * @param array $needles
513
   *
514
   * @return bool Returns true if the given values exists in the array, false otherwise
515
   */
516 1
  public function containsValues(array $needles)
517
  {
518 1
    return count(array_intersect($needles, $this->array)) === count($needles);
519
  }
520
521
  /**
522
   * Creates an Arrayy object.
523
   *
524
   * @param array $array
525
   *
526
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
527
   */
528 457
  public static function create($array = array())
529
  {
530 457
    return new static($array);
531
  }
532
533
  /**
534
   * WARNING: Creates an Arrayy object by reference.
535
   *
536
   * @param array $array
537
   *
538
   * @return self (Mutable) Return this Arrayy object.
539
   */
540
  public function createByReference(&$array = array())
541
  {
542
    $array = $this->fallbackForArray($array);
543
544
    $this->array = &$array;
545
546
    return $this;
547
  }
548
549
  /**
550
   * Create an new Arrayy object via JSON.
551
   *
552
   * @param string $json
553
   *
554
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
555
   */
556 5
  public static function createFromJson($json)
557
  {
558 5
    $array = UTF8::json_decode($json, true);
559
560 5
    return static::create($array);
561
  }
562
563
  /**
564
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
565
   *
566
   * @param \ArrayAccess $object Object that implements ArrayAccess
567
   *
568
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
569
   */
570 4
  public static function createFromObject(\ArrayAccess $object)
571
  {
572 4
    $array = new static();
573 4
    foreach ($object as $key => $value) {
574
      /** @noinspection OffsetOperationsInspection */
575 3
      $array[$key] = $value;
576 4
    }
577
578 4
    return $array;
579
  }
580
581
  /**
582
   * Create an new Arrayy object via string.
583
   *
584
   * @param string      $str       The input string.
585
   * @param string|null $delimiter The boundary string.
586
   * @param string|null $regEx     Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be used.
587
   *
588
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
589
   */
590 8
  public static function createFromString($str, $delimiter, $regEx = null)
591
  {
592 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...
593 1
      preg_match_all($regEx, $str, $array);
594
595 1
      if (!empty($array)) {
596 1
        $array = $array[0];
597 1
      }
598
599 1
    } else {
600 7
      $array = explode($delimiter, $str);
601
    }
602
603
    // trim all string in the array
604 8
    array_walk(
605 8
        $array,
606
        function (&$val) {
607
          /** @noinspection ReferenceMismatchInspection */
608 8
          if (is_string($val)) {
609 8
            $val = trim($val);
610 8
          }
611 8
        }
612 8
    );
613
614 8
    return static::create($array);
615
  }
616
617
  /**
618
   * Create an new instance containing a range of elements.
619
   *
620
   * @param mixed $low  First value of the sequence
621
   * @param mixed $high The sequence is ended upon reaching the end value
622
   * @param int   $step Used as the increment between elements in the sequence
623
   *
624
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
625
   */
626 1
  public static function createWithRange($low, $high, $step = 1)
627
  {
628 1
    return static::create(range($low, $high, $step));
629
  }
630
631
  /**
632
   * Custom sort by index via "uksort".
633
   *
634
   * @link http://php.net/manual/en/function.uksort.php
635
   *
636
   * @param callable $function
637
   *
638
   * @return self (Mutable) Return this Arrayy object.
639
   */
640 5
  public function customSortKeys($function)
641
  {
642 5
    uksort($this->array, $function);
643
644 5
    return $this;
645
  }
646
647
  /**
648
   * Custom sort by value via "usort".
649
   *
650
   * @link http://php.net/manual/en/function.usort.php
651
   *
652
   * @param callable $function
653
   *
654
   * @return self (Mutable) Return this Arrayy object.
655
   */
656 4
  public function customSortValues($function)
657
  {
658 4
    usort($this->array, $function);
659
660 4
    return $this;
661
  }
662
663
  /**
664
   * Return values that are only in the current array.
665
   *
666
   * @param array $array
667
   *
668
   * @return Arrayy (Immutable)
669
   */
670 12
  public function diff(array $array = array())
671
  {
672 12
    $result = array_diff($this->array, $array);
673
674 12
    return static::create($result);
675
  }
676
677
  /**
678
   * Return values that are only in the current multi-dimensional array.
679
   *
680
   * @param array      $array
681
   * @param null|array $helperVariableForRecursion (only for internal usage)
682
   *
683
   * @return Arrayy (Immutable)
684
   */
685 1
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
686
  {
687 1
    $result = array();
688
689
    if (
690
        $helperVariableForRecursion !== null
691 1
        &&
692 1
        is_array($helperVariableForRecursion)
693 1
    ) {
694 1
      $arrayForTheLoop = $helperVariableForRecursion;
695 1
    } else {
696 1
      $arrayForTheLoop = $this->array;
697
    }
698
699 1
    foreach ($arrayForTheLoop as $key => $value) {
700 1
      if (array_key_exists($key, $array)) {
701 1
        if (is_array($value)) {
702 1
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
703 1
          if (!empty($recursiveDiff)) {
704 1
            $result[$key] = $recursiveDiff;
705 1
          }
706 1
        } else {
707 1
          if ($value != $array[$key]) {
708 1
            $result[$key] = $value;
709 1
          }
710
        }
711 1
      } else {
712 1
        $result[$key] = $value;
713
      }
714 1
    }
715
716 1
    return static::create($result);
717
  }
718
719
  /**
720
   * Return values that are only in the new $array.
721
   *
722
   * @param array $array
723
   *
724
   * @return Arrayy (Immutable)
725
   */
726 8
  public function diffReverse(array $array = array())
727
  {
728 8
    $result = array_diff($array, $this->array);
729
730 8
    return static::create($result);
731
  }
732
733
  /**
734
   * Divide an array into two arrays. One with keys and the other with values.
735
   *
736
   * @return Arrayy (Immutable)
737
   */
738 1
  public function divide()
739
  {
740 1
    return static::create(
741
        array(
742 1
            $this->keys(),
743 1
            $this->values(),
744
        )
745 1
    );
746
  }
747
748
  /**
749
   * Iterate over the current array and modify the array's value.
750
   *
751
   * @param \Closure $closure
752
   *
753
   * @return Arrayy (Immutable)
754
   */
755 22 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...
756
  {
757 22
    $array = $this->array;
758
759 22
    foreach ($array as $key => &$value) {
760 18
      $value = $closure($value, $key);
761 22
    }
762
763 22
    return static::create($array);
764
  }
765
766
  /**
767
   * Check if a value is in the current array using a closure.
768
   *
769
   * @param \Closure $closure
770
   *
771
   * @return bool Returns true if the given value is found, false otherwise
772
   */
773 4
  public function exists(\Closure $closure)
774
  {
775 4
    $isExists = false;
776 4
    foreach ($this->array as $key => $value) {
777 3
      if ($closure($value, $key)) {
778 1
        $isExists = true;
779 1
        break;
780
      }
781 4
    }
782
783 4
    return $isExists;
784
  }
785
786
  /**
787
   * create a fallback for array
788
   *
789
   * 1. use the current array, if it's a array
790
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
791
   * 3. fallback to empty array, if there is nothing
792
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
793
   * 5. call "__toArray()" on object, if the method exists
794
   * 6. cast a string or object with "__toString()" into an array
795
   * 7. throw a "InvalidArgumentException"-Exception
796
   *
797
   * @param $array
798
   *
799
   * @return array
800
   *
801
   * @throws \InvalidArgumentException
802
   */
803 737
  protected function fallbackForArray(&$array)
804
  {
805 737
    if (is_array($array)) {
806 734
      return $array;
807
    }
808
809 10
    if ($array instanceof self) {
810 1
      return $array->getArray();
811
    }
812
813 9
    if (!$array) {
814 6
      return array();
815
    }
816
817 8
    if ($array instanceof \ArrayAccess) {
818
      /** @noinspection ReferenceMismatchInspection */
819
      return self::createFromObject($array)->getArray();
820
    }
821
822 8
    if (is_object($array) && method_exists($array, '__toArray')) {
823
      return (array)$array->__toArray();
824
    }
825
826
    /** @noinspection ReferenceMismatchInspection */
827
    if (
828 8
        is_string($array)
829
        ||
830 2
        (is_object($array) && method_exists($array, '__toString'))
831 8
    ) {
832 6
      return array((string)$array);
833
    }
834
835 2
    throw new \InvalidArgumentException(
836
        'Passed value should be a array'
837 2
    );
838
  }
839
840
  /**
841
   * Find all items in an array that pass the truth test.
842
   *
843
   * @param \Closure|null $closure
844
   *
845
   * @return Arrayy (Immutable)
846
   */
847 9
  public function filter($closure = null)
848
  {
849 9
    if (!$closure) {
850 1
      return $this->clean();
851
    }
852
853 9
    $array = array_filter($this->array, $closure);
854
855 9
    return static::create($array);
856
  }
857
858
  /**
859
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
860
   * within that.
861
   *
862
   * @param        $property
863
   * @param        $value
864
   * @param string $comparisonOp
865
   *                            'eq' (equals),<br />
866
   *                            'gt' (greater),<br />
867
   *                            'gte' || 'ge' (greater or equals),<br />
868
   *                            'lt' (less),<br />
869
   *                            'lte' || 'le' (less or equals),<br />
870
   *                            'ne' (not equals),<br />
871
   *                            'contains',<br />
872
   *                            'notContains',<br />
873
   *                            'newer' (via strtotime),<br />
874
   *                            'older' (via strtotime),<br />
875
   *
876
   * @return Arrayy (Immutable)
877
   */
878 1
  public function filterBy($property, $value, $comparisonOp = null)
879
  {
880 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...
881 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
882 1
    }
883
884
    $ops = array(
885
        'eq'          => function ($item, $prop, $value) {
886 1
          return $item[$prop] === $value;
887 1
        },
888
        'gt'          => function ($item, $prop, $value) {
889
          return $item[$prop] > $value;
890 1
        },
891
        'ge'          => function ($item, $prop, $value) {
892
          return $item[$prop] >= $value;
893 1
        },
894
        'gte'         => function ($item, $prop, $value) {
895
          return $item[$prop] >= $value;
896 1
        },
897
        'lt'          => function ($item, $prop, $value) {
898 1
          return $item[$prop] < $value;
899 1
        },
900
        'le'          => function ($item, $prop, $value) {
901
          return $item[$prop] <= $value;
902 1
        },
903
        'lte'         => function ($item, $prop, $value) {
904
          return $item[$prop] <= $value;
905 1
        },
906
        'ne'          => function ($item, $prop, $value) {
907
          return $item[$prop] !== $value;
908 1
        },
909
        'contains'    => function ($item, $prop, $value) {
910 1
          return in_array($item[$prop], (array)$value, true);
911 1
        },
912
        'notContains' => function ($item, $prop, $value) {
913
          return !in_array($item[$prop], (array)$value, true);
914 1
        },
915
        'newer'       => function ($item, $prop, $value) {
916
          return strtotime($item[$prop]) > strtotime($value);
917 1
        },
918
        'older'       => function ($item, $prop, $value) {
919
          return strtotime($item[$prop]) < strtotime($value);
920 1
        },
921 1
    );
922
923 1
    $result = array_values(
924 1
        array_filter(
925 1
            (array)$this->array,
926
            function ($item) use (
927 1
                $property,
928 1
                $value,
929 1
                $ops,
930 1
                $comparisonOp
931
            ) {
932 1
              $item = (array)$item;
933 1
              $itemArrayy = new Arrayy($item);
934 1
              $item[$property] = $itemArrayy->get($property, array());
935
936 1
              return $ops[$comparisonOp]($item, $property, $value);
937
            }
938 1
        )
939 1
    );
940
941 1
    return static::create($result);
942
  }
943
944
  /**
945
   * Find the first item in an array that passes the truth test,
946
   *  otherwise return false
947
   *
948
   * @param \Closure $closure
949
   *
950
   * @return mixed|false false if we did not find the value
951
   */
952 8
  public function find(\Closure $closure)
953
  {
954 8
    foreach ($this->array as $key => $value) {
955 6
      if ($closure($value, $key)) {
956 5
        return $value;
957
      }
958 5
    }
959
960 3
    return false;
961
  }
962
963
  /**
964
   * find by ...
965
   *
966
   * @param        $property
967
   * @param        $value
968
   * @param string $comparisonOp
969
   *
970
   * @return Arrayy (Immutable)
971
   */
972
  public function findBy($property, $value, $comparisonOp = 'eq')
973
  {
974
    return $this->filterBy($property, $value, $comparisonOp);
975
  }
976
977
  /**
978
   * Get the first value from the current array.
979
   *
980
   * @return mixed Return null if there wasn't a element.
981
   */
982 13
  public function first()
983
  {
984 13
    $tmpArray = $this->array;
985 13
    $result = array_shift($tmpArray);
986
987 13
    if ($result === null) {
988 3
      return null;
989
    } else {
990 10
      return $result;
991
    }
992
  }
993
994
  /**
995
   * Get the first value(s) from the current array.
996
   *
997
   * @param int|null $number how many values you will take?
998
   *
999
   * @return Arrayy (Immutable)
1000
   */
1001 28
  public function firstsImmutable($number = null)
1002
  {
1003 28
    if ($number === null) {
1004 7
      $arrayTmp = $this->array;
1005 7
      $array = (array)array_shift($arrayTmp);
1006 7
    } else {
1007 21
      $number = (int)$number;
1008 21
      $arrayTmp = $this->array;
1009 21
      $array = array_splice($arrayTmp, 0, $number, true);
1010
    }
1011
1012 28
    return static::create($array);
1013
  }
1014
1015
  /**
1016
   * Get the first value(s) from the current array.
1017
   *
1018
   * @param int|null $number how many values you will take?
1019
   *
1020
   * @return self (Mutable)
1021
   */
1022 26
  public function firstsMutable($number = null)
1023
  {
1024 26
    if ($number === null) {
1025 11
      $this->array = (array)array_shift($this->array);
1026 11
    } else {
1027 15
      $number = (int)$number;
1028 15
      $this->array = array_splice($this->array, 0, $number, true);
1029
    }
1030
1031 26
    return $this;
1032
  }
1033
1034
  /**
1035
   * Exchanges all keys with their associated values in an array.
1036
   *
1037
   * @return Arrayy (Immutable)
1038
   */
1039 1
  public function flip()
1040
  {
1041 1
    $result = array_flip($this->array);
1042
1043 1
    return static::create($result);
1044
  }
1045
1046
  /**
1047
   * Get a value from an array (optional using dot-notation).
1048
   *
1049
   * @param string $key      The key to look for.
1050
   * @param mixed  $fallback Value to fallback to.
1051
   * @param array  $array    The array to get from, if it's set to "null" we use the current array from the class.
1052
   *
1053
   * @return mixed
1054
   */
1055 58
  public function get($key, $fallback = null, $array = null)
1056
  {
1057
    if (
1058
        $array !== null
1059 58
        &&
1060 3
        is_array($array)
1061 58
    ) {
1062 3
      $usedArray = $array;
1063 3
    } else {
1064 56
      $usedArray = $this->array;
1065
    }
1066
1067 58
    if ($key === null) {
1068 1
      return self::create($usedArray);
1069
    }
1070
1071
    // php cast "bool"-index into "int"-index
1072 58
    if ((bool)$key === $key) {
1073 2
      $key = (int)$key;
1074 2
    }
1075
1076 58
    if (array_key_exists($key, $usedArray) === true) {
1077 48
      if (is_array($usedArray[$key])) {
1078 5
        return self::create($usedArray[$key]);
1079
      } else {
1080 45
        return $usedArray[$key];
1081
      }
1082
    }
1083
1084
    // Crawl through array, get key according to object or not
1085 19
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1086 19
      if (!isset($usedArray[$segment])) {
1087 19
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1088
      }
1089
1090 4
      $usedArray = $usedArray[$segment];
1091 4
    }
1092
1093 4
    if (is_array($usedArray)) {
1094
      return self::create($usedArray);
1095
    } else {
1096 4
      return $usedArray;
1097
    }
1098
  }
1099
1100
  /**
1101
   * Get the current array from the "Arrayy"-object.
1102
   *
1103
   * @return array
1104
   */
1105 487
  public function getArray()
1106
  {
1107 487
    array_map(array('self', 'internalGetArray'), $this->array);
1108
1109 487
    return $this->array;
1110
  }
1111
1112
  /**
1113
   * @param mixed $value
1114
   */
1115 403
  protected function internalGetArray(&$value)
1116
  {
1117 403
    if ($value instanceof self) {
1118
      $value &= $value->getArray();
1119
    }
1120 403
  }
1121
1122
  /**
1123
   * Returns the values from a single column of the input array, identified by
1124
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1125
   *
1126
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1127
   * array by the values from the $indexKey column in the input array.
1128
   *
1129
   * @param mixed $columnKey
1130
   * @param mixed $indexKey
1131
   *
1132
   * @return Arrayy (Immutable)
1133
   */
1134 1
  public function getColumn($columnKey = null, $indexKey = null)
1135
  {
1136 1
    $result = array_column($this->array, $columnKey, $indexKey);
1137
1138 1
    return static::create($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by array_column($this->array, $columnKey, $indexKey) on line 1136 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...
1139
  }
1140
1141
  /**
1142
   * Get correct PHP constant for direction.
1143
   *
1144
   * @param int|string $direction
1145
   *
1146
   * @return int
1147
   */
1148 38
  protected function getDirection($direction)
1149
  {
1150 38
    if (is_string($direction)) {
1151 10
      $direction = strtolower($direction);
1152
1153 10
      if ($direction === 'desc') {
1154 2
        $direction = SORT_DESC;
1155 2
      } else {
1156 8
        $direction = SORT_ASC;
1157
      }
1158 10
    }
1159
1160
    if (
1161
        $direction !== SORT_DESC
1162 38
        &&
1163
        $direction !== SORT_ASC
1164 38
    ) {
1165
      $direction = SORT_ASC;
1166
    }
1167
1168 38
    return $direction;
1169
  }
1170
1171
  /**
1172
   * alias: for "Arrayy->keys()"
1173
   *
1174
   * @see Arrayy::keys()
1175
   *
1176
   * @return Arrayy (Immutable)
1177
   */
1178 1
  public function getKeys()
1179
  {
1180 1
    return $this->keys();
1181
  }
1182
1183
  /**
1184
   * alias: for "Arrayy->randomImmutable()"
1185
   *
1186
   * @see Arrayy::randomImmutable()
1187
   *
1188
   * @return Arrayy (Immutable)
1189
   */
1190 3
  public function getRandom()
1191
  {
1192 3
    return $this->randomImmutable();
1193
  }
1194
1195
  /**
1196
   * alias: for "Arrayy->randomKey()"
1197
   *
1198
   * @see Arrayy::randomKey()
1199
   *
1200
   * @return mixed get a key/index or null if there wasn't a key/index
1201
   */
1202 3
  public function getRandomKey()
1203
  {
1204 3
    return $this->randomKey();
1205
  }
1206
1207
  /**
1208
   * alias: for "Arrayy->randomKeys()"
1209
   *
1210
   * @see Arrayy::randomKeys()
1211
   *
1212
   * @param int $number
1213
   *
1214
   * @return Arrayy (Immutable)
1215
   */
1216 9
  public function getRandomKeys($number)
1217
  {
1218 9
    return $this->randomKeys($number);
1219
  }
1220
1221
  /**
1222
   * alias: for "Arrayy->randomValue()"
1223
   *
1224
   * @see Arrayy::randomValue()
1225
   *
1226
   * @return mixed get a random value or null if there wasn't a value
1227
   */
1228 3
  public function getRandomValue()
1229
  {
1230 3
    return $this->randomValue();
1231
  }
1232
1233
  /**
1234
   * alias: for "Arrayy->randomValues()"
1235
   *
1236
   * @see Arrayy::randomValues()
1237
   *
1238
   * @param int $number
1239
   *
1240
   * @return Arrayy (Immutable)
1241
   */
1242 6
  public function getRandomValues($number)
1243
  {
1244 6
    return $this->randomValues($number);
1245
  }
1246
1247
  /**
1248
   * Group values from a array according to the results of a closure.
1249
   *
1250
   * @param string $grouper a callable function name
1251
   * @param bool   $saveKeys
1252
   *
1253
   * @return Arrayy (Immutable)
1254
   */
1255 3
  public function group($grouper, $saveKeys = false)
1256
  {
1257 3
    $array = (array)$this->array;
1258 3
    $result = array();
1259
1260
    // Iterate over values, group by property/results from closure
1261 3
    foreach ($array as $key => $value) {
1262
1263 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1264 3
      $newValue = $this->get($groupKey, null, $result);
1265
1266 3
      if ($groupKey instanceof self) {
1267
        $groupKey = $groupKey->getArray();
1268
      }
1269
1270 3
      if ($newValue instanceof self) {
1271 3
        $newValue = $newValue->getArray();
1272 3
      }
1273
1274
      // Add to results
1275 3
      if ($groupKey !== null) {
1276 2
        if ($saveKeys) {
1277 1
          $result[$groupKey] = $newValue;
1278 1
          $result[$groupKey][$key] = $value;
1279 1
        } else {
1280 1
          $result[$groupKey] = $newValue;
1281 1
          $result[$groupKey][] = $value;
1282
        }
1283 2
      }
1284
1285 3
    }
1286
1287 3
    return static::create($result);
1288
  }
1289
1290
  /**
1291
   * Check if an array has a given key.
1292
   *
1293
   * @param mixed $key
1294
   *
1295
   * @return bool
1296
   */
1297 22
  public function has($key)
1298
  {
1299
    // Generate unique string to use as marker.
1300 22
    $unFound = (string)uniqid('arrayy', true);
1301
1302 22
    return $this->get($key, $unFound) !== $unFound;
1303
  }
1304
1305
  /**
1306
   * Implodes an array.
1307
   *
1308
   * @param string $with What to implode it with
1309
   *
1310
   * @return string
1311
   */
1312 27
  public function implode($with = '')
1313
  {
1314 27
    return implode($with, $this->array);
1315
  }
1316
1317
  /**
1318
   * Given a list and an iterate-function that returns
1319
   * a key for each element in the list (or a property name),
1320
   * returns an object with an index of each item.
1321
   *
1322
   * Just like groupBy, but for when you know your keys are unique.
1323
   *
1324
   * @param mixed $key
1325
   *
1326
   * @return Arrayy (Immutable)
1327
   */
1328 3
  public function indexBy($key)
1329
  {
1330 3
    $results = array();
1331
1332 3
    foreach ($this->array as $a) {
1333 3
      if (array_key_exists($key, $a) === true) {
1334 2
        $results[$a[$key]] = $a;
1335 2
      }
1336 3
    }
1337
1338 3
    return static::create($results);
1339
  }
1340
1341
  /**
1342
   * alias: for "Arrayy->searchIndex()"
1343
   *
1344
   * @see Arrayy::searchIndex()
1345
   *
1346
   * @param mixed $value Value to search for
1347
   *
1348
   * @return mixed
1349
   */
1350 4
  public function indexOf($value)
1351
  {
1352 4
    return $this->searchIndex($value);
1353
  }
1354
1355
  /**
1356
   * Get everything but the last..$to items.
1357
   *
1358
   * @param int $to
1359
   *
1360
   * @return Arrayy (Immutable)
1361
   */
1362 12
  public function initial($to = 1)
1363
  {
1364 12
    $slice = count($this->array) - $to;
1365
1366 12
    return $this->firstsImmutable($slice);
1367
  }
1368
1369
  /**
1370
   * Internal mechanics of remove method.
1371
   *
1372
   * @param string $key
1373
   *
1374
   * @return boolean
1375
   */
1376 18
  protected function internalRemove($key)
1377
  {
1378 18
    $path = explode($this->pathSeparator, (string)$key);
1379
1380
    // Crawl though the keys
1381 18
    while (count($path) > 1) {
1382
      $key = array_shift($path);
1383
1384
      if (!$this->has($key)) {
1385
        return false;
1386
      }
1387
1388
      $this->array = &$this->array[$key];
1389
    }
1390
1391 18
    $key = array_shift($path);
1392
1393 18
    unset($this->array[$key]);
1394
1395 18
    return true;
1396
  }
1397
1398
  /**
1399
   * Internal mechanic of set method.
1400
   *
1401
   * @param string $key
1402
   * @param mixed  $value
1403
   *
1404
   * @return bool
1405
   */
1406 28
  protected function internalSet($key, $value)
1407
  {
1408 28
    if ($key === null) {
1409
      return false;
1410
    }
1411
1412
    // init
1413 28
    $array =& $this->array;
1414 28
    $path = explode($this->pathSeparator, (string)$key);
1415
1416
    // Crawl through the keys
1417 28
    while (count($path) > 1) {
1418 2
      $key = array_shift($path);
1419
1420
      // If the key doesn't exist at this depth, we will just create an empty array
1421
      // to hold the next value, allowing us to create the arrays to hold final
1422
      // values at the correct depth. Then we'll keep digging into the array.
1423 2
      if (!isset($array[$key]) || !is_array($array[$key])) {
1424
        $array[$key] = self::create(array());
1425
      }
1426
1427 2
      $array =& $array[$key];
1428 2
    }
1429
1430 28
    $array[array_shift($path)] = $value;
1431
1432 28
    return true;
1433
  }
1434
1435
  /**
1436
   * Return an array with all elements found in input array.
1437
   *
1438
   * @param array $search
1439
   *
1440
   * @return Arrayy (Immutable)
1441
   */
1442 2
  public function intersection(array $search)
1443
  {
1444 2
    return static::create(array_values(array_intersect($this->array, $search)));
1445
  }
1446
1447
  /**
1448
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1449
   *
1450
   * @param array $search
1451
   *
1452
   * @return bool
1453
   */
1454 1
  public function intersects(array $search)
1455
  {
1456 1
    return count($this->intersection($search)->array) > 0;
1457
  }
1458
1459
  /**
1460
   * Invoke a function on all of an array's values.
1461
   *
1462
   * @param mixed $callable
1463
   * @param mixed $arguments
1464
   *
1465
   * @return Arrayy (Immutable)
1466
   */
1467 1
  public function invoke($callable, $arguments = array())
1468
  {
1469
    // If one argument given for each iteration, create an array for it.
1470 1
    if (!is_array($arguments)) {
1471 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1472 1
    }
1473
1474
    // If the callable has arguments, pass them.
1475 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...
1476 1
      $array = array_map($callable, $this->array, $arguments);
1477 1
    } else {
1478 1
      $array = array_map($callable, $this->array);
1479
    }
1480
1481 1
    return static::create($array);
1482
  }
1483
1484
  /**
1485
   * Check whether array is associative or not.
1486
   *
1487
   * @return bool Returns true if associative, false otherwise
1488
   */
1489 15
  public function isAssoc()
1490
  {
1491 15
    if ($this->isEmpty()) {
1492 3
      return false;
1493
    }
1494
1495 13
    foreach ($this->keys()->getArray() as $key) {
1496 13
      if (!is_string($key)) {
1497 11
        return false;
1498
      }
1499 3
    }
1500
1501 3
    return true;
1502
  }
1503
1504
  /**
1505
   * Check whether the array is empty or not.
1506
   *
1507
   * @return bool Returns true if empty, false otherwise
1508
   */
1509 85
  public function isEmpty()
1510
  {
1511 85
    return !$this->array;
1512
  }
1513
1514
  /**
1515
   * Check if the current array is equal to the given "$array" or not.
1516
   *
1517
   * @param array $array
1518
   *
1519
   * @return bool
1520
   */
1521
  public function isEqual(array $array)
1522
  {
1523
    return ($this->array === $array);
1524
  }
1525
1526
  /**
1527
   * Check if the current array is a multi-array.
1528
   *
1529
   * @return bool
1530
   */
1531 14
  public function isMultiArray()
1532
  {
1533 14
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1534
  }
1535
1536
  /**
1537
   * Check whether array is numeric or not.
1538
   *
1539
   * @return bool Returns true if numeric, false otherwise
1540
   */
1541 5
  public function isNumeric()
1542
  {
1543 5
    if ($this->isEmpty()) {
1544 2
      return false;
1545
    }
1546
1547 4
    foreach ($this->keys() as $key) {
1548 4
      if (!is_int($key)) {
1549 2
        return false;
1550
      }
1551 3
    }
1552
1553 2
    return true;
1554
  }
1555
1556
  /**
1557
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1558
   *
1559
   * @return bool
1560
   */
1561 1
  public function isSequential()
1562
  {
1563 1
    return array_keys($this->array) === range(0, count($this->array) - 1);
1564
  }
1565
1566
  /**
1567
   * Get all keys from the current array.
1568
   *
1569
   * @return Arrayy (Immutable)
1570
   */
1571 25
  public function keys()
1572
  {
1573 25
    return static::create(array_keys($this->array));
1574
  }
1575
1576
  /**
1577
   * Get the last value from the current array.
1578
   *
1579
   * @return mixed Return null if there wasn't a element.
1580
   */
1581 4
  public function last()
1582
  {
1583 4
    return $this->pop();
1584
  }
1585
1586
  /**
1587
   * Get the last value(s) from the current array.
1588
   *
1589
   * @param int|null $number
1590
   *
1591
   * @return Arrayy (Immutable)
1592
   */
1593 13
  public function lastsImmutable($number = null)
1594
  {
1595 13
    if ($this->isEmpty()) {
1596 1
      return static::create();
1597
    }
1598
1599 12
    if ($number === null) {
1600 8
      $poppedValue = $this->pop();
1601
1602 8
      if ($poppedValue === null) {
1603 1
        $poppedValue = array($poppedValue);
1604 1
      } else {
1605 7
        $poppedValue = (array)$poppedValue;
1606
      }
1607
1608 8
      $arrayy = static::create($poppedValue);
1609 8
    } else {
1610 4
      $number = (int)$number;
1611 4
      $arrayy = $this->rest(-$number);
1612
    }
1613
1614 12
    return $arrayy;
1615
  }
1616
1617
  /**
1618
   * Get the last value(s) from the current array.
1619
   *
1620
   * @param int|null $number
1621
   *
1622
   * @return self (Mutable)
1623
   */
1624 13
  public function lastsMutable($number = null)
1625
  {
1626 13
    if ($this->isEmpty()) {
1627 1
      return $this;
1628
    }
1629
1630 12
    if ($number === null) {
1631 8
      $poppedValue = $this->pop();
1632
1633 8
      if ($poppedValue === null) {
1634 1
        $poppedValue = array($poppedValue);
1635 1
      } else {
1636 7
        $poppedValue = (array)$poppedValue;
1637
      }
1638
1639 8
      $this->array = static::create($poppedValue)->array;
1640 8
    } else {
1641 4
      $number = (int)$number;
1642 4
      $this->array = $this->rest(-$number)->array;
1643
    }
1644
1645 12
    return $this;
1646
  }
1647
1648
  /**
1649
   * Count the values from the current array.
1650
   *
1651
   * alias: for "Arrayy->size()"
1652
   *
1653
   * @see Arrayy::size()
1654
   *
1655
   * @return int
1656
   */
1657 10
  public function length()
1658
  {
1659 10
    return $this->size();
1660
  }
1661
1662
  /**
1663
   * Apply the given function to the every element of the array,
1664
   * collecting the results.
1665
   *
1666
   * @param callable $callable
1667
   *
1668
   * @return Arrayy (Immutable) Arrayy object with modified elements
1669
   */
1670 4
  public function map($callable)
1671
  {
1672 4
    $result = array_map($callable, $this->array);
1673
1674 4
    return static::create($result);
1675
  }
1676
1677
  /**
1678
   * Check if all items in current array match a truth test.
1679
   *
1680
   * @param \Closure $closure
1681
   *
1682
   * @return bool
1683
   */
1684 9 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...
1685
  {
1686
    // Reduce the array to only booleans
1687 9
    $array = $this->each($closure);
1688
1689
    // Check the results
1690 9
    if (count($array) === 0) {
1691 2
      return true;
1692
    }
1693
1694 7
    $array = array_search(false, $array->toArray(), false);
1695
1696 7
    return is_bool($array);
1697
  }
1698
1699
  /**
1700
   * Check if any item in the current array matches a truth test.
1701
   *
1702
   * @param \Closure $closure
1703
   *
1704
   * @return bool
1705
   */
1706 9 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...
1707
  {
1708
    // Reduce the array to only booleans
1709 9
    $array = $this->each($closure);
1710
1711
    // Check the results
1712 9
    if (count($array) === 0) {
1713 2
      return true;
1714
    }
1715
1716 7
    $array = array_search(true, $array->toArray(), false);
1717
1718 7
    return is_int($array);
1719
  }
1720
1721
  /**
1722
   * Get the max value from an array.
1723
   *
1724
   * @return mixed
1725
   */
1726 10
  public function max()
1727
  {
1728 10
    if ($this->count() === 0) {
1729 1
      return false;
1730
    }
1731
1732 9
    return max($this->array);
1733
  }
1734
1735
  /**
1736
   * Merge the new $array into the current array.
1737
   *
1738
   * - keep key,value from the current array, also if the index is in the new $array
1739
   *
1740
   * @param array $array
1741
   * @param bool  $recursive
1742
   *
1743
   * @return Arrayy (Immutable)
1744
   */
1745 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...
1746
  {
1747 25
    if (true === $recursive) {
1748 4
      $result = array_replace_recursive($this->array, $array);
1749 4
    } else {
1750 21
      $result = array_replace($this->array, $array);
1751
    }
1752
1753 25
    return static::create($result);
1754
  }
1755
1756
  /**
1757
   * Merge the new $array into the current array.
1758
   *
1759
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1760
   * - create new indexes
1761
   *
1762
   * @param array $array
1763
   * @param bool  $recursive
1764
   *
1765
   * @return Arrayy (Immutable)
1766
   */
1767 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...
1768
  {
1769 16
    if (true === $recursive) {
1770 4
      $result = array_merge_recursive($this->array, $array);
1771 4
    } else {
1772 12
      $result = array_merge($this->array, $array);
1773
    }
1774
1775 16
    return static::create($result);
1776
  }
1777
1778
  /**
1779
   * Merge the the current array into the $array.
1780
   *
1781
   * - use key,value from the new $array, also if the index is in the current array
1782
   *
1783
   * @param array $array
1784
   * @param bool  $recursive
1785
   *
1786
   * @return Arrayy (Immutable)
1787
   */
1788 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...
1789
  {
1790 16
    if (true === $recursive) {
1791 4
      $result = array_replace_recursive($array, $this->array);
1792 4
    } else {
1793 12
      $result = array_replace($array, $this->array);
1794
    }
1795
1796 16
    return static::create($result);
1797
  }
1798
1799
  /**
1800
   * Merge the current array into the new $array.
1801
   *
1802
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1803
   * - create new indexes
1804
   *
1805
   * @param array $array
1806
   * @param bool  $recursive
1807
   *
1808
   * @return Arrayy (Immutable)
1809
   */
1810 16 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...
1811
  {
1812 16
    if (true === $recursive) {
1813 4
      $result = array_merge_recursive($array, $this->array);
1814 4
    } else {
1815 12
      $result = array_merge($array, $this->array);
1816
    }
1817
1818 16
    return static::create($result);
1819
  }
1820
1821
  /**
1822
   * Get the min value from an array.
1823
   *
1824
   * @return mixed
1825
   */
1826 10
  public function min()
1827
  {
1828 10
    if ($this->count() === 0) {
1829 1
      return false;
1830
    }
1831
1832 9
    return min($this->array);
1833
  }
1834
1835
  /**
1836
   * Get a subset of the items from the given array.
1837
   *
1838
   * @param mixed[] $keys
1839
   *
1840
   * @return Arrayy (Immutable)
1841
   */
1842
  public function only(array $keys)
1843
  {
1844
    $array = $this->array;
1845
1846
    return static::create(array_intersect_key($array, array_flip($keys)));
1847
  }
1848
1849
  /**
1850
   * Pad array to the specified size with a given value.
1851
   *
1852
   * @param int   $size  Size of the result array
1853
   * @param mixed $value Empty value by default
1854
   *
1855
   * @return Arrayy (Immutable) Arrayy object padded to $size with $value
1856
   */
1857 4
  public function pad($size, $value)
1858
  {
1859 4
    $result = array_pad($this->array, $size, $value);
1860
1861 4
    return static::create($result);
1862
  }
1863
1864
  /**
1865
   * Pop a specified value off the end of the current array.
1866
   *
1867
   * @return mixed The popped element from the current array. (Mutable)
1868
   */
1869 16
  public function pop()
1870
  {
1871 16
    return array_pop($this->array);
1872
  }
1873
1874
  /**
1875
   * Prepend a value to the current array.
1876
   *
1877
   * @param mixed $value
1878
   * @param mixed $key
1879
   *
1880
   * @return self (Mutable) Return this Arrayy object, with the prepended value.
1881
   */
1882 8
  public function prepend($value, $key = null)
1883
  {
1884 8
    if ($key === null) {
1885 8
      array_unshift($this->array, $value);
1886 8
    } else {
1887
      /** @noinspection AdditionOperationOnArraysInspection */
1888 1
      $this->array = array($key => $value) + $this->array;
1889
    }
1890
1891 8
    return $this;
1892
  }
1893
1894
  /**
1895
   * Push one or more values onto the end of array at once.
1896
   *
1897
   * @return self (Mutable) Return this Arrayy object, with pushed elements to the end of array.
1898
   */
1899 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...
1900
  {
1901 4
    if (func_num_args()) {
1902 4
      $args = array_merge(array(&$this->array), func_get_args());
1903 4
      call_user_func_array('array_push', $args);
1904 4
    }
1905
1906 4
    return $this;
1907
  }
1908
1909
  /**
1910
   * Get a random value from the current array.
1911
   *
1912
   * @param null|int $number how many values you will take?
1913
   *
1914
   * @return Arrayy (Immutable)
1915
   */
1916 17
  public function randomImmutable($number = null)
1917
  {
1918 17
    if ($this->count() === 0) {
1919
      return static::create();
1920
    }
1921
1922 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...
1923 14
      $arrayRandValue = array($this->array[array_rand($this->array)]);
1924
1925 14
      return static::create($arrayRandValue);
1926
    }
1927
1928 5
    $arrayTmp = $this->array;
1929 5
    shuffle($arrayTmp);
1930
1931 5
    return self::create($arrayTmp)->firstsImmutable($number);
1932
  }
1933
1934
  /**
1935
   * Pick a random key/index from the keys of this array.
1936
   *
1937
   * @return mixed get a key/index or null if there wasn't a key/index
1938
   *
1939
   * @throws \RangeException If array is empty
1940
   */
1941 4
  public function randomKey()
1942
  {
1943 4
    $result = $this->randomKeys(1);
1944
1945 4
    if (!isset($result[0])) {
1946
      $result[0] = null;
1947
    }
1948
1949 4
    return $result[0];
1950
  }
1951
1952
  /**
1953
   * Pick a given number of random keys/indexes out of this array.
1954
   *
1955
   * @param int $number The number of keys/indexes (should be <= $this->count())
1956
   *
1957
   * @return Arrayy (Immutable)
1958
   *
1959
   * @throws \RangeException If array is empty
1960
   */
1961 14
  public function randomKeys($number)
1962
  {
1963 14
    $number = (int)$number;
1964 14
    $count = $this->count();
1965
1966 14
    if ($number === 0 || $number > $count) {
1967 3
      throw new \RangeException(
1968 3
          sprintf(
1969 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1970 3
              $number,
1971
              $count
1972 3
          )
1973 3
      );
1974
    }
1975
1976 11
    $result = (array)array_rand($this->array, $number);
1977
1978 11
    return static::create($result);
1979
  }
1980
1981
  /**
1982
   * Get a random value from the current array.
1983
   *
1984
   * @param null|int $number how many values you will take?
1985
   *
1986
   * @return Arrayy (Mutable)
1987
   */
1988 17
  public function randomMutable($number = null)
1989
  {
1990 17
    if ($this->count() === 0) {
1991
      return static::create();
1992
    }
1993
1994 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...
1995 7
      $arrayRandValue = array($this->array[array_rand($this->array)]);
1996 7
      $this->array = $arrayRandValue;
1997
1998 7
      return $this;
1999
    }
2000
2001 11
    shuffle($this->array);
2002
2003 11
    return $this->firstsMutable($number);
2004
  }
2005
2006
  /**
2007
   * Pick a random value from the values of this array.
2008
   *
2009
   * @return mixed get a random value or null if there wasn't a value
2010
   */
2011 4
  public function randomValue()
2012
  {
2013 4
    $result = $this->randomImmutable();
2014
2015 4
    if (!isset($result[0])) {
2016
      $result[0] = null;
2017
    }
2018
2019 4
    return $result[0];
2020
  }
2021
2022
  /**
2023
   * Pick a given number of random values out of this array.
2024
   *
2025
   * @param int $number
2026
   *
2027
   * @return Arrayy (Mutable)
2028
   */
2029 7
  public function randomValues($number)
2030
  {
2031 7
    $number = (int)$number;
2032
2033 7
    return $this->randomMutable($number);
2034
  }
2035
2036
  /**
2037
   * Get a random value from an array, with the ability to skew the results.
2038
   *
2039
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2040
   *
2041
   * @param array    $array
2042
   * @param null|int $number how many values you will take?
2043
   *
2044
   * @return Arrayy (Immutable)
2045
   */
2046 9
  public function randomWeighted(array $array, $number = null)
2047
  {
2048 9
    $options = array();
2049 9
    foreach ($array as $option => $weight) {
2050 9
      if ($this->searchIndex($option) !== false) {
2051 2
        for ($i = 0; $i < $weight; ++$i) {
2052 1
          $options[] = $option;
2053 1
        }
2054 2
      }
2055 9
    }
2056
2057 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2058
  }
2059
2060
  /**
2061
   * Reduce the current array via callable e.g. anonymous-function.
2062
   *
2063
   * @param mixed $callable
2064
   * @param array $init
2065
   *
2066
   * @return Arrayy (Immutable)
2067
   */
2068 3
  public function reduce($callable, array $init = array())
2069
  {
2070 3
    $result = array_reduce($this->array, $callable, $init);
2071
2072 3
    if ($result === null) {
2073
      $this->array = array();
2074
    } else {
2075 3
      $this->array = (array)$result;
2076
    }
2077
2078 3
    return static::create($this->array);
2079
  }
2080
2081
  /**
2082
   * Create a numerically re-indexed Arrayy object.
2083
   *
2084
   * @return self (Mutable) Return this Arrayy object, with re-indexed array-elements.
2085
   */
2086 9
  public function reindex()
2087
  {
2088 9
    $this->array = array_values($this->array);
2089
2090 9
    return $this;
2091
  }
2092
2093
  /**
2094
   * Return all items that fail the truth test.
2095
   *
2096
   * @param \Closure $closure
2097
   *
2098
   * @return Arrayy (Immutable)
2099
   */
2100 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...
2101
  {
2102 1
    $filtered = array();
2103
2104 1
    foreach ($this->array as $key => $value) {
2105 1
      if (!$closure($value, $key)) {
2106 1
        $filtered[$key] = $value;
2107 1
      }
2108 1
    }
2109
2110 1
    return static::create($filtered);
2111
  }
2112
2113
  /**
2114
   * Remove a value from the current array (optional using dot-notation).
2115
   *
2116
   * @param mixed $key
2117
   *
2118
   * @return Arrayy (Immutable)
2119
   */
2120 18
  public function remove($key)
2121
  {
2122
    // Recursive call
2123 18
    if (is_array($key)) {
2124
      foreach ($key as $k) {
2125
        $this->internalRemove($k);
2126
      }
2127
2128
      return static::create($this->array);
2129
    }
2130
2131 18
    $this->internalRemove($key);
2132
2133 18
    return static::create($this->array);
2134
  }
2135
2136
  /**
2137
   * Remove the first value from the current array.
2138
   *
2139
   * @return Arrayy (Immutable)
2140
   */
2141 7
  public function removeFirst()
2142
  {
2143 7
    $tmpArray = $this->array;
2144 7
    array_shift($tmpArray);
2145
2146 7
    return static::create($tmpArray);
2147
  }
2148
2149
  /**
2150
   * Remove the last value from the current array.
2151
   *
2152
   * @return Arrayy (Immutable)
2153
   */
2154 7
  public function removeLast()
2155
  {
2156 7
    $tmpArray = $this->array;
2157 7
    array_pop($tmpArray);
2158
2159 7
    return static::create($tmpArray);
2160
  }
2161
2162
  /**
2163
   * Removes a particular value from an array (numeric or associative).
2164
   *
2165
   * @param mixed $value
2166
   *
2167
   * @return Arrayy (Immutable)
2168
   */
2169 7
  public function removeValue($value)
2170
  {
2171 7
    $isNumericArray = true;
2172 7
    foreach ($this->array as $key => $item) {
2173 6
      if ($item === $value) {
2174 6
        if (!is_int($key)) {
2175
          $isNumericArray = false;
2176
        }
2177 6
        unset($this->array[$key]);
2178 6
      }
2179 7
    }
2180
2181 7
    if ($isNumericArray) {
2182 7
      $this->array = array_values($this->array);
2183 7
    }
2184
2185 7
    return static::create($this->array);
2186
  }
2187
2188
  /**
2189
   * Replace a key with a new key/value pair.
2190
   *
2191
   * @param $replace
2192
   * @param $key
2193
   * @param $value
2194
   *
2195
   * @return Arrayy (Immutable)
2196
   */
2197 2
  public function replace($replace, $key, $value)
2198
  {
2199 2
    $this->remove($replace);
2200
2201 2
    return $this->set($key, $value);
2202
  }
2203
2204
  /**
2205
   * Create an array using the current array as values and the other array as keys.
2206
   *
2207
   * @param array $keys Keys array
2208
   *
2209
   * @return Arrayy (Immutable) Arrayy object with keys from the other array.
2210
   */
2211 2
  public function replaceAllKeys(array $keys)
2212
  {
2213 2
    $result = array_combine($keys, $this->array);
2214
2215 2
    return static::create($result);
2216
  }
2217
2218
  /**
2219
   * Create an array using the current array as keys and the other array as values.
2220
   *
2221
   * @param array $array Values array
2222
   *
2223
   * @return Arrayy (Immutable) Arrayy object with values from the other array.
2224
   */
2225 2
  public function replaceAllValues(array $array)
2226
  {
2227 2
    $result = array_combine($this->array, $array);
2228
2229 2
    return static::create($result);
2230
  }
2231
2232
  /**
2233
   * Replace the keys in an array with another set.
2234
   *
2235
   * @param array $keys An array of keys matching the array's size
2236
   *
2237
   * @return Arrayy (Immutable)
2238
   */
2239 1
  public function replaceKeys(array $keys)
2240
  {
2241 1
    $values = array_values($this->array);
2242 1
    $result = array_combine($keys, $values);
2243
2244 1
    return static::create($result);
2245
  }
2246
2247
  /**
2248
   * Replace the first matched value in an array.
2249
   *
2250
   * @param mixed $search
2251
   * @param mixed $replacement
2252
   *
2253
   * @return Arrayy (Immutable)
2254
   */
2255 3
  public function replaceOneValue($search, $replacement = '')
2256
  {
2257 3
    $array = $this->array;
2258 3
    $key = array_search($search, $array, true);
2259
2260 3
    if ($key !== false) {
2261 3
      $array[$key] = $replacement;
2262 3
    }
2263
2264 3
    return static::create($array);
2265
  }
2266
2267
  /**
2268
   * Replace values in the current array.
2269
   *
2270
   * @param string $search      The string to replace.
2271
   * @param string $replacement What to replace it with.
2272
   *
2273
   * @return Arrayy (Immutable)
2274
   */
2275 1
  public function replaceValues($search, $replacement = '')
2276
  {
2277 1
    $array = $this->each(
2278
        function ($value) use ($search, $replacement) {
2279 1
          return UTF8::str_replace($search, $replacement, $value);
2280
        }
2281 1
    );
2282
2283 1
    return $array;
2284
  }
2285
2286
  /**
2287
   * Get the last elements from index $from until the end of this array.
2288
   *
2289
   * @param int $from
2290
   *
2291
   * @return Arrayy (Immutable)
2292
   */
2293 15
  public function rest($from = 1)
2294
  {
2295 15
    $tmpArray = $this->array;
2296
2297 15
    return static::create(array_splice($tmpArray, $from));
2298
  }
2299
2300
  /**
2301
   * Move an array element to a new index.
2302
   *
2303
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2304
   *
2305
   * @param int|string $from
2306
   * @param int|string $to
2307
   *
2308
   * @return Arrayy (Immutable)
2309
   */
2310 1
  public function moveElement($from, $to)
2311
  {
2312 1
    $array = $this->array;
2313
2314 1
    if (is_int($from)) {
2315 1
      $tmp = array_splice($array, $from, 1);
2316 1
      array_splice($array, $to, 0, $tmp);
2317 1
      $output = $array;
2318 1
    } elseif (is_string($from)) {
2319 1
      $indexToMove = array_search($from, array_keys($array), true);
2320 1
      $itemToMove = $array[$from];
2321 1
      array_splice($array, $indexToMove, 1);
2322 1
      $i = 0;
2323 1
      $output = array();
2324 1
      foreach($array as $key => $item) {
2325 1
        if ($i == $to) {
2326 1
          $output[$from] = $itemToMove;
2327 1
        }
2328 1
        $output[$key] = $item;
2329 1
        $i++;
2330 1
      }
2331 1
    } else {
2332
      $output = array();
2333
    }
2334
2335 1
    return static::create($output);
2336
  }
2337
2338
  /**
2339
   * Return the array in the reverse order.
2340
   *
2341
   * @return self (Mutable) Return this Arrayy object.
2342
   */
2343 7
  public function reverse()
2344
  {
2345 7
    $this->array = array_reverse($this->array);
2346
2347 7
    return $this;
2348
  }
2349
2350
  /**
2351
   * Search for the first index of the current array via $value.
2352
   *
2353
   * @param mixed $value
2354
   *
2355
   * @return int|float|string
2356
   */
2357 20
  public function searchIndex($value)
2358
  {
2359 20
    return array_search($value, $this->array, true);
2360
  }
2361
2362
  /**
2363
   * Search for the value of the current array via $index.
2364
   *
2365
   * @param mixed $index
2366
   *
2367
   * @return Arrayy (Immutable) will return a empty Arrayy if the value wasn't found
2368
   */
2369 9
  public function searchValue($index)
2370
  {
2371
    // init
2372 9
    $return = array();
2373
2374 9
    if ($this->isEmpty()) {
2375
      return static::create();
2376
    }
2377
2378
    // php cast "bool"-index into "int"-index
2379 9
    if ((bool)$index === $index) {
2380 1
      $index = (int)$index;
2381 1
    }
2382
2383 9
    if (array_key_exists($index, $this->array) === true) {
2384 7
      $return = array($this->array[$index]);
2385 7
    }
2386
2387
2388 9
    return static::create($return);
2389
  }
2390
2391
  /**
2392
   * Set a value for the current array (optional using dot-notation).
2393
   *
2394
   * @param string $key   The key to set
2395
   * @param mixed  $value Its value
2396
   *
2397
   * @return Arrayy (Immutable)
2398
   */
2399 17
  public function set($key, $value)
2400
  {
2401 17
    $this->internalSet($key, $value);
2402
2403 17
    return static::create($this->array);
2404
  }
2405
2406
  /**
2407
   * Get a value from a array and set it if it was not.
2408
   *
2409
   * WARNING: this method only set the value, if the $key is not already set
2410
   *
2411
   * @param string $key      The key
2412
   * @param mixed  $fallback The default value to set if it isn't
2413
   *
2414
   * @return mixed (Mutable)
2415
   */
2416 11
  public function setAndGet($key, $fallback = null)
2417
  {
2418
    // If the key doesn't exist, set it
2419 11
    if (!$this->has($key)) {
2420 4
      $this->array = $this->set($key, $fallback)->getArray();
2421 4
    }
2422
2423 11
    return $this->get($key);
2424
  }
2425
2426
  /**
2427
   * Shifts a specified value off the beginning of array.
2428
   *
2429
   * @return mixed A shifted element from the current array. (Mutable)
2430
   */
2431 4
  public function shift()
2432
  {
2433 4
    return array_shift($this->array);
2434
  }
2435
2436
  /**
2437
   * Shuffle the current array.
2438
   *
2439
   * @return Arrayy (Immutable)
2440
   */
2441 1
  public function shuffle()
2442
  {
2443 1
    $array = $this->array;
2444
2445 1
    shuffle($array);
2446
2447 1
    return static::create($array);
2448
  }
2449
2450
  /**
2451
   * Get the size of an array.
2452
   *
2453
   * @return int
2454
   */
2455 111
  public function size()
2456
  {
2457 111
    return count($this->array);
2458
  }
2459
2460
  /**
2461
   * Extract a slice of the array.
2462
   *
2463
   * @param int      $offset       Slice begin index
2464
   * @param int|null $length       Length of the slice
2465
   * @param bool     $preserveKeys Whether array keys are preserved or no
2466
   *
2467
   * @return static A slice of the original array with length $length
2468
   */
2469 4
  public function slice($offset, $length = null, $preserveKeys = false)
2470
  {
2471 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
2472
2473 4
    return static::create($result);
2474
  }
2475
2476
  /**
2477
   * Sort the current array and optional you can keep the keys.
2478
   *
2479
   * @param integer $direction use SORT_ASC or SORT_DESC
2480
   * @param integer $strategy
2481
   * @param bool    $keepKeys
2482
   *
2483
   * @return self (Mutable) Return this Arrayy object.
2484
   */
2485 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2486
  {
2487 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2488
2489 19
    return $this;
2490
  }
2491
2492
  /**
2493
   * Sort the current array by key.
2494
   *
2495
   * @link http://php.net/manual/en/function.ksort.php
2496
   * @link http://php.net/manual/en/function.krsort.php
2497
   *
2498
   * @param int|string $direction use SORT_ASC or SORT_DESC
2499
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2500
   *
2501
   * @return self (Mutable) Return this Arrayy object.
2502
   */
2503 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2504
  {
2505 18
    $this->sorterKeys($this->array, $direction, $strategy);
2506
2507 18
    return $this;
2508
  }
2509
2510
  /**
2511
   * Sort the current array by value.
2512
   *
2513
   * @param int $direction use SORT_ASC or SORT_DESC
2514
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2515
   *
2516
   * @return Arrayy (Immutable)
2517
   */
2518 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2519
  {
2520 1
    return $this->sort($direction, $strategy, true);
2521
  }
2522
2523
  /**
2524
   * Sort the current array by value.
2525
   *
2526
   * @param int $direction use SORT_ASC or SORT_DESC
2527
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2528
   *
2529
   * @return Arrayy (Immutable)
2530
   */
2531 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2532
  {
2533 1
    return $this->sort($direction, $strategy, false);
2534
  }
2535
2536
  /**
2537
   * Sort a array by value, by a closure or by a property.
2538
   *
2539
   * - If the sorter is null, the array is sorted naturally.
2540
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2541
   *
2542
   * @param null       $sorter
2543
   * @param string|int $direction
2544
   * @param int        $strategy
2545
   *
2546
   * @return Arrayy (Immutable)
2547
   */
2548 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2549
  {
2550 1
    $array = (array)$this->array;
2551 1
    $direction = $this->getDirection($direction);
2552
2553
    // Transform all values into their results.
2554 1
    if ($sorter) {
2555 1
      $arrayy = self::create($array);
2556
2557 1
      $that = $this;
2558 1
      $results = $arrayy->each(
2559
          function ($value) use ($sorter, $that) {
2560 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2561
          }
2562 1
      );
2563
2564 1
      $results = $results->getArray();
2565 1
    } else {
2566 1
      $results = $array;
2567
    }
2568
2569
    // Sort by the results and replace by original values
2570 1
    array_multisort($results, $direction, $strategy, $array);
2571
2572 1
    return static::create($array);
2573
  }
2574
2575
  /**
2576
   * sorting keys
2577
   *
2578
   * @param array $elements
2579
   * @param int   $direction
2580
   * @param int   $strategy
2581
   */
2582 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2583
  {
2584 18
    $direction = $this->getDirection($direction);
2585
2586
    switch ($direction) {
2587 18
      case 'desc':
2588 18
      case SORT_DESC:
2589 6
        krsort($elements, $strategy);
2590 6
        break;
2591 13
      case 'asc':
2592 13
      case SORT_ASC:
2593 13
      default:
2594 13
        ksort($elements, $strategy);
2595 13
    }
2596 18
  }
2597
2598
  /**
2599
   * @param array      &$elements
2600
   * @param int|string $direction
2601
   * @param int        $strategy
2602
   * @param bool       $keepKeys
2603
   */
2604 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2605
  {
2606 19
    $direction = $this->getDirection($direction);
2607
2608 19
    if (!$strategy) {
2609 19
      $strategy = SORT_REGULAR;
2610 19
    }
2611
2612
    switch ($direction) {
2613 19
      case 'desc':
2614 19
      case SORT_DESC:
2615 9
        if ($keepKeys) {
2616 5
          arsort($elements, $strategy);
2617 5
        } else {
2618 4
          rsort($elements, $strategy);
2619
        }
2620 9
        break;
2621 10
      case 'asc':
2622 10
      case SORT_ASC:
2623 10
      default:
2624 10
        if ($keepKeys) {
2625 4
          asort($elements, $strategy);
2626 4
        } else {
2627 6
          sort($elements, $strategy);
2628
        }
2629 10
    }
2630 19
  }
2631
2632
  /**
2633
   * Split an array in the given amount of pieces.
2634
   *
2635
   * @param int  $numberOfPieces
2636
   * @param bool $keepKeys
2637
   *
2638
   * @return Arrayy (Immutable)
2639
   */
2640 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2641
  {
2642 1
    $arrayCount = $this->count();
2643
2644 1
    if ($arrayCount === 0) {
2645 1
      $result = array();
2646 1
    } else {
2647 1
      $numberOfPieces = (int)$numberOfPieces;
2648 1
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
2649 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
2650
    }
2651
2652 1
    return static::create($result);
2653
  }
2654
2655
  /**
2656
   * Stripe all empty items.
2657
   *
2658
   * @return Arrayy (Immutable)
2659
   */
2660 1
  public function stripEmpty()
2661
  {
2662 1
    return $this->filter(
2663
        function ($item) {
2664 1
          if ($item === null) {
2665 1
            return false;
2666
          }
2667
2668 1
          return (bool)trim((string)$item);
2669
        }
2670 1
    );
2671
  }
2672
2673
  /**
2674
   * Swap two values between positions by key.
2675
   *
2676
   * @param string|int $swapA an key in the array
2677
   * @param string|int $swapB an key in the array
2678
   *
2679
   * @return Arrayy (Immutable)
2680
   */
2681 1
  public function swap($swapA, $swapB)
2682
  {
2683 1
    $array = $this->array;
2684
2685 1
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
2686
2687 1
    return static::create($array);
2688
  }
2689
2690
  /**
2691
   * alias: for "Arrayy->getArray()"
2692
   *
2693
   * @see Arrayy::getArray()
2694
   */
2695 155
  public function toArray()
2696
  {
2697 155
    return $this->getArray();
2698
  }
2699
2700
  /**
2701
   * Convert the current array to JSON.
2702
   *
2703
   * @param null $options e.g. JSON_PRETTY_PRINT
2704
   *
2705
   * @return string
2706
   */
2707 5
  public function toJson($options = null)
2708
  {
2709 5
    return UTF8::json_encode($this->array, $options);
2710
  }
2711
2712
  /**
2713
   * Implodes array to a string with specified separator.
2714
   *
2715
   * @param string $separator The element's separator
2716
   *
2717
   * @return string The string representation of array, separated by ","
2718
   */
2719 19
  public function toString($separator = ',')
2720
  {
2721 19
    return $this->implode($separator);
2722
  }
2723
2724
  /**
2725
   * Return a duplicate free copy of the current array.
2726
   *
2727
   * @return Arrayy (Mutable)
2728
   */
2729 8
  public function unique()
2730
  {
2731 8
    $this->array = array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce($this->arra...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...
2732 8
        $this->array,
2733 8
        function ($resultArray, $value) {
2734 7
          if (!in_array($value, $resultArray, true)) {
2735 7
            $resultArray[] = $value;
2736 7
          }
2737
2738 7
          return $resultArray;
2739 8
        },
2740 8
        array()
2741 8
    );
2742
2743 8
    if ($this->array === null) {
2744
      $this->array = array();
2745
    } else {
2746 8
      $this->array = (array)$this->array;
2747
    }
2748
2749 8
    return $this;
2750
  }
2751
2752
  /**
2753
   * Prepends one or more values to the beginning of array at once.
2754
   *
2755
   * @return self (Mutable) Return this Arrayy object, with prepended elements to the beginning of array.
2756
   */
2757 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...
2758
  {
2759 4
    if (func_num_args()) {
2760 4
      $args = array_merge(array(&$this->array), func_get_args());
2761 4
      call_user_func_array('array_unshift', $args);
2762 4
    }
2763
2764 4
    return $this;
2765
  }
2766
2767
  /**
2768
   * Get all values from a array.
2769
   *
2770
   * @return Arrayy (Immutable)
2771
   */
2772 2
  public function values()
2773
  {
2774 2
    return static::create(array_values((array)$this->array));
2775
  }
2776
2777
  /**
2778
   * Apply the given function to every element in the array, discarding the results.
2779
   *
2780
   * @param callable $callable
2781
   * @param bool     $recursive Whether array will be walked recursively or no
2782
   *
2783
   * @return self (Mutable) Return this Arrayy object, with modified elements
2784
   */
2785 9
  public function walk($callable, $recursive = false)
2786
  {
2787 9
    if (true === $recursive) {
2788 4
      array_walk_recursive($this->array, $callable);
2789 4
    } else {
2790 5
      array_walk($this->array, $callable);
2791
    }
2792
2793 9
    return $this;
2794
  }
2795
2796
}
2797