Completed
Push — master ( 3c31a4...f56e40 )
by Lars
02:22
created

Arrayy::get()   C

Complexity

Conditions 11
Paths 34

Size

Total Lines 44
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 11

Importance

Changes 0
Metric Value
cc 11
eloc 25
nc 34
nop 3
dl 0
loc 44
ccs 11
cts 11
cp 1
crap 11
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 728
  public function __construct($array = array())
34
  {
35 728
    $array = $this->fallbackForArray($array);
36
37 726
    $this->array = $array;
38 726
  }
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
  public function __get($key)
48
  {
49
    $return = $this->get($key);
50
51
    if (is_array($return)) {
52
      return self::create($return);
53
    }
54
55
    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
  public function __set($key, $value)
97
  {
98
    $this->internalSet($key, $value);
99
  }
100 16
101
  /**
102 16
   * magic to string
103
   *
104
   * @return string
105
   */
106
  public function __toString()
107
  {
108
    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 1
   * @see Arrayy::append()
125
   *
126 1
   * @param mixed $value
127
   *
128
   * @return self (Mutable) Return this Arrayy object, with the appended values.
129
   */
130
  public function add($value)
131
  {
132
    return $this->append($value);
133
  }
134
135
  /**
136 9
   * Append a value to the current array.
137
   *
138 9
   * @param mixed $value
139
   *
140 9
   * @return self (Mutable) Return this Arrayy object, with the appended values.
141
   */
142
  public function append($value)
143
  {
144
    $this->array[] = $value;
145
146
    return $this;
147
  }
148
149
  /**
150
   * Count the values from the current array.
151
   *
152 110
   * alias: for "Arrayy->size()"
153
   *
154 110
   * @see Arrayy::size()
155
   *
156
   * @return int
157
   */
158
  public function count()
159
  {
160
    return $this->size();
161
  }
162 19
163
  /**
164 19
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
165
   *
166
   * @return ArrayyIterator An iterator for the values in the array.
167
   */
168
  public function getIterator()
169
  {
170
    return new ArrayyIterator($this->array);
171
  }
172
173
  /**
174 37
   * Whether or not an offset exists.
175
   *
176 37
   * @param int|float|string $offset
177
   *
178
   * @return bool
179 37
   */
180
  public function offsetExists($offset)
181
  {
182 15
    if ($this->isEmpty()) {
183
      return false;
184 37
    }
185
186
    // php cast "bool"-index into "int"-index
187
    if ((bool)$offset === $offset) {
188 35
      $offset = (int)$offset;
189
    }
190
191
    $tmpReturn = array_key_exists($offset, $this->array);
192 2
193 2
    if (
194 2
        $tmpReturn === true
195 2
        ||
196
        (
197 2
            $tmpReturn === false
198
            &&
199
            strpos((string)$offset, $this->pathSeparator) === false
200 2
        )
201 2
    ) {
202
203
      return $tmpReturn;
204 2
205
    } else {
206
207
      $offsetExists = false;
208
209
      if (strpos((string)$offset, $this->pathSeparator) !== false) {
210
211
        $offsetExists = false;
212
        $explodedPath = explode($this->pathSeparator, (string)$offset);
213
        $lastOffset = array_pop($explodedPath);
214
        $containerPath = implode($this->pathSeparator, $explodedPath);
215 23
216
        $this->callAtPath(
217 23
            $containerPath,
218
            function ($container) use ($lastOffset, &$offsetExists) {
219
              $offsetExists = array_key_exists($lastOffset, $container);
220
            }
221
        );
222
      }
223
224
      return $offsetExists;
225
    }
226 14
  }
227
228 14
  /**
229 4
   * Returns the value at specified offset.
230
   *
231 10
   * @param mixed $offset
232
   *
233 14
   * @return mixed return null if the offset did not exists
234
   */
235
  public function offsetGet($offset)
236
  {
237
    return $this->offsetExists($offset) ? $this->get($offset) : null;
238
  }
239
240 6
  /**
241
   * Assigns a value to the specified offset.
242 6
   *
243 3
   * @param mixed $offset
244
   * @param mixed $value
245 3
   */
246
  public function offsetSet($offset, $value)
247
  {
248 3
    if ($offset === null) {
249 3
      $this->array[] = $value;
250
    } else {
251 3
      $this->internalSet($offset, $value);
252 3
    }
253
  }
254 1
255 3
  /**
256
   * Unset an offset.
257 3
   *
258
   * @param mixed $offset
259
   */
260
  public function offsetUnset($offset)
261
  {
262
    if ($this->isEmpty()) {
263
      return;
264 2
    }
265
266 2
    if (array_key_exists($offset, $this->array)) {
267
      unset($this->array[$offset]);
268
269
      return;
270
    }
271
272
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
273
274
      $path = explode($this->pathSeparator, (string)$offset);
275
      $pathToUnset = array_pop($path);
276 2
277
      $this->callAtPath(
278 2
          implode($this->pathSeparator, $path),
279
          function (&$offset) use (&$pathToUnset) {
280 2
            unset($offset[$pathToUnset]);
281
          }
282
      );
283
284
    }
285
  }
286
287
  /**
288
   * Serialize the current array.
289
   *
290 2
   * @return string
291
   */
292 2
  public function serialize()
293
  {
294 2
    return serialize($this->array);
295 2
  }
296
297
  /**
298 2
   * Unserialize an string and return this object.
299
   *
300
   * @param string $string
301
   *
302
   * @return self (Mutable)
303
   */
304
  public function unserialize($string)
305
  {
306
    $this->array = unserialize($string);
307
308 10
    return $this;
309
  }
310 10
311
  /**
312 10
   * Iterate over the current array and execute a callback for each loop.
313 2
   *
314
   * @param \Closure $closure
315
   *
316 8
   * @return Arrayy (Immutable)
317 3
   */
318 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 8
    $array = $this->array;
321
322
    foreach ($array as $key => $value) {
323
      $closure($value, $key);
324
    }
325
326
    return static::create($array);
327
  }
328 4
329
  /**
330 4
   * Returns the average value of the current array.
331 4
   *
332
   * @param int $decimals The number of decimals to return
333
   *
334 4
   * @return int|double The average value
335 4
   */
336
  public function average($decimals = 0)
337 4
  {
338 2
    $count = $this->count();
339
340
    if (!$count) {
341 2
      return 0;
342
    }
343
344
    if (!is_int($decimals)) {
345
      $decimals = 0;
346
    }
347
348 2
    return round(array_sum($this->array) / $count, $decimals);
349
  }
350 2
351
  /**
352
   * @param mixed      $path
353
   * @param callable   $callable
354
   * @param null|array $currentOffset
355
   */
356
  protected function callAtPath($path, $callable, &$currentOffset = null)
357
  {
358
    if ($currentOffset === null) {
359
      $currentOffset = &$this->array;
360
    }
361
362
    $explodedPath = explode($this->pathSeparator, $path);
363
    $nextPath = array_shift($explodedPath);
364
365
    if (!isset($currentOffset[$nextPath])) {
366
      return;
367
    }
368
369
    if (!empty($explodedPath)) {
370
      $this->callAtPath(
371
          implode($this->pathSeparator, $explodedPath),
372
          $callable,
373
          $currentOffset[$nextPath]
374
      );
375
    } else {
376 4
      $callable($currentOffset[$nextPath]);
377
    }
378 4
  }
379
380 4
  /**
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 8
   */
389
  public function changeSeparator($separator)
390 8
  {
391
    $this->pathSeparator = $separator;
392 7
393 8
    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 4
   * @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
    return static::create($result);
409
  }
410
411
  /**
412
   * Clean all falsy values from the current array.
413
   *
414
   * @return Arrayy (Immutable)
415
   */
416 13
  public function clean()
417
  {
418 13
    return $this->filter(
419
        function ($value) {
420
          return (bool)$value;
421
        }
422
    );
423
  }
424
425
  /**
426
   * WARNING!!! -> Clear the current array.
427
   *
428 13
   * @return self (Mutable) Return this Arrayy object, with an empty array.
429
   */
430 13
  public function clear()
431 13
  {
432
    $this->array = array();
433
434 13
    return $this;
435 13
  }
436
437 13
  /**
438
   * Check if an item is in the current array.
439 13
   *
440
   * @param string|int|float $value
441
   *
442
   * @return bool
443
   */
444
  public function contains($value)
445
  {
446
    return in_array($value, $this->array, true);
447
  }
448
449
  /**
450 4
   * Check if an (case-insensitive) string is in the current array.
451
   *
452 4
   * @param string $value
453
   *
454
   * @return bool
455
   */
456
  public function containsCaseInsensitive($value)
457
  {
458
    return in_array(
459
        UTF8::strtolower($value),
460
        array_map(
461
            array(
462 1
                new UTF8(),
463
                'strtolower',
464 1
            ),
465
            $this->array
466
        ),
467
        true
468
    );
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
  public function containsKey($key)
479
  {
480
    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 1
   * @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
    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 452
   * @param string|int|float $value
501
   *
502 452
   * @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
  public function containsValues(array $needles)
517
  {
518
    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 5
  public static function create($array = array())
529
  {
530 5
    return new static($array);
531
  }
532 5
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 4
    $array = $this->fallbackForArray($array);
543
544 4
    $this->array = &$array;
545 4
546
    return $this;
547 3
  }
548
549
  /**
550 4
   * 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
  public static function createFromJson($json)
557
  {
558
    $array = UTF8::json_decode($json, true);
559
560
    return static::create($array);
561
  }
562 8
563
  /**
564 8
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
565 1
   *
566
   * @param \ArrayAccess $object Object that implements ArrayAccess
567 1
   *
568 1
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
569
   */
570
  public static function createFromObject(\ArrayAccess $object)
571
  {
572 7
    $array = new static();
573
    foreach ($object as $key => $value) {
574
      /** @noinspection OffsetOperationsInspection */
575
      $array[$key] = $value;
576 8
    }
577
578
    return $array;
579
  }
580 8
581 8
  /**
582
   * Create an new Arrayy object via string.
583 8
   *
584
   * @param string      $str       The input string.
585
   * @param string|null $delimiter The boundary string.
586 8
   * @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
  public static function createFromString($str, $delimiter, $regEx = null)
591
  {
592
    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
      preg_match_all($regEx, $str, $array);
594
595
      if (!empty($array)) {
596
        $array = $array[0];
597
      }
598 1
599
    } else {
600 1
      $array = explode($delimiter, $str);
601
    }
602
603
    // trim all string in the array
604
    array_walk(
605
        $array,
606
        function (&$val) {
607
          /** @noinspection ReferenceMismatchInspection */
608
          if (is_string($val)) {
609
            $val = trim($val);
610
          }
611
        }
612 5
    );
613
614 5
    return static::create($array);
615
  }
616 5
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
  public static function createWithRange($low, $high, $step = 1)
627
  {
628 4
    return static::create(range($low, $high, $step));
629
  }
630 4
631
  /**
632 4
   * 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
  public function customSortKeys($function)
641
  {
642 12
    uksort($this->array, $function);
643
644 12
    return $this;
645
  }
646 12
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
  public function customSortValues($function)
657 1
  {
658
    usort($this->array, $function);
659 1
660
    return $this;
661 1
  }
662 1
663
  /**
664 1
   * Return values that are only in the current array.
665
   *
666
   * @param array $array
667 1
   *
668 1
   * @return Arrayy (Immutable)
669 1
   */
670 1
  public function diff(array $array = array())
671 1
  {
672 1
    $result = array_diff($this->array, $array);
673
674
    return static::create($result);
675 1
  }
676 1
677
  /**
678
   * Return values that are only in the current multi-dimensional array.
679
   *
680 1
   * @param array      $array
681
   * @param null|array $helperVariableForRecursion (only for internal usage)
682
   *
683
   * @return Arrayy (Immutable)
684 1
   */
685
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
686
  {
687
    $result = array();
688
689
    if (
690
        $helperVariableForRecursion !== null
691
        &&
692
        is_array($helperVariableForRecursion)
693
    ) {
694 8
      $arrayForTheLoop = $helperVariableForRecursion;
695
    } else {
696 8
      $arrayForTheLoop = $this->array;
697
    }
698 8
699
    foreach ($arrayForTheLoop as $key => $value) {
700
      if (array_key_exists($key, $array)) {
701
        if (is_array($value)) {
702
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
703
          if (!empty($recursiveDiff)) {
704
            $result[$key] = $recursiveDiff;
705
          }
706 1
        } else {
707
          if ($value != $array[$key]) {
708 1
            $result[$key] = $value;
709
          }
710 1
        }
711 1
      } else {
712
        $result[$key] = $value;
713
      }
714
    }
715
716
    return static::create($result);
717
  }
718
719
  /**
720
   * Return values that are only in the new $array.
721
   *
722
   * @param array $array
723 22
   *
724
   * @return Arrayy (Immutable)
725 22
   */
726
  public function diffReverse(array $array = array())
727 22
  {
728 18
    $result = array_diff($array, $this->array);
729
730
    return static::create($result);
731 22
  }
732
733
  /**
734
   * Divide an array into two arrays. One with keys and the other with values.
735
   *
736
   * @return Arrayy (Immutable)
737
   */
738
  public function divide()
739
  {
740
    return static::create(
741 4
        array(
742
            $this->keys(),
743 4
            $this->values(),
744 4
        )
745 3
    );
746 1
  }
747 3
748
  /**
749
   * Iterate over the current array and modify the array's value.
750
   *
751 4
   * @param \Closure $closure
752
   *
753
   * @return Arrayy (Immutable)
754
   */
755 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
    $array = $this->array;
758
759
    foreach ($array as $key => &$value) {
760
      $value = $closure($value, $key);
761
    }
762
763
    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 728
   * @return bool Returns true if the given value is found, false otherwise
772
   */
773 728
  public function exists(\Closure $closure)
774 725
  {
775
    $isExists = false;
776
    foreach ($this->array as $key => $value) {
777 9
      if ($closure($value, $key)) {
778
        $isExists = true;
779
        break;
780
      }
781 9
    }
782 6
783
    return $isExists;
784
  }
785 8
786
  /**
787
   * create a fallback for array
788
   *
789
   * 1. use the current array, if it's a array
790 8
   * 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 8
   *
797
   * @param $array
798 8
   *
799
   * @return array
800 6
   *
801
   * @throws \InvalidArgumentException
802
   */
803 2
  protected function fallbackForArray(&$array)
804 2
  {
805
    if (is_array($array)) {
806
      return $array;
807
    }
808
809
    if ($array instanceof self) {
810
      return $array->getArray();
811
    }
812
813
    if (!$array) {
814
      return array();
815 9
    }
816
817 9
    if ($array instanceof \ArrayAccess) {
818 1
      /** @noinspection ReferenceMismatchInspection */
819
      return self::createFromObject($array)->getArray();
820
    }
821 9
822
    if (is_object($array) && method_exists($array, '__toArray')) {
823 9
      return (array)$array->__toArray();
824
    }
825
826
    /** @noinspection ReferenceMismatchInspection */
827
    if (
828
        is_string($array)
829
        ||
830
        (is_object($array) && method_exists($array, '__toString'))
831
    ) {
832
      return array((string)$array);
833
    }
834
835
    throw new \InvalidArgumentException(
836
        'Passed value should be a array'
837
    );
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 1
   */
847
  public function filter($closure = null)
848 1
  {
849 1
    if (!$closure) {
850
      return $this->clean();
851
    }
852
853
    $array = array_filter($this->array, $closure);
854 1
855 1
    return static::create($array);
856
  }
857
858 1
  /**
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 1
   *
862
   * @param        $property
863
   * @param        $value
864 1
   * @param string $comparisonOp
865
   *                            'eq' (equals),<br />
866 1
   *                            'gt' (greater),<br />
867 1
   *                            'gte' || 'ge' (greater or equals),<br />
868
   *                            'lt' (less),<br />
869
   *                            'lte' || 'le' (less or equals),<br />
870 1
   *                            'ne' (not equals),<br />
871
   *                            'contains',<br />
872
   *                            'notContains',<br />
873 1
   *                            'newer' (via strtotime),<br />
874
   *                            'older' (via strtotime),<br />
875
   *
876 1
   * @return Arrayy (Immutable)
877
   */
878 1
  public function filterBy($property, $value, $comparisonOp = null)
879 1
  {
880
    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
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
882 1
    }
883
884
    $ops = array(
885 1
        'eq'          => function ($item, $prop, $value) {
886
          return $item[$prop] === $value;
887
        },
888 1
        'gt'          => function ($item, $prop, $value) {
889
          return $item[$prop] > $value;
890
        },
891 1
        'ge'          => function ($item, $prop, $value) {
892
          return $item[$prop] >= $value;
893 1
        },
894
        'gte'         => function ($item, $prop, $value) {
895 1
          return $item[$prop] >= $value;
896 1
        },
897 1
        'lt'          => function ($item, $prop, $value) {
898 1
          return $item[$prop] < $value;
899
        },
900 1
        'le'          => function ($item, $prop, $value) {
901 1
          return $item[$prop] <= $value;
902 1
        },
903
        'lte'         => function ($item, $prop, $value) {
904 1
          return $item[$prop] <= $value;
905 1
        },
906
        'ne'          => function ($item, $prop, $value) {
907
          return $item[$prop] !== $value;
908
        },
909 1
        'contains'    => function ($item, $prop, $value) {
910
          return in_array($item[$prop], (array)$value, true);
911
        },
912
        'notContains' => function ($item, $prop, $value) {
913
          return !in_array($item[$prop], (array)$value, true);
914
        },
915
        'newer'       => function ($item, $prop, $value) {
916
          return strtotime($item[$prop]) > strtotime($value);
917
        },
918
        'older'       => function ($item, $prop, $value) {
919
          return strtotime($item[$prop]) < strtotime($value);
920 8
        },
921
    );
922 8
923 6
    $result = array_values(
924 6
        array_filter(
925
            (array)$this->array,
926
            function ($item) use (
927
                $property,
928 3
                $value,
929
                $ops,
930
                $comparisonOp
931
            ) {
932
              $item = (array)$item;
933
              $itemArrayy = new Arrayy($item);
934
              $item[$property] = $itemArrayy->get($property, array());
935
936
              return $ops[$comparisonOp]($item, $property, $value);
937
            }
938
        )
939
    );
940
941
    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 13
   * @return mixed|false false if we did not find the value
951
   */
952 13
  public function find(\Closure $closure)
953 13
  {
954
    foreach ($this->array as $key => $value) {
955 13
      if ($closure($value, $key)) {
956 3
        return $value;
957
      }
958 10
    }
959
960
    return false;
961
  }
962
963
  /**
964
   * find by ...
965
   *
966
   * @param        $property
967
   * @param        $value
968
   * @param string $comparisonOp
969 28
   *
970
   * @return Arrayy (Immutable)
971 28
   */
972 7
  public function findBy($property, $value, $comparisonOp = 'eq')
973 7
  {
974
    return $this->filterBy($property, $value, $comparisonOp);
975 21
  }
976 21
977 21
  /**
978
   * Get the first value from the current array.
979
   *
980 28
   * @return mixed Return null if there wasn't a element.
981
   */
982
  public function first()
983
  {
984
    $tmpArray = $this->array;
985
    $result = array_shift($tmpArray);
986
987
    if ($result === null) {
988
      return null;
989
    } else {
990 26
      return $result;
991
    }
992 26
  }
993 11
994
  /**
995 15
   * Get the first value(s) from the current array.
996 15
   *
997
   * @param int|null $number how many values you will take?
998
   *
999 26
   * @return Arrayy (Immutable)
1000
   */
1001
  public function firstsImmutable($number = null)
1002
  {
1003
    if ($number === null) {
1004
      $arrayTmp = $this->array;
1005
      $array = (array)array_shift($arrayTmp);
1006
    } else {
1007 1
      $number = (int)$number;
1008
      $arrayTmp = $this->array;
1009 1
      $array = array_splice($arrayTmp, 0, $number, true);
1010
    }
1011 1
1012
    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
  public function firstsMutable($number = null)
1023 54
  {
1024
    if ($number === null) {
1025 54
      $this->array = (array)array_shift($this->array);
1026 3
    } else {
1027
      $number = (int)$number;
1028 52
      $this->array = array_splice($this->array, 0, $number, true);
1029
    }
1030
1031 54
    return $this;
1032 1
  }
1033
1034
  /**
1035 54
   * Exchanges all keys with their associated values in an array.
1036 42
   *
1037
   * @return Arrayy (Immutable)
1038
   */
1039
  public function flip()
1040 20
  {
1041 20
    $result = array_flip($this->array);
1042 17
1043
    return static::create($result);
1044
  }
1045 3
1046
  /**
1047
   * Get a value from an array (optional using dot-notation).
1048 3
   *
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
  public function get($key, $fallback = null, $array = null)
1056 481
  {
1057
    if (
1058 481
        $array !== null
1059
        &&
1060
        is_array($array)
1061
    ) {
1062
      $usedArray = $array;
1063
    } else {
1064
      $usedArray = $this->array;
1065
    }
1066
1067
    if ($key === null) {
1068
      return self::create($usedArray);
1069
    }
1070
1071
    // php cast "bool"-index into "int"-index
1072
    if ((bool)$key === $key) {
1073 1
      $key = (int)$key;
1074
    }
1075 1
1076
    if (array_key_exists($key, $usedArray) === true) {
1077 1
      if (is_array($usedArray[$key])) {
1078
        return self::create($usedArray[$key]);
1079
      } else {
1080
        return $usedArray[$key];
1081
      }
1082
    }
1083
1084
    // Crawl through array, get key according to object or not
1085
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1086
      if (!isset($usedArray[$segment])) {
1087 38
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1088
      }
1089 38
1090 10
      $usedArray = $usedArray[$segment];
1091
    }
1092 10
1093 2
    if (is_array($usedArray)) {
1094
      return self::create($usedArray);
1095 8
    } else {
1096
      return $usedArray;
1097
    }
1098
  }
1099
1100 38
  /**
1101
   * Get the current array from the "Arrayy"-object.
1102 38
   *
1103
   * @return array
1104
   */
1105
  public function getArray()
1106
  {
1107 38
    array_map(array('self', 'internalGetArray'), $this->array);
1108
1109
    return $this->array;
1110
  }
1111
1112
  /**
1113
   * @param mixed $value
1114
   */
1115
  protected function internalGetArray(&$value)
1116
  {
1117 1
    if ($value instanceof self) {
1118
      $value &= $value->getArray();
1119 1
    }
1120
  }
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 3
   * @param mixed $columnKey
1130
   * @param mixed $indexKey
1131 3
   *
1132
   * @return Arrayy (Immutable)
1133
   */
1134
  public function getColumn($columnKey = null, $indexKey = null)
1135
  {
1136
    $result = array_column($this->array, $columnKey, $indexKey);
1137
1138
    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 3
  /**
1142
   * Get correct PHP constant for direction.
1143 3
   *
1144
   * @param int|string $direction
1145
   *
1146
   * @return int
1147
   */
1148
  protected function getDirection($direction)
1149
  {
1150
    if (is_string($direction)) {
1151
      $direction = strtolower($direction);
1152
1153
      if ($direction === 'desc') {
1154
        $direction = SORT_DESC;
1155 9
      } else {
1156
        $direction = SORT_ASC;
1157 9
      }
1158
    }
1159
1160
    if (
1161
        $direction !== SORT_DESC
1162
        &&
1163
        $direction !== SORT_ASC
1164
    ) {
1165
      $direction = SORT_ASC;
1166
    }
1167 3
1168
    return $direction;
1169 3
  }
1170
1171
  /**
1172
   * alias: for "Arrayy->keys()"
1173
   *
1174
   * @see Arrayy::keys()
1175
   *
1176
   * @return Arrayy (Immutable)
1177
   */
1178
  public function getKeys()
1179
  {
1180
    return $this->keys();
1181 6
  }
1182
1183 6
  /**
1184
   * alias: for "Arrayy->randomImmutable()"
1185
   *
1186
   * @see Arrayy::randomImmutable()
1187
   *
1188
   * @return Arrayy (Immutable)
1189
   */
1190
  public function getRandom()
1191
  {
1192
    return $this->randomImmutable();
1193
  }
1194 3
1195
  /**
1196 3
   * alias: for "Arrayy->randomKey()"
1197 3
   *
1198
   * @see Arrayy::randomKey()
1199
   *
1200 3
   * @return mixed get a key/index or null if there wasn't a key/index
1201 3
   */
1202 3
  public function getRandomKey()
1203
  {
1204
    return $this->randomKey();
1205 3
  }
1206 2
1207 1
  /**
1208 1
   * alias: for "Arrayy->randomKeys()"
1209
   *
1210 1
   * @see Arrayy::randomKeys()
1211 3
   *
1212
   * @param int $number
1213
   *
1214
   * @return Arrayy (Immutable)
1215
   */
1216
  public function getRandomKeys($number)
1217 3
  {
1218
    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 19
   */
1228
  public function getRandomValue()
1229
  {
1230 19
    return $this->randomValue();
1231
  }
1232 19
1233
  /**
1234
   * alias: for "Arrayy->randomValues()"
1235
   *
1236
   * @see Arrayy::randomValues()
1237
   *
1238
   * @param int $number
1239
   *
1240
   * @return Arrayy (Immutable)
1241
   */
1242 27
  public function getRandomValues($number)
1243
  {
1244 27
    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
  public function group($grouper, $saveKeys = false)
1256
  {
1257
    $array = (array)$this->array;
1258 3
    $result = array();
1259
1260 3
    // Iterate over values, group by property/results from closure
1261
    foreach ($array as $key => $value) {
1262 3
1263 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1264 3
      $newValue = $this->get($groupKey, null, $result);
1265
1266
      if ($groupKey instanceof self) {
1267
        $groupKey = $groupKey->getArray();
1268 3
      }
1269
1270
      if ($newValue instanceof self) {
1271
        $newValue = $newValue->getArray();
1272
      }
1273
1274
      // Add to results
1275
      if ($groupKey !== null) {
1276
        if ($saveKeys) {
1277
          $result[$groupKey] = $newValue;
1278
          $result[$groupKey][$key] = $value;
1279
        } else {
1280 4
          $result[$groupKey] = $newValue;
1281
          $result[$groupKey][] = $value;
1282 4
        }
1283
      }
1284
1285
    }
1286
1287
    return static::create($result);
1288
  }
1289
1290
  /**
1291
   * Check if an array has a given key.
1292 12
   *
1293
   * @param mixed $key
1294 12
   *
1295
   * @return bool
1296 12
   */
1297
  public function has($key)
1298
  {
1299
    // Generate unique string to use as marker.
1300
    $unFound = (string)uniqid('arrayy', true);
1301
1302
    return $this->get($key, $unFound) !== $unFound;
1303
  }
1304
1305
  /**
1306 18
   * Implodes an array.
1307
   *
1308 18
   * @param string $with What to implode it with
1309
   *
1310
   * @return string
1311 18
   */
1312
  public function implode($with = '')
1313
  {
1314
    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 18
   *
1322
   * Just like groupBy, but for when you know your keys are unique.
1323 18
   *
1324
   * @param mixed $key
1325 18
   *
1326
   * @return Arrayy (Immutable)
1327
   */
1328
  public function indexBy($key)
1329
  {
1330
    $results = array();
1331
1332
    foreach ($this->array as $a) {
1333
      if (array_key_exists($key, $a) === true) {
1334
        $results[$a[$key]] = $a;
1335
      }
1336 27
    }
1337
1338 27
    return static::create($results);
1339
  }
1340
1341
  /**
1342
   * alias: for "Arrayy->searchIndex()"
1343 27
   *
1344 27
   * @see Arrayy::searchIndex()
1345
   *
1346
   * @param mixed $value Value to search for
1347 27
   *
1348 2
   * @return mixed
1349
   */
1350
  public function indexOf($value)
1351
  {
1352 2
    return $this->searchIndex($value);
1353
  }
1354
1355 2
  /**
1356
   * Get everything but the last..$to items.
1357
   *
1358 27
   * @param int $to
1359
   *
1360 27
   * @return Arrayy (Immutable)
1361
   */
1362
  public function initial($to = 1)
1363
  {
1364
    $slice = count($this->array) - $to;
1365
1366
    return $this->firstsImmutable($slice);
1367
  }
1368
1369
  /**
1370 2
   * Internal mechanics of remove method.
1371
   *
1372 2
   * @param string $key
1373
   *
1374
   * @return boolean
1375
   */
1376
  protected function internalRemove($key)
1377
  {
1378
    $path = explode($this->pathSeparator, (string)$key);
1379
1380
    // Crawl though the keys
1381
    while (count($path) > 1) {
1382 1
      $key = array_shift($path);
1383
1384 1
      if (!$this->has($key)) {
1385
        return false;
1386
      }
1387
1388
      $this->array = &$this->array[$key];
1389
    }
1390
1391
    $key = array_shift($path);
1392
1393
    unset($this->array[$key]);
1394
1395 1
    return true;
1396
  }
1397
1398 1
  /**
1399 1
   * Internal mechanic of set method.
1400
   *
1401
   * @param string $key
1402
   * @param mixed  $value
1403 1
   *
1404 1
   * @return bool
1405
   */
1406 1
  protected function internalSet($key, $value)
1407
  {
1408
    if ($key === null) {
1409 1
      return false;
1410
    }
1411
1412
    // init
1413
    $array =& $this->array;
1414
    $path = explode($this->pathSeparator, (string)$key);
1415
1416
    // Crawl through the keys
1417 15
    while (count($path) > 1) {
1418
      $key = array_shift($path);
1419 15
1420 3
      // 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 13
      if (!isset($array[$key]) || !is_array($array[$key])) {
1424 13
        $array[$key] = self::create(array());
1425 13
      }
1426
1427
      $array =& $array[$key];
1428
    }
1429 3
1430
    $array[array_shift($path)] = $value;
1431
1432
    return true;
1433
  }
1434
1435
  /**
1436
   * Return an array with all elements found in input array.
1437 25
   *
1438
   * @param array $search
1439 25
   *
1440
   * @return Arrayy (Immutable)
1441
   */
1442
  public function intersection(array $search)
1443
  {
1444
    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
  public function intersects(array $search)
1455
  {
1456
    return count($this->intersection($search)->array) > 0;
1457
  }
1458
1459 14
  /**
1460
   * Invoke a function on all of an array's values.
1461 14
   *
1462
   * @param mixed $callable
1463
   * @param mixed $arguments
1464
   *
1465
   * @return Arrayy (Immutable)
1466
   */
1467
  public function invoke($callable, $arguments = array())
1468
  {
1469 5
    // If one argument given for each iteration, create an array for it.
1470
    if (!is_array($arguments)) {
1471 5
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1472 2
    }
1473
1474
    // If the callable has arguments, pass them.
1475 4
    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 4
      $array = array_map($callable, $this->array, $arguments);
1477 4
    } else {
1478
      $array = array_map($callable, $this->array);
1479
    }
1480
1481 2
    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 1
  public function isAssoc()
1490
  {
1491 1
    if ($this->isEmpty()) {
1492
      return false;
1493
    }
1494
1495
    foreach ($this->keys()->getArray() as $key) {
1496
      if (!is_string($key)) {
1497
        return false;
1498
      }
1499 25
    }
1500
1501 25
    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 4
  public function isEmpty()
1510
  {
1511 4
    return !$this->array;
1512
  }
1513 4
1514 1
  /**
1515
   * Check if the current array is equal to the given "$array" or not.
1516 3
   *
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 12
   * Check if the current array is a multi-array.
1528
   *
1529 12
   * @return bool
1530 8
   */
1531 8
  public function isMultiArray()
1532
  {
1533 4
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1534 4
  }
1535
1536
  /**
1537 12
   * Check whether array is numeric or not.
1538
   *
1539
   * @return bool Returns true if numeric, false otherwise
1540
   */
1541
  public function isNumeric()
1542
  {
1543
    if ($this->isEmpty()) {
1544
      return false;
1545
    }
1546
1547 12
    foreach ($this->keys() as $key) {
1548
      if (!is_int($key)) {
1549 12
        return false;
1550 8
      }
1551 8
    }
1552
1553 4
    return true;
1554 4
  }
1555
1556
  /**
1557 12
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1558
   *
1559
   * @return bool
1560
   */
1561
  public function isSequential()
1562
  {
1563
    return array_keys($this->array) === range(0, count($this->array) - 1);
1564
  }
1565
1566
  /**
1567
   * Get all keys from the current array.
1568
   *
1569 10
   * @return Arrayy (Immutable)
1570
   */
1571 10
  public function keys()
1572
  {
1573
    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
  public function last()
1582 4
  {
1583
    return $this->pop();
1584 4
  }
1585
1586 4
  /**
1587
   * Get the last value(s) from the current array.
1588
   *
1589
   * @param int|null $number
1590
   *
1591
   * @return Arrayy (Immutable)
1592
   */
1593
  public function lastsImmutable($number = null)
1594
  {
1595
    if ($this->isEmpty()) {
1596 9
      return static::create();
1597
    }
1598
1599 9
    if ($number === null) {
1600
      $poppedValue = $this->pop();
1601
1602 9
      if ($poppedValue === null) {
1603 2
        $poppedValue = array($poppedValue);
1604
      } else {
1605
        $poppedValue = (array)$poppedValue;
1606 7
      }
1607
1608 7
      $arrayy = static::create($poppedValue);
1609
    } else {
1610
      $number = (int)$number;
1611
      $arrayy = $this->rest(-$number);
1612
    }
1613
1614
    return $arrayy;
1615
  }
1616
1617
  /**
1618 9
   * Get the last value(s) from the current array.
1619
   *
1620
   * @param int|null $number
1621 9
   *
1622
   * @return self (Mutable)
1623
   */
1624 9
  public function lastsMutable($number = null)
1625 2
  {
1626
    if ($this->isEmpty()) {
1627
      return $this;
1628 7
    }
1629
1630 7
    if ($number === null) {
1631
      $poppedValue = $this->pop();
1632
1633
      if ($poppedValue === null) {
1634
        $poppedValue = array($poppedValue);
1635
      } else {
1636
        $poppedValue = (array)$poppedValue;
1637
      }
1638 10
1639
      $this->array = static::create($poppedValue)->array;
1640 10
    } else {
1641 1
      $number = (int)$number;
1642
      $this->array = $this->rest(-$number)->array;
1643
    }
1644 9
1645
    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 25
  public function length()
1658
  {
1659 25
    return $this->size();
1660 4
  }
1661
1662 21
  /**
1663
   * Apply the given function to the every element of the array,
1664
   * collecting the results.
1665 25
   *
1666
   * @param callable $callable
1667
   *
1668
   * @return Arrayy (Immutable) Arrayy object with modified elements
1669
   */
1670
  public function map($callable)
1671
  {
1672
    $result = array_map($callable, $this->array);
1673
1674
    return static::create($result);
1675
  }
1676
1677
  /**
1678
   * Check if all items in current array match a truth test.
1679 16
   *
1680
   * @param \Closure $closure
1681 16
   *
1682 4
   * @return bool
1683
   */
1684 12 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 16
    $array = $this->each($closure);
1688
1689
    // Check the results
1690
    if (count($array) === 0) {
1691
      return true;
1692
    }
1693
1694
    $array = array_search(false, $array->toArray(), false);
1695
1696
    return is_bool($array);
1697
  }
1698
1699
  /**
1700 16
   * Check if any item in the current array matches a truth test.
1701
   *
1702 16
   * @param \Closure $closure
1703 4
   *
1704
   * @return bool
1705 12
   */
1706 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 16
    // Reduce the array to only booleans
1709
    $array = $this->each($closure);
1710
1711
    // Check the results
1712
    if (count($array) === 0) {
1713
      return true;
1714
    }
1715
1716
    $array = array_search(true, $array->toArray(), false);
1717
1718
    return is_int($array);
1719
  }
1720
1721
  /**
1722 16
   * Get the max value from an array.
1723
   *
1724 16
   * @return mixed
1725 4
   */
1726
  public function max()
1727 12
  {
1728
    if ($this->count() === 0) {
1729
      return false;
1730 16
    }
1731
1732
    return max($this->array);
1733
  }
1734
1735
  /**
1736
   * Merge the new $array into the current array.
1737
   *
1738 10
   * - keep key,value from the current array, also if the index is in the new $array
1739
   *
1740 10
   * @param array $array
1741 1
   * @param bool  $recursive
1742
   *
1743
   * @return Arrayy (Immutable)
1744 9
   */
1745 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
    if (true === $recursive) {
1748
      $result = array_replace_recursive($this->array, $array);
1749
    } else {
1750
      $result = array_replace($this->array, $array);
1751
    }
1752
1753
    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 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 4
    if (true === $recursive) {
1770
      $result = array_merge_recursive($this->array, $array);
1771 4
    } else {
1772
      $result = array_merge($this->array, $array);
1773 4
    }
1774
1775
    return static::create($result);
1776
  }
1777
1778
  /**
1779
   * Merge the the current array into the $array.
1780
   *
1781 16
   * - use key,value from the new $array, also if the index is in the current array
1782
   *
1783 16
   * @param array $array
1784
   * @param bool  $recursive
1785
   *
1786
   * @return Arrayy (Immutable)
1787
   */
1788 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
    if (true === $recursive) {
1791
      $result = array_replace_recursive($array, $this->array);
1792
    } else {
1793
      $result = array_replace($array, $this->array);
1794 8
    }
1795
1796 8
    return static::create($result);
1797 8
  }
1798
1799
  /**
1800 1
   * 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 8
   * - create new indexes
1804
   *
1805
   * @param array $array
1806
   * @param bool  $recursive
1807
   *
1808
   * @return Arrayy (Immutable)
1809
   */
1810 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 4
  {
1812
    if (true === $recursive) {
1813 4
      $result = array_merge_recursive($array, $this->array);
1814 4
    } else {
1815 4
      $result = array_merge($array, $this->array);
1816
    }
1817
1818 4
    return static::create($result);
1819
  }
1820
1821
  /**
1822
   * Get the min value from an array.
1823
   *
1824
   * @return mixed
1825
   */
1826
  public function min()
1827
  {
1828 17
    if ($this->count() === 0) {
1829
      return false;
1830 17
    }
1831
1832
    return min($this->array);
1833
  }
1834 17
1835 14
  /**
1836
   * Get a subset of the items from the given array.
1837 14
   *
1838
   * @param mixed[] $keys
1839
   *
1840 5
   * @return Arrayy (Immutable)
1841 5
   */
1842
  public function only(array $keys)
1843 5
  {
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 4
   *
1855
   * @return Arrayy (Immutable) Arrayy object padded to $size with $value
1856 4
   */
1857
  public function pad($size, $value)
1858 4
  {
1859
    $result = array_pad($this->array, $size, $value);
1860
1861
    return static::create($result);
1862 4
  }
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
  public function pop()
1870
  {
1871
    return array_pop($this->array);
1872
  }
1873
1874 14
  /**
1875
   * Prepend a value to the current array.
1876 14
   *
1877 14
   * @param mixed $value
1878
   * @param mixed $key
1879 14
   *
1880 3
   * @return self (Mutable) Return this Arrayy object, with the prepended value.
1881
   */
1882 3
  public function prepend($value, $key = null)
1883
  {
1884
    if ($key === null) {
1885
      array_unshift($this->array, $value);
1886
    } else {
1887
      /** @noinspection AdditionOperationOnArraysInspection */
1888
      $this->array = array($key => $value) + $this->array;
1889 11
    }
1890
1891 11
    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 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 16
    if (func_num_args()) {
1902
      $args = array_merge(array(&$this->array), func_get_args());
1903 16
      call_user_func_array('array_push', $args);
1904
    }
1905
1906
    return $this;
1907 16
  }
1908 6
1909 6
  /**
1910
   * Get a random value from the current array.
1911 6
   *
1912
   * @param null|int $number how many values you will take?
1913
   *
1914 11
   * @return Arrayy (Immutable)
1915
   */
1916 11
  public function randomImmutable($number = null)
1917
  {
1918
    if ($this->count() === 0) {
1919
      return static::create();
1920
    }
1921
1922 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
      $arrayRandValue = array($this->array[array_rand($this->array)]);
1924 4
1925
      return static::create($arrayRandValue);
1926 4
    }
1927
1928 4
    $arrayTmp = $this->array;
1929
    shuffle($arrayTmp);
1930
1931
    return self::create($arrayTmp)->firstsImmutable($number);
1932 4
  }
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
  public function randomKey()
1942 7
  {
1943
    $result = $this->randomKeys(1);
1944 7
1945
    if (!isset($result[0])) {
1946 7
      $result[0] = null;
1947
    }
1948
1949
    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 9
   * @throws \RangeException If array is empty
1960
   */
1961 9
  public function randomKeys($number)
1962 9
  {
1963 9
    $number = (int)$number;
1964 9
    $count = $this->count();
1965 1
1966
    if ($number === 0 || $number > $count) {
1967
      throw new \RangeException(
1968
          sprintf(
1969
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1970 9
              $number,
1971
              $count
1972
          )
1973
      );
1974
    }
1975
1976
    $result = (array)array_rand($this->array, $number);
1977
1978
    return static::create($result);
1979
  }
1980
1981 3
  /**
1982
   * Get a random value from the current array.
1983 3
   *
1984
   * @param null|int $number how many values you will take?
1985 3
   *
1986
   * @return Arrayy (Mutable)
1987
   */
1988 3
  public function randomMutable($number = null)
1989
  {
1990
    if ($this->count() === 0) {
1991 3
      return static::create();
1992
    }
1993
1994 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
      $arrayRandValue = array($this->array[array_rand($this->array)]);
1996
      $this->array = $arrayRandValue;
1997
1998
      return $this;
1999 9
    }
2000
2001 9
    shuffle($this->array);
2002
2003 9
    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
  public function randomValue()
2012
  {
2013 1
    $result = $this->randomImmutable();
2014
2015 1
    if (!isset($result[0])) {
2016
      $result[0] = null;
2017 1
    }
2018 1
2019 1
    return $result[0];
2020
  }
2021
2022
  /**
2023 1
   * Pick a given number of random values out of this array.
2024
   *
2025
   * @param int $number
2026
   *
2027
   * @return Arrayy (Mutable)
2028
   */
2029
  public function randomValues($number)
2030
  {
2031
    $number = (int)$number;
2032
2033 18
    return $this->randomMutable($number);
2034
  }
2035
2036 18
  /**
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 18
   * @return Arrayy (Immutable)
2045
   */
2046 18
  public function randomWeighted(array $array, $number = null)
2047
  {
2048
    $options = array();
2049
    foreach ($array as $option => $weight) {
2050
      if ($this->searchIndex($option) !== false) {
2051
        for ($i = 0; $i < $weight; ++$i) {
2052
          $options[] = $option;
2053
        }
2054 7
      }
2055
    }
2056 7
2057 7
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2058
  }
2059 7
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 7
   */
2068
  public function reduce($callable, array $init = array())
2069 7
  {
2070 7
    $result = array_reduce($this->array, $callable, $init);
2071
2072 7
    if ($result === null) {
2073
      $this->array = array();
2074
    } else {
2075
      $this->array = (array)$result;
2076
    }
2077
2078
    return static::create($this->array);
2079
  }
2080
2081
  /**
2082 7
   * Create a numerically re-indexed Arrayy object.
2083
   *
2084 7
   * @return self (Mutable) Return this Arrayy object, with re-indexed array-elements.
2085 7
   */
2086 6
  public function reindex()
2087 6
  {
2088
    $this->array = array_values($this->array);
2089
2090 6
    return $this;
2091
  }
2092
2093
  /**
2094 7
   * Return all items that fail the truth test.
2095 7
   *
2096
   * @param \Closure $closure
2097
   *
2098 7
   * @return Arrayy (Immutable)
2099
   */
2100 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
    $filtered = array();
2103
2104
    foreach ($this->array as $key => $value) {
2105
      if (!$closure($value, $key)) {
2106
        $filtered[$key] = $value;
2107
      }
2108
    }
2109
2110 2
    return static::create($filtered);
2111
  }
2112 2
2113
  /**
2114 2
   * Remove a value from the current array (optional using dot-notation).
2115
   *
2116
   * @param mixed $key
2117
   *
2118
   * @return Arrayy (Immutable)
2119
   */
2120
  public function remove($key)
2121
  {
2122
    // Recursive call
2123
    if (is_array($key)) {
2124 2
      foreach ($key as $k) {
2125
        $this->internalRemove($k);
2126 2
      }
2127
2128 2
      return static::create($this->array);
2129
    }
2130
2131
    $this->internalRemove($key);
2132
2133
    return static::create($this->array);
2134
  }
2135
2136
  /**
2137
   * Remove the first value from the current array.
2138 2
   *
2139
   * @return Arrayy (Immutable)
2140 2
   */
2141
  public function removeFirst()
2142 2
  {
2143
    $tmpArray = $this->array;
2144
    array_shift($tmpArray);
2145
2146
    return static::create($tmpArray);
2147
  }
2148
2149
  /**
2150
   * Remove the last value from the current array.
2151
   *
2152 1
   * @return Arrayy (Immutable)
2153
   */
2154 1
  public function removeLast()
2155 1
  {
2156
    $tmpArray = $this->array;
2157 1
    array_pop($tmpArray);
2158
2159
    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 3
   */
2169
  public function removeValue($value)
2170 3
  {
2171 3
    $isNumericArray = true;
2172
    foreach ($this->array as $key => $item) {
2173 3
      if ($item === $value) {
2174 3
        if (!is_int($key)) {
2175
          $isNumericArray = false;
2176
        }
2177 3
        unset($this->array[$key]);
2178
      }
2179
    }
2180
2181
    if ($isNumericArray) {
2182
      $this->array = array_values($this->array);
2183
    }
2184
2185
    return static::create($this->array);
2186
  }
2187
2188 1
  /**
2189
   * Replace a key with a new key/value pair.
2190 1
   *
2191
   * @param $replace
2192 1
   * @param $key
2193 1
   * @param $value
2194
   *
2195
   * @return Arrayy (Immutable)
2196 1
   */
2197
  public function replace($replace, $key, $value)
2198
  {
2199
    $this->remove($replace);
2200
2201
    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 15
   *
2207
   * @param array $keys Keys array
2208 15
   *
2209
   * @return Arrayy (Immutable) Arrayy object with keys from the other array.
2210 15
   */
2211
  public function replaceAllKeys(array $keys)
2212
  {
2213
    $result = array_combine($keys, $this->array);
2214
2215
    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 1
   * @return Arrayy (Immutable) Arrayy object with values from the other array.
2224
   */
2225 1
  public function replaceAllValues(array $array)
2226
  {
2227 1
    $result = array_combine($this->array, $array);
2228 1
2229 1
    return static::create($result);
2230 1
  }
2231 1
2232 1
  /**
2233 1
   * Replace the keys in an array with another set.
2234 1
   *
2235 1
   * @param array $keys An array of keys matching the array's size
2236 1
   *
2237 1
   * @return Arrayy (Immutable)
2238 1
   */
2239 1
  public function replaceKeys(array $keys)
2240
  {
2241 1
    $values = array_values($this->array);
2242 1
    $result = array_combine($keys, $values);
2243
2244
    return static::create($result);
2245
  }
2246
2247
  /**
2248 1
   * Replace the first matched value in an array.
2249
   *
2250
   * @param mixed $search
2251
   * @param mixed $replacement
2252
   *
2253
   * @return Arrayy (Immutable)
2254
   */
2255
  public function replaceOneValue($search, $replacement = '')
2256 7
  {
2257
    $array = $this->array;
2258 7
    $key = array_search($search, $array, true);
2259
2260 7
    if ($key !== false) {
2261
      $array[$key] = $replacement;
2262
    }
2263
2264
    return static::create($array);
2265
  }
2266
2267
  /**
2268
   * Replace values in the current array.
2269
   *
2270 20
   * @param string $search      The string to replace.
2271
   * @param string $replacement What to replace it with.
2272 20
   *
2273
   * @return Arrayy (Immutable)
2274
   */
2275
  public function replaceValues($search, $replacement = '')
2276
  {
2277
    $array = $this->each(
2278
        function ($value) use ($search, $replacement) {
2279
          return UTF8::str_replace($search, $replacement, $value);
2280
        }
2281
    );
2282 7
2283
    return $array;
2284
  }
2285 7
2286
  /**
2287 7
   * Get the last elements from index $from until the end of this array.
2288 7
   *
2289
   * @param int $from
2290 7
   *
2291 5
   * @return Arrayy (Immutable)
2292
   */
2293
  public function rest($from = 1)
2294
  {
2295 7
    $tmpArray = $this->array;
2296
2297
    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 17
   * @param int|string $to
2307
   *
2308 17
   * @return Arrayy (Immutable)
2309
   */
2310 17
  public function moveElement($from, $to)
2311
  {
2312
    $array = $this->array;
2313
2314
    if (is_int($from)) {
2315
      $tmp = array_splice($array, $from, 1);
2316
      array_splice($array, $to, 0, $tmp);
2317
      $output = $array;
2318
    } elseif (is_string($from)) {
2319
      $indexToMove = array_search($from, array_keys($array), true);
2320
      $itemToMove = $array[$from];
2321
      array_splice($array, $indexToMove, 1);
2322
      $i = 0;
2323 10
      $output = array();
2324
      foreach($array as $key => $item) {
2325
        if ($i == $to) {
2326 10
          $output[$from] = $itemToMove;
2327 5
        }
2328
        $output[$key] = $item;
2329
        $i++;
2330 10
      }
2331
    } else {
2332
      $output = array();
2333
    }
2334
2335
    return static::create($output);
2336
  }
2337
2338 4
  /**
2339
   * Return the array in the reverse order.
2340 4
   *
2341
   * @return self (Mutable) Return this Arrayy object.
2342
   */
2343
  public function reverse()
2344
  {
2345
    $this->array = array_reverse($this->array);
2346
2347
    return $this;
2348 1
  }
2349
2350 1
  /**
2351
   * Search for the first index of the current array via $value.
2352 1
   *
2353
   * @param mixed $value
2354 1
   *
2355
   * @return int|float|string
2356
   */
2357
  public function searchIndex($value)
2358
  {
2359
    return array_search($value, $this->array, true);
2360
  }
2361
2362 110
  /**
2363
   * Search for the value of the current array via $index.
2364 110
   *
2365
   * @param mixed $index
2366
   *
2367
   * @return Arrayy (Immutable) will return a empty Arrayy if the value wasn't found
2368
   */
2369
  public function searchValue($index)
2370
  {
2371
    // init
2372
    $return = array();
2373
2374
    if ($this->isEmpty()) {
2375
      return static::create();
2376 4
    }
2377
2378 4
    // php cast "bool"-index into "int"-index
2379
    if ((bool)$index === $index) {
2380 4
      $index = (int)$index;
2381
    }
2382
2383
    if (array_key_exists($index, $this->array) === true) {
2384
      $return = array($this->array[$index]);
2385
    }
2386
2387
2388
    return static::create($return);
2389
  }
2390
2391
  /**
2392 19
   * Set a value for the current array (optional using dot-notation).
2393
   *
2394 19
   * @param string $key   The key to set
2395
   * @param mixed  $value Its value
2396 19
   *
2397
   * @return Arrayy (Immutable)
2398
   */
2399
  public function set($key, $value)
2400
  {
2401
    $this->internalSet($key, $value);
2402
2403
    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 18
   *
2411
   * @param string $key      The key
2412 18
   * @param mixed  $fallback The default value to set if it isn't
2413
   *
2414 18
   * @return mixed (Mutable)
2415
   */
2416
  public function setAndGet($key, $fallback = null)
2417
  {
2418
    // If the key doesn't exist, set it
2419
    if (!$this->has($key)) {
2420
      $this->array = $this->set($key, $fallback)->getArray();
2421
    }
2422
2423
    return $this->get($key);
2424
  }
2425 1
2426
  /**
2427 1
   * Shifts a specified value off the beginning of array.
2428
   *
2429
   * @return mixed A shifted element from the current array. (Mutable)
2430
   */
2431
  public function shift()
2432
  {
2433
    return array_shift($this->array);
2434
  }
2435
2436
  /**
2437
   * Shuffle the current array.
2438 1
   *
2439
   * @return Arrayy (Immutable)
2440 1
   */
2441
  public function shuffle()
2442
  {
2443
    $array = $this->array;
2444
2445
    shuffle($array);
2446
2447
    return static::create($array);
2448
  }
2449
2450
  /**
2451
   * Get the size of an array.
2452
   *
2453
   * @return int
2454
   */
2455 1
  public function size()
2456
  {
2457 1
    return count($this->array);
2458 1
  }
2459
2460
  /**
2461 1
   * Extract a slice of the array.
2462 1
   *
2463
   * @param int      $offset       Slice begin index
2464 1
   * @param int|null $length       Length of the slice
2465 1
   * @param bool     $preserveKeys Whether array keys are preserved or no
2466
   *
2467 1
   * @return static A slice of the original array with length $length
2468 1
   */
2469
  public function slice($offset, $length = null, $preserveKeys = false)
2470
  {
2471 1
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
2472
2473 1
    return static::create($result);
2474
  }
2475
2476
  /**
2477 1
   * Sort the current array and optional you can keep the keys.
2478
   *
2479 1
   * @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
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2486
  {
2487
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2488
2489 18
    return $this;
2490
  }
2491 18
2492
  /**
2493
   * Sort the current array by key.
2494 18
   *
2495 18
   * @link http://php.net/manual/en/function.ksort.php
2496 6
   * @link http://php.net/manual/en/function.krsort.php
2497 6
   *
2498 13
   * @param int|string $direction use SORT_ASC or SORT_DESC
2499 13
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2500
   *
2501 13
   * @return self (Mutable) Return this Arrayy object.
2502
   */
2503 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2504
  {
2505
    $this->sorterKeys($this->array, $direction, $strategy);
2506
2507
    return $this;
2508
  }
2509
2510
  /**
2511 19
   * Sort the current array by value.
2512
   *
2513 19
   * @param int $direction use SORT_ASC or SORT_DESC
2514
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2515 19
   *
2516 19
   * @return Arrayy (Immutable)
2517
   */
2518
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2519
  {
2520 19
    return $this->sort($direction, $strategy, true);
2521 19
  }
2522 9
2523 5
  /**
2524
   * Sort the current array by value.
2525 4
   *
2526
   * @param int $direction use SORT_ASC or SORT_DESC
2527 9
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2528 10
   *
2529 10
   * @return Arrayy (Immutable)
2530
   */
2531 10
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2532 4
  {
2533
    return $this->sort($direction, $strategy, false);
2534 6
  }
2535
2536
  /**
2537 19
   * 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 1
   */
2548
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2549 1
  {
2550
    $array = (array)$this->array;
2551 1
    $direction = $this->getDirection($direction);
2552 1
2553
    // Transform all values into their results.
2554 1
    if ($sorter) {
2555 1
      $arrayy = self::create($array);
2556 1
2557
      $that = $this;
2558
      $results = $arrayy->each(
2559 1
          function ($value) use ($sorter, $that) {
2560
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2561
          }
2562
      );
2563
2564
      $results = $results->getArray();
2565
    } else {
2566
      $results = $array;
2567 1
    }
2568
2569 1
    // Sort by the results and replace by original values
2570
    array_multisort($results, $direction, $strategy, $array);
2571 1
2572 1
    return static::create($array);
2573
  }
2574
2575 1
  /**
2576 1
   * sorting keys
2577
   *
2578
   * @param array $elements
2579
   * @param int   $direction
2580
   * @param int   $strategy
2581
   */
2582
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2583
  {
2584
    $direction = $this->getDirection($direction);
2585
2586
    switch ($direction) {
2587
      case 'desc':
2588 1
      case SORT_DESC:
2589
        krsort($elements, $strategy);
2590 1
        break;
2591
      case 'asc':
2592 1
      case SORT_ASC:
2593
      default:
2594 1
        ksort($elements, $strategy);
2595
    }
2596
  }
2597
2598
  /**
2599
   * @param array      &$elements
2600
   * @param int|string $direction
2601
   * @param int        $strategy
2602 155
   * @param bool       $keepKeys
2603
   */
2604 155
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2605
  {
2606
    $direction = $this->getDirection($direction);
2607
2608
    if (!$strategy) {
2609
      $strategy = SORT_REGULAR;
2610
    }
2611
2612
    switch ($direction) {
2613
      case 'desc':
2614 5
      case SORT_DESC:
2615
        if ($keepKeys) {
2616 5
          arsort($elements, $strategy);
2617
        } else {
2618
          rsort($elements, $strategy);
2619
        }
2620
        break;
2621
      case 'asc':
2622
      case SORT_ASC:
2623
      default:
2624
        if ($keepKeys) {
2625
          asort($elements, $strategy);
2626 19
        } else {
2627
          sort($elements, $strategy);
2628 19
        }
2629
    }
2630
  }
2631
2632
  /**
2633
   * Split an array in the given amount of pieces.
2634
   *
2635
   * @param int  $numberOfPieces
2636 8
   * @param bool $keepKeys
2637
   *
2638 8
   * @return Arrayy (Immutable)
2639 8
   */
2640 8
  public function split($numberOfPieces = 2, $keepKeys = false)
2641 7
  {
2642 7
    $arrayCount = $this->count();
2643
2644
    if ($arrayCount === 0) {
2645 7
      $result = array();
2646 8
    } else {
2647 8
      $numberOfPieces = (int)$numberOfPieces;
2648
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
2649
      $result = array_chunk($this->array, $splitSize, $keepKeys);
2650 8
    }
2651
2652
    return static::create($result);
2653 8
  }
2654
2655
  /**
2656 8
   * Stripe all empty items.
2657
   *
2658
   * @return Arrayy (Immutable)
2659
   */
2660
  public function stripEmpty()
2661
  {
2662
    return $this->filter(
2663
        function ($item) {
2664 4
          if ($item === null) {
2665
            return false;
2666 4
          }
2667 4
2668 4
          return (bool)trim((string)$item);
2669
        }
2670
    );
2671 4
  }
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 2
   * @return Arrayy (Immutable)
2680
   */
2681 2
  public function swap($swapA, $swapB)
2682
  {
2683
    $array = $this->array;
2684
2685
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
2686
2687
    return static::create($array);
2688
  }
2689
2690
  /**
2691
   * alias: for "Arrayy->getArray()"
2692 9
   *
2693
   * @see Arrayy::getArray()
2694 9
   */
2695 4
  public function toArray()
2696
  {
2697 5
    return $this->getArray();
2698
  }
2699
2700 9
  /**
2701
   * Convert the current array to JSON.
2702
   *
2703
   * @param null $options e.g. JSON_PRETTY_PRINT
2704
   *
2705
   * @return string
2706
   */
2707
  public function toJson($options = null)
2708
  {
2709
    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
  public function toString($separator = ',')
2720
  {
2721
    return $this->implode($separator);
2722
  }
2723
2724
  /**
2725
   * Return a duplicate free copy of the current array.
2726
   *
2727
   * @return Arrayy (Mutable)
2728
   */
2729
  public function unique()
2730
  {
2731
    $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
        $this->array,
2733
        function ($resultArray, $value) {
2734
          if (!in_array($value, $resultArray, true)) {
2735
            $resultArray[] = $value;
2736
          }
2737
2738
          return $resultArray;
2739
        },
2740
        array()
2741
    );
2742
2743
    if ($this->array === null) {
2744
      $this->array = array();
2745
    } else {
2746
      $this->array = (array)$this->array;
2747
    }
2748
2749
    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 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
    if (func_num_args()) {
2760
      $args = array_merge(array(&$this->array), func_get_args());
2761
      call_user_func_array('array_unshift', $args);
2762
    }
2763
2764
    return $this;
2765
  }
2766
2767
  /**
2768
   * Get all values from a array.
2769
   *
2770
   * @return Arrayy (Immutable)
2771
   */
2772
  public function values()
2773
  {
2774
    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
  public function walk($callable, $recursive = false)
2786
  {
2787
    if (true === $recursive) {
2788
      array_walk_recursive($this->array, $callable);
2789
    } else {
2790
      array_walk($this->array, $callable);
2791
    }
2792
2793
    return $this;
2794
  }
2795
2796
}
2797