Completed
Push — master ( 17fe6b...d39ec0 )
by Lars
03:26
created

Arrayy::appendArrayValues()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 7.2269

Importance

Changes 0
Metric Value
cc 7
nc 6
nop 2
dl 0
loc 24
ccs 5
cts 6
cp 0.8333
crap 7.2269
rs 8.6026
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arrayy;
6
7
use voku\helper\UTF8;
8
9
/** @noinspection ClassReImplementsParentInterfaceInspection */
10
11
/**
12
 * Methods to manage arrays.
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \Countable
18
{
19
  /**
20
   * @var array
21
   */
22
  protected $array = [];
23
24
  /**
25
   * @var string
26
   */
27
  protected $iteratorClass = ArrayyIterator::class;
28
29
  /**
30
   * @var string
31
   */
32
  protected $pathSeparator = '.';
33
34
  /** @noinspection MagicMethodsValidityInspection */
35
  /**
36
   * Initializes
37
   *
38
   * @param mixed  $array <p>Should be an array, otherwise it will try to convert it into an array.</p>
39
   * @param string $iteratorClass
40
   */
41 870
  public function __construct($array = [], $iteratorClass = ArrayyIterator::class)
42
  {
43 870
    $array = $this->fallbackForArray($array);
44 868
    $this->array = $array;
45
46 868
    $this->setIteratorClass($iteratorClass);
47 868
  }
48
49
  /**
50
   * Get a value by key.
51
   *
52
   * @param mixed $key
53
   *
54
   * @return mixed <p>Get a Value from the current array.</p>
55
   */
56 2
  public function &__get($key)
57
  {
58 2
    $return = $this->get($key);
59
60 2
    if (\is_array($return)) {
61
      return static::create($return);
62
    }
63
64 2
    return $return;
65
  }
66
67
  /**
68
   * Call object as function.
69
   *
70
   * @param mixed $key
71
   *
72
   * @return mixed
73
   */
74 1
  public function __invoke($key = null)
75
  {
76 1
    if ($key !== null) {
77 1
      if (isset($this->array[$key])) {
78 1
        return $this->array[$key];
79
      }
80
81
      return false;
82
    }
83
84
    return (array)$this->array;
85
  }
86
87
  /**
88
   * Whether or not an element exists by key.
89
   *
90
   * @param mixed $key
91
   *
92
   * @return bool <p>True is the key/index exists, otherwise false.</p>
93
   */
94
  public function __isset($key)
95
  {
96
    return $this->offsetExists($key);
97
  }
98
99
  /**
100
   * Assigns a value to the specified element.
101
   *
102
   * @param mixed $key
103
   * @param mixed $value
104
   */
105 2
  public function __set($key, $value)
106
  {
107 2
    $this->internalSet($key, $value);
108 2
  }
109
110
  /**
111
   * magic to string
112
   *
113
   * @return string
114
   */
115 15
  public function __toString()
116
  {
117 15
    return $this->toString();
118
  }
119
120
  /**
121
   * Unset element by key.
122
   *
123
   * @param mixed $key
124
   */
125
  public function __unset($key)
126
  {
127
    $this->internalRemove($key);
128
  }
129
130
  /**
131
   * alias: for "Arrayy->append()"
132
   *
133
   * @see Arrayy::append()
134
   *
135
   * @param mixed $value
136
   *
137
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
138
   */
139 1
  public function add($value)
140
  {
141 1
    return $this->append($value);
142
  }
143
144
  /**
145
   * Append a (key) + values to the current array.
146
   *
147
   * @param array $values
148
   * @param mixed $key
149
   *
150
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
151
   */
152 9
  public function appendArrayValues(array $values, $key = null)
153
  {
154 9
    if ($key !== null) {
155
      if (
156
          isset($this->array[$key])
157 9
          &&
158
          is_array($this->array[$key])
159
      ) {
160 9
        foreach ($values as $value) {
161
          $this->array[$key][] = $value;
162
        }
163
      } else {
164
        foreach ($values as $value) {
165
          $this->array[$key] = $value;
166
        }
167
      }
168
    } else {
169
      foreach ($values as $value) {
170
        $this->array[] = $value;
171
      }
172
    }
173
174 4
    return $this;
175
  }
176 4
177
  /**
178 4
   * Append a (key) + value to the current array.
179
   *
180
   * @param mixed $value
181
   * @param mixed $key
182
   *
183
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
184
   */
185
  public function append($value, $key = null)
186
  {
187
    if ($key !== null) {
188
      if (
189
          isset($this->array[$key])
190
          &&
191
          is_array($this->array[$key])
192
      ) {
193
        $this->array[$key][] = $value;
194
      } else {
195
        $this->array[$key] = $value;
196
      }
197
    } else {
198
      $this->array[] = $value;
199
    }
200
201
    return $this;
202
  }
203
204
  /**
205
   * Sort the entries by value.
206
   *
207
   * @param int $sort_flags [optional] <p>
208
   *                        You may modify the behavior of the sort using the optional
209
   *                        parameter sort_flags, for details
210
   *                        see sort.
211
   *                        </p>
212
   *
213 37
   * @return static <p>(Mutable) Return this Arrayy object.</p>
214
   */
215 37
  public function asort(int $sort_flags = 0)
216
  {
217
    \asort($this->array, $sort_flags);
218
219
    return $this;
220
  }
221
222
  /**
223
   * Counts all elements in an array, or something in an object.
224
   * <p>For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
225 1
   * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
226
   * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
227 1
   * implemented and used in PHP.
228
   *
229 1
   * @link http://php.net/manual/en/function.count.php
230
   *
231
   * @param int $mode [optional] If the optional mode parameter is set to
232
   *                  COUNT_RECURSIVE (or 1), count
233
   *                  will recursively count the array. This is particularly useful for
234
   *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
235
   *
236
   * @return int the number of elements in var, which is
237 1
   * typically an array, since anything else will have one
238
   * element.
239 1
   * </p>
240
   * <p>
241
   * If var is not an array or an object with
242
   * implemented Countable interface,
243
   * 1 will be returned.
244
   * There is one exception, if var is &null;,
245
   * 0 will be returned.
246
   * </p>
247 20
   * <p>
248
   * Caution: count may return 0 for a variable that isn't set,
249 20
   * but it may also return 0 for a variable that has been initialized with an
250
   * empty array. Use isset to test if a variable is set.
251 20
   *
252
   * @return int
253
   */
254
  public function count(int $mode = COUNT_NORMAL): int
255
  {
256
    return \count($this->array, $mode);
257
  }
258
259 20
  /**
260
   * Exchange the array for another one.
261 20
   *
262
   * @param array|static $data
263
   *
264
   * @return array
265
   */
266
  public function exchangeArray($data): array
267
  {
268
    $this->array = $this->fallbackForArray($data);
269
270
    return $this->array;
271
  }
272
273
  /**
274
   * Creates a copy of the ArrayyObject.
275 4
   *
276
   * @return array
277 4
   */
278
  public function getArrayCopy(): array
279 4
  {
280
    return $this->array;
281
  }
282
283
  /**
284
   * Returns a new ArrayyIterator, thus implementing the \ArrayIterator interface.
285
   *
286
   * @return \ArrayIterator <p>An iterator for the values in the array.</p>
287
   */
288
  public function getIterator(): \ArrayIterator
289
  {
290
    $iterator = $this->getIteratorClass();
291
292
    return new $iterator($this->array);
293
  }
294
295
  /**
296
   * Gets the iterator classname for the ArrayObject.
297
   *
298
   * @return string
299 1
   */
300
  public function getIteratorClass(): string
301 1
  {
302
    return $this->iteratorClass;
303 1
  }
304
305
  /**
306
   * Sort the entries by key
307
   *
308
   * @param int $sort_flags [optional] <p>
309
   *                        You may modify the behavior of the sort using the optional
310
   *                        parameter sort_flags, for details
311
   *                        see sort.
312
   *                        </p>
313 40
   *
314
   * @return static <p>(Mutable) Return this Arrayy object.</p>
315 40
   */
316 4
  public function ksort(int $sort_flags = 0)
317
  {
318
    \ksort($this->array, $sort_flags);
319
320 36
    return $this;
321 1
  }
322
323
  /**
324 36
   * Sort an array using a case insensitive "natural order" algorithm
325
   *
326
   * @return static <p>(Mutable) Return this Arrayy object.</p>
327 36
   */
328
  public function natcasesort()
329
  {
330 12
    \natcasesort($this->array);
331
332 36
    return $this;
333
  }
334
335 34
  /**
336
   * Sort entries using a "natural order" algorithm
337
   *
338 3
   * @return static <p>(Mutable) Return this Arrayy object.</p>
339
   */
340 3
  public function natsort()
341
  {
342 3
    \natsort($this->array);
343 3
344 3
    return $this;
345 3
  }
346
347 3
  /**
348 3
   * Whether or not an offset exists.
349 3
   *
350 3
   * @param int|float|string $offset
351 3
   *
352
   * @return bool
353
   */
354
  public function offsetExists($offset): bool
355 3
  {
356
    if ($this->isEmpty()) {
357
      return false;
358
    }
359
360
    // php cast "bool"-index into "int"-index
361
    if ((bool)$offset === $offset) {
362
      $offset = (int)$offset;
363
    }
364
365 26
    $tmpReturn = \array_key_exists($offset, $this->array);
366
367 26
    if (
368
        $tmpReturn === true
369
        ||
370
        (
371
            $tmpReturn === false
372
            &&
373
            \strpos((string)$offset, $this->pathSeparator) === false
374
        )
375
    ) {
376 17
      return $tmpReturn;
377
    }
378 17
379 4
    $offsetExists = false;
380
381 13
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
382
383 17
      $offsetExists = false;
384
      $explodedPath = \explode($this->pathSeparator, (string)$offset);
385
      $lastOffset = \array_pop($explodedPath);
386
      $containerPath = \implode($this->pathSeparator, $explodedPath);
387
388
      $this->callAtPath(
389
          $containerPath,
390 7
          function ($container) use ($lastOffset, &$offsetExists) {
0 ignored issues
show
Documentation introduced by
function ($container) us...tOffset, $container); } is of type object<Closure>, but the function expects a object<callable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
391
            $offsetExists = \array_key_exists($lastOffset, $container);
392 7
          }
393 1
      );
394
    }
395
396 6
    return $offsetExists;
397 4
  }
398
399 4
  /**
400
   * Returns the value at specified offset.
401
   *
402 3
   * @param int|float|string $offset
403
   *
404 2
   * @return mixed <p>Will return null if the offset did not exists.</p>
405 2
   */
406
  public function offsetGet($offset)
407 2
  {
408 2
    return $this->offsetExists($offset) ? $this->get($offset) : null;
409 2
  }
410 2
411 2
  /**
412
   * Assigns a value to the specified offset.
413
   *
414
   * @param int|float|string $offset
415 3
   * @param mixed            $value
416
   */
417
  public function offsetSet($offset, $value)
418
  {
419
    if ($offset === null) {
420
      $this->array[] = $value;
421
    } else {
422 1
      $this->internalSet($offset, $value);
423
    }
424 1
  }
425
426
  /**
427
   * Unset an offset.
428
   *
429
   * @param int|float|string $offset
430
   */
431
  public function offsetUnset($offset)
432
  {
433
    if ($this->isEmpty()) {
434
      return;
435
    }
436 868
437
    if (\array_key_exists($offset, $this->array)) {
438 868
      unset($this->array[$offset]);
439 868
440
      return;
441 868
    }
442
443
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
444
445
      $path = \explode($this->pathSeparator, (string)$offset);
446
      $pathToUnset = \array_pop($path);
447
448
      $this->callAtPath(
449
          \implode($this->pathSeparator, $path),
450
          function (&$offset) use ($pathToUnset) {
0 ignored issues
show
Documentation introduced by
function (&$offset) use(...ffset[$pathToUnset]); } is of type object<Closure>, but the function expects a object<callable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
451
            unset($offset[$pathToUnset]);
452
          }
453
      );
454
455
    }
456
  }
457
458
  /**
459
   * Serialize the current "Arrayy"-object.
460
   *
461
   * @return string
462
   */
463
  public function serialize()
464
  {
465
    return parent::serialize();
466
  }
467
468
  /**
469
   * Sets the iterator classname for the current "Arrayy"-object.
470
   *
471
   * @param string $class
472
   *
473
   * @return void
474
   *
475
   * @throws \InvalidArgumentException
476
   */
477
  public function setIteratorClass($class)
478
  {
479
    if (\class_exists($class)) {
480
      $this->iteratorClass = $class;
481
482
      return;
483
    }
484
485
    if (\strpos($class, '\\') === 0) {
486
      $class = '\\' . $class;
487 5
      if (\class_exists($class)) {
488
        $this->iteratorClass = $class;
489 5
490
        return;
491
      }
492
    }
493
494
    throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
495
  }
496
497
  /**
498
   * Sort the entries with a user-defined comparison function and maintain key association.
499 1
   *
500
   * @param \callable $function
501 1
   *
502
   * @return static <p>(Mutable) Return this Arrayy object.</p>
503 1
   *
504
   * @throws \InvalidArgumentException
505
   */
506 View Code Duplication
  public function uasort($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
507
  {
508
    if (!\is_callable($function)) {
509
      throw new \InvalidArgumentException(
510
          'Passed function must be callable'
511
      );
512
    }
513 10
514
    \uasort($this->array, $function);
515 10
516 10
    return $this;
517 9
  }
518
519 9
  /**
520
   * Sort the entries by keys using a user-defined comparison function.
521
   *
522 9
   * @param \callable $function
523
   *
524
   * @return static <p>(Mutable) Return this Arrayy object.</p>
525
   *
526 10
   * @throws \InvalidArgumentException
527
   */
528
  public function uksort($function)
529
  {
530
    return $this->customSortKeys($function);
531
  }
532
533
  /**
534
   * Unserialize an string and return this object.
535
   *
536 10
   * @param string $string
537
   *
538 10
   * @return static <p>(Mutable)</p>
539 10
   */
540 9
  public function unserialize($string)
541
  {
542 9
    parent::unserialize($string);
543
544 9
    return $this;
545 1
  }
546
547 9
  /**
548
   * Add a suffix to each key.
549
   *
550
   * @param mixed $prefix
551 10
   *
552
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
553
   */
554 View Code Duplication
  public function appendToEachKey($prefix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
555
  {
556
    $result = [];
557
    foreach ($this->array as $key => $item) {
558
      if ($item instanceof self) {
559
        $result[$prefix . $key] = $item->appendToEachKey($prefix);
560
      } elseif (\is_array($item)) {
561 4
        $result[$prefix . $key] = self::create($item)->appendToEachKey($prefix)->toArray();
562
      } else {
563 4
        $result[$prefix . $key] = $item;
564
      }
565 4
    }
566 1
567
    return self::create($result);
568
  }
569 3
570 3
  /**
571 1
   * Add a prefix to each value.
572 1
   *
573
   * @param mixed $prefix
574 3
   *
575
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
576
   */
577 3 View Code Duplication
  public function appendToEachValue($prefix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
578
  {
579
    $result = [];
580
    foreach ($this->array as $key => $item) {
581
      if ($item instanceof self) {
582
        $result[$key] = $item->appendToEachValue($prefix);
583
      } elseif (\is_array($item)) {
584
        $result[$key] = self::create($item)->appendToEachValue($prefix)->toArray();
585
      } elseif (\is_object($item)) {
586
        $result[$key] = $item;
587
      } else {
588
        $result[$key] = $prefix . $item;
589
      }
590
    }
591
592
    return self::create($result);
593 10
  }
594
595
  /**
596 10
   * Convert an array into a object.
597
   *
598 10
   * @param array $array PHP array
599
   *
600
   * @return \stdClass (object)
601
   */
602 10
  protected static function arrayToObject(array $array = []): \stdClass
603
  {
604
    $object = new \stdClass();
605 10
606
    if (!\is_array($array) || \count($array, COUNT_NORMAL) <= 0) {
607
      return $object;
608
    }
609
610 10
    foreach ($array as $name => $value) {
611
      if (\is_array($value)) {
612
        $object->{$name} = self::arrayToObject($value);
613 10
        continue;
614
      }
615
      $object->{$name} = $value;
616
    }
617 10
618 10
    return $object;
619
  }
620
621
  /**
622 10
   * @param array $input        <p>
623
   *                            An array containing keys to return.
624
   *                            </p>
625
   * @param mixed $search_value [optional] <p>
626
   *                            If specified, then only keys containing these values are returned.
627
   *                            </p>
628
   * @param bool  $strict       [optional] <p>
629
   *                            Determines if strict comparison (===) should be used during the search.
630 4
   *                            </p>
631
   *
632 4
   * @return array an array of all the keys in input.
633
   */
634 4
  protected function array_keys_recursive(array $input = null, $search_value = null, bool $strict = true): array
635
  {
636
    // init
637
    $keys = [];
638
639
    if ($input === null) {
640
      $input = $this->array;
641
    }
642
643
    foreach ($input as $key => $value) {
644 2
645
      if (
646 2
          $search_value === null
647
          ||
648 2
          (
649 2
              \is_array($search_value) === true
650
              &&
651
              \in_array($key, $search_value, $strict)
652 2
          )
653
      ) {
654
        $keys[] = $key;
655
      }
656
657
      // check if recursive is needed
658
      if (\is_array($value) === true) {
659
        $keys = \array_merge($keys, $this->array_keys_recursive($value));
660
      }
661
    }
662 10
663
    return $keys;
664 10
  }
665
666 10
  /**
667 2
   * Sort an array in reverse order and maintain index association.
668
   *
669
   * @return static <p>(Mutable) Return this Arrayy object.</p>
670 8
   */
671 3
  public function arsort()
672
  {
673
    \arsort($this->array);
674 8
675
    return $this;
676
  }
677
678
  /**
679
   * Iterate over the current array and execute a callback for each loop.
680
   *
681
   * @param \Closure $closure
682 4
   *
683
   * @return static <p>(Immutable)</p>
684 4
   */
685 4 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...
686
  {
687
    $array = $this->array;
688 4
689 4
    foreach ($array as $key => $value) {
690
      $closure($value, $key);
691 4
    }
692
693
    return static::create($array);
694
  }
695 4
696 1
  /**
697 1
   * Returns the average value of the current array.
698 1
   *
699 1
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
700
   *
701
   * @return int|double <p>The average value.</p>
702 4
   */
703
  public function average($decimals = 0)
704 4
  {
705
    $count = \count($this->array, COUNT_NORMAL);
706
707
    if (!$count) {
708
      return 0;
709
    }
710
711
    if (!\is_int($decimals)) {
712
      $decimals = 0;
713
    }
714 1
715
    return \round(\array_sum($this->array) / $count, $decimals);
716 1
  }
717
718
  /**
719
   * @param mixed      $path
720
   * @param \callable  $callable
721
   * @param null|array $currentOffset
722
   */
723
  protected function callAtPath($path, $callable, &$currentOffset = null)
724
  {
725
    if ($currentOffset === null) {
726
      $currentOffset = &$this->array;
727
    }
728 1
729
    $explodedPath = \explode($this->pathSeparator, $path);
730 1
    $nextPath = \array_shift($explodedPath);
731
732 1
    if (!isset($currentOffset[$nextPath])) {
733
      return;
734
    }
735
736
    if (!empty($explodedPath)) {
737
      $this->callAtPath(
738
          \implode($this->pathSeparator, $explodedPath),
739
          $callable,
740
          $currentOffset[$nextPath]
741
      );
742
    } else {
743 4
      $callable($currentOffset[$nextPath]);
744
    }
745 4
  }
746
747 4
  /**
748
   * Changes all keys in an array.
749
   *
750
   * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
751
   *                  or <strong>CASE_LOWER</strong> (default)</p>
752
   *
753
   * @return static <p>(Immutable)</p>
754
   */
755 8
  public function changeKeyCase(int $case = CASE_LOWER)
756
  {
757 8
    return static::create(UTF8::array_change_key_case($this->array, $case));
758 8
  }
759 7
760 8
  /**
761
   * Change the path separator of the array wrapper.
762
   *
763
   * By default, the separator is: "."
764
   *
765
   * @param string $separator <p>Separator to set.</p>
766
   *
767
   * @return static <p>Mutable</p>
768
   */
769 4
  public function changeSeparator($separator)
770
  {
771 4
    $this->pathSeparator = $separator;
772
773 4
    return $this;
774
  }
775
776
  /**
777
   * Create a chunked version of the current array.
778
   *
779
   * @param int  $size         <p>Size of each chunk.</p>
780
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
781
   *
782
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
783
   */
784
  public function chunk($size, $preserveKeys = false)
785 22
  {
786
    $result = \array_chunk($this->array, $size, $preserveKeys);
787 22
788 18
    return static::create($result);
789
  }
790
791 13
  /**
792
   * Clean all falsy values from the current array.
793
   *
794
   * @return static <p>(Immutable)</p>
795
   */
796
  public function clean()
797
  {
798
    return $this->filter(
799
        function ($value) {
800
          return (bool)$value;
801
        }
802 26
    );
803
  }
804 26
805 26
  /**
806 26
   * WARNING!!! -> Clear the current array.
807 26
   *
808 26
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
809 22
   */
810 26
  public function clear()
811 26
  {
812 26
    $this->array = [];
813 26
814
    return $this;
815
  }
816
817 13
  /**
818 13
   * Check if an item is in the current array.
819 13
   *
820 13
   * @param string|int|float $value
821 11
   * @param bool             $recursive
822 13
   * @param bool             $strict
823 13
   *
824 13
   * @return bool
825 13
   */
826
  public function contains($value, $recursive = false, $strict = true): bool
827
  {
828
    if ($recursive === true) {
829
      return $this->in_array_recursive($value, $this->array, $strict);
830
    }
831
832
    return \in_array($value, $this->array, $strict);
833
  }
834
835
  /**
836 4
   * Check if an (case-insensitive) string is in the current array.
837
   *
838 4
   * @param string $value
839
   * @param bool   $recursive
840
   *
841
   * @return bool
842
   */
843
  public function containsCaseInsensitive($value, $recursive = false): bool
844
  {
845
    if ($recursive === true) {
846
      return $this->in_array_recursive(
847
          UTF8::strtoupper($value),
848
          $this->walk(
849 2
              function (&$val) {
0 ignored issues
show
Documentation introduced by
function (&$val) { $...F8::strtoupper($val); } is of type object<Closure>, but the function expects a object<callable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
850
                $val = UTF8::strtoupper($val);
851 2
              },
852 2
              true
853 2
          )->getArray(),
854 2
          true
855
      );
856
    }
857 2
858 2
    return \in_array(
859 2
        UTF8::strtoupper($value),
860
        $this->walk(
861
            function (&$val) {
0 ignored issues
show
Documentation introduced by
function (&$val) { $...F8::strtoupper($val); } is of type object<Closure>, but the function expects a object<callable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
862
              $val = UTF8::strtoupper($val);
863 1
            },
864 1
            false
865 1
        )->getArray(),
866
        true
867
    );
868 1
  }
869 1
870 1
  /**
871
   * Check if the given key/index exists in the array.
872
   *
873
   * @param string|int|float $key <p>key/index to search for</p>
874
   *
875
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
876
   */
877
  public function containsKey($key): bool
878
  {
879
    return $this->offsetExists($key);
880
  }
881 1
882
  /**
883 1
   * Check if all given needles are present in the array as key/index.
884
   *
885
   * @param array $needles <p>The keys you are searching for.</p>
886
   * @param bool  $recursive
887
   *
888
   * @return bool <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
889
   */
890
  public function containsKeys(array $needles, $recursive = false): bool
891
  {
892
    if ($recursive === true) {
893
      return \count(
894
                 \array_intersect($needles, $this->keys(true)->getArray()),
895 9
                 COUNT_RECURSIVE
896
             )
897 9
             ===
898
             \count(
899
                 $needles,
900
                 COUNT_RECURSIVE
901
             );
902
    }
903
904
    return \count(
905
               \array_intersect($needles, $this->keys()->getArray()),
906
               COUNT_NORMAL
907
           )
908
           ===
909 18
           \count(
910
               $needles,
911 18
               COUNT_NORMAL
912
           );
913
  }
914
915
  /**
916
   * Check if all given needles are present in the array as key/index.
917
   *
918
   * @param array $needles <p>The keys you are searching for.</p>
919
   *
920
   * @return bool <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
921 1
   */
922
  public function containsKeysRecursive(array $needles): bool
923 1
  {
924
    return $this->containsKeys($needles, true);
925 1
  }
926
927
  /**
928
   * alias: for "Arrayy->contains()"
929
   *
930
   * @see Arrayy::contains()
931
   *
932
   * @param string|int|float $value
933
   *
934
   * @return bool
935
   */
936
  public function containsValue($value): bool
937
  {
938
    return $this->contains($value);
939 1
  }
940
941 1
  /**
942
   * alias: for "Arrayy->contains($value, true)"
943
   *
944
   * @see Arrayy::contains()
945
   *
946
   * @param string|int|float $value
947
   *
948
   * @return bool
949
   */
950
  public function containsValueRecursive($value): bool
951 538
  {
952
    return $this->contains($value, true);
953 538
  }
954
955
  /**
956
   * Check if all given needles are present in the array.
957
   *
958
   * @param array $needles
959
   *
960
   * @return bool <p>Returns true if all the given values exists in the array, false otherwise.</p>
961
   */
962
  public function containsValues(array $needles): bool
963 1
  {
964
    return \count(\array_intersect($needles, $this->array), COUNT_NORMAL)
965 1
           ===
966
           \count($needles, COUNT_NORMAL);
967 1
  }
968
969 1
  /**
970
   * Counts all the values of an array
971
   *
972
   * @link http://php.net/manual/en/function.array-count-values.php
973
   *
974
   * @return static <p>
975
   *                (Immutable)
976
   *                An associative Arrayy-object of values from input as
977
   *                keys and their count as value.
978
   *                </p>
979 5
   */
980
  public function countValues(): self
981 5
  {
982
    return new static(\array_count_values($this->array));
983 5
  }
984
985
  /**
986
   * Creates an Arrayy object.
987
   *
988
   * @param mixed $array
989
   *
990
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
991
   */
992
  public static function create($array = []): self
993 4
  {
994
    return new static($array);
995 4
  }
996 4
997
  /**
998 3
   * WARNING: Creates an Arrayy object by reference.
999
   *
1000
   * @param array $array
1001 4
   *
1002
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1003
   */
1004
  public function createByReference(array &$array = []): self
1005
  {
1006
    $array = $this->fallbackForArray($array);
1007
1008
    $this->array = &$array;
1009
1010
    return $this;
1011 5
  }
1012
1013 5
  /**
1014
   * Create an new Arrayy object via JSON.
1015
   *
1016
   * @param string $json
1017
   *
1018
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1019
   */
1020
  public static function createFromJson(string $json)
1021
  {
1022
    $array = UTF8::json_decode($json, true);
1023
1024
    return static::create($array);
1025
  }
1026 8
1027
  /**
1028 8
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
1029 1
   *
1030
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
1031 1
   *
1032 1
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1033
   */
1034
  public static function createFromObject(\ArrayAccess $object)
1035
  {
1036 7
    $array = new static();
1037
    foreach ($object as $key => $value) {
1038
      /** @noinspection OffsetOperationsInspection */
1039
      $array[$key] = $value;
1040 8
    }
1041
1042 8
    return $array;
1043
  }
1044 8
1045 8
  /**
1046
   * Create an new instance filled with values from an object.
1047 8
   *
1048
   * @param object $object
1049
   *
1050 8
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1051
   */
1052
  public static function createFromObjectVars($object): self
1053
  {
1054
    return new static(self::objectToArray($object));
1055
  }
1056
1057
  /**
1058
   * Create an new Arrayy object via string.
1059
   *
1060
   * @param string      $str       <p>The input string.</p>
1061
   * @param string|null $delimiter <p>The boundary string.</p>
1062 1
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1063
   *                               used.</p>
1064 1
   *
1065
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1066
   */
1067
  public static function createFromString(string $str, string $delimiter = null, string $regEx = null)
1068
  {
1069
    if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type null|string 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...
1070
      \preg_match_all($regEx, $str, $array);
1071
1072
      if (!empty($array)) {
1073
        $array = $array[0];
1074
      }
1075
1076
    } else {
1077
      $array = \explode($delimiter, $str);
1078 5
    }
1079
1080 5
    // trim all string in the array
1081
    \array_walk(
1082
        $array,
1083
        function (&$val) {
1084
          /** @noinspection ReferenceMismatchInspection */
1085
          if (\is_string($val)) {
1086 5
            $val = \trim($val);
1087
          }
1088 5
        }
1089
    );
1090
1091
    return static::create($array);
1092
  }
1093
1094
  /**
1095
   * Create an new instance containing a range of elements.
1096
   *
1097
   * @param mixed $low  <p>First value of the sequence.</p>
1098
   * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1099
   * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1100
   *
1101
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1102 5
   */
1103
  public static function createWithRange($low, $high, int $step = 1)
1104 5
  {
1105
    return static::create(\range($low, $high, $step));
1106
  }
1107
1108
  /**
1109
   * Custom sort by index via "uksort".
1110 5
   *
1111
   * @link http://php.net/manual/en/function.uksort.php
1112 5
   *
1113
   * @param \callable $function
1114
   *
1115
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1116
   *
1117
   * @throws \InvalidArgumentException
1118
   */
1119 View Code Duplication
  public function customSortKeys($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1120
  {
1121
    if (!\is_callable($function)) {
1122 12
      throw new \InvalidArgumentException(
1123
          'Passed function must be callable'
1124 12
      );
1125
    }
1126 12
1127
    \uksort($this->array, $function);
1128
1129
    return $this;
1130
  }
1131
1132
  /**
1133
   * Custom sort by value via "usort".
1134
   *
1135
   * @link http://php.net/manual/en/function.usort.php
1136
   *
1137 1
   * @param \callable $function
1138
   *
1139 1
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1140
   *
1141
   * @throws \InvalidArgumentException
1142 1
   */
1143 View Code Duplication
  public function customSortValues($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1144 1
  {
1145
    if (!\is_callable($function)) {
1146 1
      throw new \InvalidArgumentException(
1147
          'Passed function must be callable'
1148 1
      );
1149
    }
1150
1151 1
    \usort($this->array, $function);
1152 1
1153 1
    return $this;
1154 1
  }
1155 1
1156 1
  /**
1157
   * Return values that are only in the current array.
1158 1
   *
1159 1
   * @param array $array
1160
   *
1161
   * @return static <p>(Immutable)</p>
1162 1
   */
1163
  public function diff(array $array = [])
1164
  {
1165
    $result = \array_diff($this->array, $array);
1166 1
1167
    return static::create($result);
1168
  }
1169
1170
  /**
1171
   * Return values that are only in the current multi-dimensional array.
1172
   *
1173
   * @param array      $array
1174
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
1175
   *
1176 8
   * @return static <p>(Immutable)</p>
1177
   */
1178 8
  public function diffRecursive(array $array = [], $helperVariableForRecursion = null)
1179
  {
1180 8
    $result = [];
1181
1182
    if (
1183
        $helperVariableForRecursion !== null
1184
        &&
1185
        \is_array($helperVariableForRecursion)
1186
    ) {
1187
      $arrayForTheLoop = $helperVariableForRecursion;
1188 1
    } else {
1189
      $arrayForTheLoop = $this->array;
1190 1
    }
1191
1192 1
    foreach ($arrayForTheLoop as $key => $value) {
1193 1
      if (\array_key_exists($key, $array)) {
1194
        if (\is_array($value)) {
1195
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
1196
          if (!empty($recursiveDiff)) {
1197
            $result[$key] = $recursiveDiff;
1198
          }
1199
        } elseif ($value != $array[$key]) {
1200
          $result[$key] = $value;
1201
        }
1202
      } else {
1203
        $result[$key] = $value;
1204
      }
1205 4
    }
1206
1207 4
    return static::create($result);
1208
  }
1209 4
1210 4
  /**
1211
   * Return values that are only in the new $array.
1212
   *
1213 4
   * @param array $array
1214
   *
1215
   * @return static <p>(Immutable)</p>
1216
   */
1217
  public function diffReverse(array $array = [])
1218
  {
1219
    $result = \array_diff($array, $this->array);
1220
1221
    return static::create($result);
1222
  }
1223 4
1224
  /**
1225 4
   * Divide an array into two arrays. One with keys and the other with values.
1226 4
   *
1227 3
   * @return static <p>(Immutable)</p>
1228 1
   */
1229 3
  public function divide()
1230
  {
1231
    return static::create(
1232
        [
1233 4
            $this->keys(),
1234
            $this->values(),
1235
        ]
1236
    );
1237
  }
1238
1239
  /**
1240
   * Iterate over the current array and modify the array's value.
1241
   *
1242
   * @param \Closure $closure
1243
   *
1244
   * @return static <p>(Immutable)</p>
1245
   */
1246 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...
1247
  {
1248
    $array = $this->array;
1249
1250
    foreach ($array as $key => $value) {
1251
      $array[$key] = $closure($value, $key);
1252
    }
1253 870
1254
    return static::create($array);
1255 870
  }
1256 867
1257
  /**
1258
   * Check if a value is in the current array using a closure.
1259 11
   *
1260 1
   * @param \Closure $closure
1261
   *
1262
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
1263 10
   */
1264 6
  public function exists(\Closure $closure): bool
1265
  {
1266
    $isExists = false;
1267 9
    foreach ($this->array as $key => $value) {
1268
      if ($closure($value, $key)) {
1269 9
        $isExists = true;
1270
        break;
1271
      }
1272
    }
1273
1274 9
    return $isExists;
1275
  }
1276
1277
  /**
1278 9
   * create a fallback for array
1279
   *
1280
   * 1. use the current array, if it's a array
1281
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
1282
   * 3. fallback to empty array, if there is nothing
1283
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
1284 9
   * 5. call "__toArray()" on object, if the method exists
1285
   * 6. cast a string or object with "__toString()" into an array
1286 9
   * 7. throw a "InvalidArgumentException"-Exception
1287
   *
1288 7
   * @param $array
1289
   *
1290
   * @return array
1291 2
   *
1292 2
   * @throws \InvalidArgumentException
1293
   */
1294
  protected function fallbackForArray(&$array): array
1295
  {
1296
    if (\is_array($array)) {
1297
      return $array;
1298
    }
1299
1300
    if ($array instanceof self) {
1301
      return $array->getArray();
1302
    }
1303
1304 8
    if (!$array) {
1305
      return [];
1306 8
    }
1307 1
1308
    $isObject = \is_object($array);
1309
1310 7
    if ($isObject && $array instanceof \ArrayAccess) {
1311
      /** @noinspection ReferenceMismatchInspection */
1312 7
      return static::createFromObject($array)->getArray();
1313
    }
1314 7
1315 4
    if ($isObject && $array instanceof \ArrayObject) {
1316 4
      return $array->getArrayCopy();
1317
    }
1318
1319 7
    if ($isObject && \method_exists($array, '__toArray')) {
1320
      return (array)$array->__toArray();
1321
    }
1322
1323
    /** @noinspection ReferenceMismatchInspection */
1324
    if (
1325
        \is_string($array)
1326
        ||
1327
        ($isObject && \method_exists($array, '__toString'))
1328
    ) {
1329
      return [(string)$array];
1330
    }
1331
1332
    throw new \InvalidArgumentException(
1333
        'Passed value should be a array'
1334
    );
1335
  }
1336
1337
  /**
1338
   * Fill the array until "$num" with "$default" values.
1339
   *
1340
   * @param int   $num
1341
   * @param mixed $default
1342
   *
1343
   * @return static <p>(Immutable)</p>
1344
   */
1345
  public function fillWithDefaults(int $num, $default = null)
1346
  {
1347
    if ($num < 0) {
1348
      throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1349
    }
1350 9
1351
    $tmpArray = $this->array;
1352 9
1353 1
    $count = \count($tmpArray);
1354
1355
    while ($count < $num) {
1356 9
      $tmpArray[] = $default;
1357
      $count++;
1358 9
    }
1359
1360
    return static::create($tmpArray);
1361
  }
1362
1363
  /**
1364
   * Find all items in an array that pass the truth test.
1365
   *
1366
   * @param \Closure|null $closure [optional] <p>
1367
   *                               The callback function to use
1368
   *                               </p>
1369
   *                               <p>
1370
   *                               If no callback is supplied, all entries of
1371
   *                               input equal to false (see
1372
   *                               converting to
1373
   *                               boolean) will be removed.
1374
   *                               </p>
1375
   *
1376
   *  * @param int $flag [optional] <p>
1377
   *                               Flag determining what arguments are sent to <i>callback</i>:
1378
   *                               </p><ul>
1379
   *                               <li>
1380
   *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1381
   *                               to <i>callback</i> instead of the value</span>
1382
   *                               </li>
1383 1
   *                               <li>
1384
   *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1385 1
   *                               arguments to <i>callback</i> instead of the value</span>
1386 1
   *                               </li>
1387
   *                               </ul>
1388
   *
1389
   * @return static <p>(Immutable)</p>
1390 1
   */
1391 1
  public function filter($closure = null, int $flag = ARRAY_FILTER_USE_BOTH)
1392 1
  {
1393 1
    if (!$closure) {
1394
      return $this->clean();
1395 1
    }
1396 1
1397
    $array = \array_filter($this->array, $closure, $flag);
1398 1
1399 1
    return static::create($array);
1400
  }
1401 1
1402 1
  /**
1403 1
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
1404 1
   * within that.
1405 1
   *
1406
   * @param string          $property
1407 1
   * @param string|string[] $value
1408 1
   * @param string          $comparisonOp
1409
   *                            <p>
1410 1
   *                            'eq' (equals),<br />
1411 1
   *                            'gt' (greater),<br />
1412
   *                            'gte' || 'ge' (greater or equals),<br />
1413 1
   *                            'lt' (less),<br />
1414 1
   *                            'lte' || 'le' (less or equals),<br />
1415 1
   *                            'ne' (not equals),<br />
1416 1
   *                            'contains',<br />
1417 1
   *                            'notContains',<br />
1418
   *                            'newer' (via strtotime),<br />
1419 1
   *                            'older' (via strtotime),<br />
1420 1
   *                            </p>
1421
   *
1422 1
   * @return static <p>(Immutable)</p>
1423 1
   */
1424
  public function filterBy(string $property, $value, string $comparisonOp = null)
1425 1
  {
1426
    if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type null|string 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...
1427
      $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1428 1
    }
1429 1
1430 1
    $ops = [
1431 1
        'eq'          => function ($item, $prop, $value) {
1432 1
          return $item[$prop] === $value;
1433 1
        },
1434 1
        'gt'          => function ($item, $prop, $value) {
1435 1
          return $item[$prop] > $value;
1436
        },
1437 1
        'ge'          => function ($item, $prop, $value) {
1438 1
          return $item[$prop] >= $value;
1439 1
        },
1440
        'gte'         => function ($item, $prop, $value) {
1441 1
          return $item[$prop] >= $value;
1442 1
        },
1443
        'lt'          => function ($item, $prop, $value) {
1444
          return $item[$prop] < $value;
1445
        },
1446 1
        'le'          => function ($item, $prop, $value) {
1447
          return $item[$prop] <= $value;
1448
        },
1449
        'lte'         => function ($item, $prop, $value) {
1450
          return $item[$prop] <= $value;
1451
        },
1452
        'ne'          => function ($item, $prop, $value) {
1453
          return $item[$prop] !== $value;
1454
        },
1455
        'contains'    => function ($item, $prop, $value) {
1456
          return \in_array($item[$prop], (array)$value, true);
1457 8
        },
1458
        'notContains' => function ($item, $prop, $value) {
1459 8
          return !\in_array($item[$prop], (array)$value, true);
1460 6
        },
1461 6
        'newer'       => function ($item, $prop, $value) {
1462
          return \strtotime($item[$prop]) > \strtotime($value);
1463
        },
1464
        'older'       => function ($item, $prop, $value) {
1465 3
          return \strtotime($item[$prop]) < \strtotime($value);
1466
        },
1467
    ];
1468
1469
    $result = \array_values(
1470
        \array_filter(
1471
            (array)$this->array,
1472
            function ($item) use (
1473
                $property,
1474
                $value,
1475
                $ops,
1476
                $comparisonOp
1477
            ) {
1478
              $item = (array)$item;
1479
              $itemArrayy = new Arrayy($item);
1480
              $item[$property] = $itemArrayy->get($property, []);
1481
1482
              return $ops[$comparisonOp]($item, $property, $value);
1483
            }
1484
        )
1485
    );
1486
1487 13
    return static::create($result);
1488
  }
1489 13
1490 13
  /**
1491
   * Find the first item in an array that passes the truth test,
1492 13
   *  otherwise return false
1493 3
   *
1494
   * @param \Closure $closure
1495
   *
1496 10
   * @return mixed|false <p>Return false if we did not find the value.</p>
1497
   */
1498 View Code Duplication
  public function find(\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...
1499
  {
1500
    foreach ($this->array as $key => $value) {
1501
      if ($closure($value, $key)) {
1502
        return $value;
1503
      }
1504
    }
1505
1506 28
    return false;
1507
  }
1508 28
1509 7
  /**
1510 7
   * find by ...
1511
   *
1512 21
   * @param string          $property
1513 21
   * @param string|string[] $value
1514 21
   * @param string          $comparisonOp
1515
   *
1516
   * @return static <p>(Immutable)</p>
1517 28
   */
1518
  public function findBy(string $property, $value, string $comparisonOp = 'eq')
1519
  {
1520
    return $this->filterBy($property, $value, $comparisonOp);
1521
  }
1522
1523
  /**
1524
   * Get the first value from the current array.
1525
   *
1526
   * @return mixed <p>Return null if there wasn't a element.</p>
1527 26
   */
1528
  public function first()
1529 26
  {
1530 11
    $tmpArray = $this->array;
1531
    $result = \array_shift($tmpArray);
1532 15
1533 15
    if ($result === null) {
1534
      return null;
1535
    }
1536 26
1537
    return $result;
1538
  }
1539
1540
  /**
1541
   * Get the first value(s) from the current array.
1542
   *
1543
   * @param int|null $number <p>How many values you will take?</p>
1544 1
   *
1545
   * @return static <p>(Immutable)</p>
1546 1
   */
1547
  public function firstsImmutable(int $number = null)
1548 1
  {
1549
    if ($number === null) {
1550
      $arrayTmp = $this->array;
1551
      $array = (array)\array_shift($arrayTmp);
1552
    } else {
1553
      $number = (int)$number;
1554
      $arrayTmp = $this->array;
1555
      $array = \array_splice($arrayTmp, 0, $number, true);
1556
    }
1557
1558
    return static::create($array);
1559
  }
1560
1561 62
  /**
1562
   * Get the first value(s) from the current array.
1563 62
   *
1564 3
   * @param int|null $number <p>How many values you will take?</p>
1565
   *
1566 59
   * @return static <p>(Mutable)</p>
1567
   */
1568
  public function firstsMutable(int $number = null)
1569 62
  {
1570 1
    if ($number === null) {
1571
      $this->array = (array)\array_shift($this->array);
1572
    } else {
1573
      $number = (int)$number;
1574 62
      $this->array = \array_splice($this->array, 0, $number, true);
1575 2
    }
1576
1577
    return $this;
1578 62
  }
1579 52
1580 6
  /**
1581
   * Exchanges all keys with their associated values in an array.
1582
   *
1583 48
   * @return static <p>(Immutable)</p>
1584
   */
1585
  public function flip()
1586
  {
1587 21
    $result = \array_flip($this->array);
1588 21
1589 20
    return static::create($result);
1590
  }
1591
1592 6
  /**
1593
   * Get a value from an array (optional using dot-notation).
1594
   *
1595 6
   * @param mixed $key       <p>The key to look for.</p>
1596 1
   * @param mixed $fallback  <p>Value to fallback to.</p>
1597
   * @param array $array     <p>The array to get from, if it's set to "null" we use the current array from the
1598
   *                         class.</p>
1599 6
   *
1600
   * @return mixed|static
1601
   */
1602
  public function get($key, $fallback = null, array $array = null)
1603
  {
1604
    if ($array !== null) {
1605
      $usedArray = $array;
1606
    } else {
1607 578
      $usedArray = $this->array;
1608
    }
1609 578
1610
    if ($key === null) {
1611 578
      return static::create($usedArray);
1612
    }
1613
1614
    // php cast "bool"-index into "int"-index
1615
    if ((bool)$key === $key) {
1616
      $key = (int)$key;
1617
    }
1618
1619
    if (\array_key_exists($key, $usedArray) === true) {
1620
      if (\is_array($usedArray[$key])) {
1621
        return static::create($usedArray[$key]);
1622
      }
1623
1624
      return $usedArray[$key];
1625
    }
1626 1
1627
    // Crawl through array, get key according to object or not
1628 1
    foreach (\explode($this->pathSeparator, (string)$key) as $segment) {
1629
      if (!isset($usedArray[$segment])) {
1630 1
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1631
      }
1632
1633
      $usedArray = $usedArray[$segment];
1634
    }
1635
1636
    if (\is_array($usedArray)) {
1637
      return static::create($usedArray);
1638
    }
1639
1640 38
    return $usedArray;
1641
  }
1642 38
1643 10
  /**
1644
   * Get the current array from the "Arrayy"-object.
1645 10
   *
1646 2
   * @return array
1647
   */
1648 8
  public function getArray(): array
1649
  {
1650
    \array_map(['self', 'internalGetArray'], $this->array);
1651
1652
    foreach ($this->array as $key => $item) {
1653 38
      if ($item instanceof self) {
1654
        $this->array[$key] = $item->getArray();
1655 38
      }
1656
    }
1657
1658
    return $this->array;
1659
  }
1660 38
1661
  /**
1662
   * Returns the values from a single column of the input array, identified by
1663
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1664
   *
1665
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1666
   * array by the values from the $indexKey column in the input array.
1667
   *
1668
   * @param mixed $columnKey
1669
   * @param mixed $indexKey
1670 1
   *
1671
   * @return static <p>(Immutable)</p>
1672 1
   */
1673
  public function getColumn($columnKey = null, $indexKey = null)
1674
  {
1675
    $result = \array_column($this->array, $columnKey, $indexKey);
1676
1677
    return static::create($result);
1678
  }
1679
1680 4
  /**
1681
   * Get correct PHP constant for direction.
1682 4
   *
1683
   * @param int|string $direction
1684
   *
1685
   * @return int
1686
   */
1687
  protected function getDirection($direction): int
1688
  {
1689
    if (\is_string($direction)) {
1690
      $direction = \strtolower($direction);
1691
1692 4
      if ($direction === 'desc') {
1693
        $direction = SORT_DESC;
1694 4
      } else {
1695
        $direction = SORT_ASC;
1696
      }
1697
    }
1698
1699
    if (
1700
        $direction !== SORT_DESC
1701
        &&
1702
        $direction !== SORT_ASC
1703
    ) {
1704 3
      $direction = SORT_ASC;
1705
    }
1706 3
1707
    return $direction;
1708
  }
1709
1710
  /**
1711
   * alias: for "Arrayy->keys()"
1712
   *
1713
   * @see Arrayy::keys()
1714
   *
1715
   * @return static <p>(Immutable)</p>
1716
   */
1717
  public function getKeys()
1718 8
  {
1719
    return $this->keys();
1720 8
  }
1721
1722
  /**
1723
   * Get the current array from the "Arrayy"-object as object.
1724
   *
1725
   * @return \stdClass (object)
1726
   */
1727
  public function getObject(): \stdClass
1728
  {
1729
    return self::arrayToObject($this->getArray());
1730 3
  }
1731
1732 3
  /**
1733
   * alias: for "Arrayy->randomImmutable()"
1734
   *
1735
   * @see Arrayy::randomImmutable()
1736
   *
1737
   * @return static <p>(Immutable)</p>
1738
   */
1739
  public function getRandom()
1740
  {
1741
    return $this->randomImmutable();
1742
  }
1743
1744 6
  /**
1745
   * alias: for "Arrayy->randomKey()"
1746 6
   *
1747
   * @see Arrayy::randomKey()
1748
   *
1749
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1750
   */
1751
  public function getRandomKey()
1752
  {
1753
    return $this->randomKey();
1754
  }
1755
1756
  /**
1757 3
   * alias: for "Arrayy->randomKeys()"
1758
   *
1759 3
   * @see Arrayy::randomKeys()
1760 3
   *
1761
   * @param int $number
1762
   *
1763 3
   * @return static <p>(Immutable)</p>
1764
   */
1765 3
  public function getRandomKeys(int $number)
1766 3
  {
1767
    return $this->randomKeys($number);
1768 3
  }
1769
1770
  /**
1771
   * alias: for "Arrayy->randomValue()"
1772 3
   *
1773 3
   * @see Arrayy::randomValue()
1774
   *
1775
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1776
   */
1777 3
  public function getRandomValue()
1778 2
  {
1779 1
    return $this->randomValue();
1780 1
  }
1781
1782 1
  /**
1783 3
   * alias: for "Arrayy->randomValues()"
1784
   *
1785
   * @see Arrayy::randomValues()
1786
   *
1787
   * @param int $number
1788
   *
1789 3
   * @return static <p>(Immutable)</p>
1790
   */
1791
  public function getRandomValues(int $number)
1792
  {
1793
    return $this->randomValues($number);
1794
  }
1795
1796
  /**
1797
   * Group values from a array according to the results of a closure.
1798
   *
1799 23
   * @param \callable $grouper <p>A callable function name.</p>
1800
   * @param bool      $saveKeys
1801 23
   *
1802
   * @return static <p>(Immutable)</p>
1803 23
   */
1804
  public function group($grouper, bool $saveKeys = false)
1805 1
  {
1806
    $array = (array)$this->array;
1807
    $result = [];
1808 23
1809
    // Iterate over values, group by property/results from closure.
1810
    foreach ($array as $key => $value) {
1811
1812
      $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $array);
1813
      $newValue = $this->get($groupKey, null, $result);
1814
1815
      if ($groupKey instanceof self) {
1816
        $groupKey = $groupKey->getArray();
1817
      }
1818 27
1819
      if ($newValue instanceof self) {
1820 27
        $newValue = $newValue->getArray();
1821
      }
1822
1823
      // Add to results.
1824
      if ($groupKey !== null) {
1825
        if ($saveKeys) {
1826
          $result[$groupKey] = $newValue;
1827
          $result[$groupKey][$key] = $value;
1828
        } else {
1829
          $result[$groupKey] = $newValue;
1830 8
          $result[$groupKey][] = $value;
1831
        }
1832 8
      }
1833
1834
    }
1835
1836
    return static::create($result);
1837
  }
1838
1839
  /**
1840
   * Check if an array has a given key.
1841
   *
1842 35
   * @param mixed $key
1843
   *
1844 35
   * @return bool
1845 1
   */
1846
  public function has($key): bool
1847
  {
1848 35
    static $UN_FOUND = null;
1849 35
1850 35
    if ($UN_FOUND === null) {
1851
      // Generate unique string to use as marker.
1852 35
      $UN_FOUND = \uniqid('arrayy', true);
1853 35
    }
1854 35
1855 35
    return $this->get($key, $UN_FOUND) !== $UN_FOUND;
1856 35
  }
1857 35
1858
  /**
1859
   * Implodes the values of this array.
1860
   *
1861
   * @param string $glue
1862 35
   *
1863
   * @return string
1864
   */
1865
  public function implode(string $glue = ''): string
1866
  {
1867
    return $this->implode_recursive($glue, $this->array, false);
1868
  }
1869
1870
  /**
1871
   * Implodes the keys of this array.
1872
   *
1873
   * @param string $glue
1874
   *
1875
   * @return string
1876
   */
1877
  public function implodeKeys(string $glue = ''): string
1878
  {
1879
    return $this->implode_recursive($glue, $this->array, true);
1880
  }
1881
1882
  /**
1883
   * @param mixed               $glue
1884
   * @param string|array|static $pieces
1885 44
   * @param bool                $useKeys
1886
   *
1887 44
   * @return string
1888
   */
1889
  protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
1890
  {
1891 44
    if ($pieces instanceof self) {
1892
      $pieces = $pieces->getArray();
1893 36
    }
1894 8
1895
    if (\is_array($pieces)) {
1896 36
      $pieces_count = \count($pieces, COUNT_NORMAL);
1897
      $pieces_count_not_zero = $pieces_count > 0;
1898
1899 36
      return \implode(
1900 36
          $glue,
1901
          \array_map(
1902
              [$this, 'implode_recursive'],
1903
              \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
1904 18
              ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
1905
          )
1906
      );
1907
    }
1908
1909
    return (string)$pieces;
1910
  }
1911
1912
  /**
1913
   * @param mixed $needle   <p>
1914
   *                        The searched value.
1915
   *                        </p>
1916 3
   *                        <p>
1917
   *                        If needle is a string, the comparison is done
1918 3
   *                        in a case-sensitive manner.
1919
   *                        </p>
1920 3
   * @param array $haystack <p>
1921 3
   *                        The array.
1922 3
   *                        </p>
1923
   * @param bool  $strict   [optional] <p>
1924
   *                        If the third parameter strict is set to true
1925
   *                        then the in_array function will also check the
1926 3
   *                        types of the
1927
   *                        needle in the haystack.
1928
   *                        </p>
1929
   *
1930
   * @return bool true if needle is found in the array, false otherwise.
1931
   */
1932
  protected function in_array_recursive($needle, array $haystack = null, $strict = true): bool
1933
  {
1934
    if ($haystack === null) {
1935
      $haystack = $this->array;
1936
    }
1937
1938 4
    foreach ($haystack as $item) {
1939
1940 4
      if (\is_array($item) === true) {
1941
        $returnTmp = $this->in_array_recursive($needle, $item, $strict);
1942
      } else {
1943
        $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
1944
      }
1945
1946
      if ($returnTmp === true) {
1947
        return true;
1948
      }
1949
    }
1950 12
1951
    return false;
1952 12
  }
1953
1954
  /**
1955
   * Given a list and an iterate-function that returns
1956
   * a key for each element in the list (or a property name),
1957
   * returns an object with an index of each item.
1958 476
   *
1959
   * @param mixed $key
1960 476
   *
1961
   * @return static <p>(Immutable)</p>
1962
   */
1963
  public function indexBy($key)
1964
  {
1965
    $results = [];
1966
1967
    foreach ($this->array as $a) {
1968
      if (\array_key_exists($key, $a) === true) {
1969
        $results[$a[$key]] = $a;
1970 476
      }
1971
    }
1972
1973
    return static::create($results);
1974 476
  }
1975
1976
  /**
1977
   * alias: for "Arrayy->searchIndex()"
1978
   *
1979
   * @see Arrayy::searchIndex()
1980
   *
1981
   * @param mixed $value <p>The value to search for.</p>
1982
   *
1983 18
   * @return mixed
1984
   */
1985 18
  public function indexOf($value)
1986
  {
1987
    return $this->searchIndex($value);
1988 18
  }
1989
1990
  /**
1991
   * Get everything but the last..$to items.
1992
   *
1993
   * @param int $to
1994
   *
1995
   * @return static <p>(Immutable)</p>
1996
   */
1997
  public function initial(int $to = 1)
1998 18
  {
1999
    return $this->firstsImmutable(\count($this->array, COUNT_NORMAL) - $to);
2000 18
  }
2001
2002 18
  /**
2003
   * @param mixed $value
2004
   */
2005
  protected function internalGetArray(&$value)
2006
  {
2007
    if ($value instanceof self) {
2008
2009
      $valueTmp = $value->getArray();
2010
      if (\count($valueTmp, COUNT_NORMAL) === 0) {
2011
        $value = [];
2012
      } else {
2013 30
        /** @noinspection PhpUnusedLocalVariableInspection */
2014
        $value = &$valueTmp;
2015 30
      }
2016
2017
    } elseif ($value instanceof \JsonSerializable) {
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

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

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

2. Missing use statement

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

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

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

Loading history...
2018
      /** @noinspection PhpUnusedLocalVariableInspection */
2019
      $value = &$value->jsonSerialize();
2020 30
    }
2021 30
  }
2022
2023
  /**
2024 30
   * Internal mechanics of remove method.
2025 3
   *
2026
   * @param mixed $key
2027
   *
2028
   * @return bool
2029
   */
2030 3
  protected function internalRemove($key): bool
2031
  {
2032
    $path = \explode($this->pathSeparator, (string)$key);
2033
2034 3
    // Crawl though the keys
2035
    while (\count($path, COUNT_NORMAL) > 1) {
2036
      $key = \array_shift($path);
2037 30
2038
      if (!$this->has($key)) {
2039 30
        return false;
2040
      }
2041
2042
      $this->array = &$this->array[$key];
2043
    }
2044
2045
    $key = \array_shift($path);
2046
2047
    unset($this->array[$key]);
2048
2049 2
    return true;
2050
  }
2051 2
2052
  /**
2053
   * Internal mechanic of set method.
2054
   *
2055
   * @param mixed $key
2056
   * @param mixed $value
2057
   *
2058
   * @return bool
2059
   */
2060
  protected function internalSet($key, $value): bool
2061 1
  {
2062
    if ($key === null) {
2063 1
      return false;
2064
    }
2065
2066
    // init
2067
    $array =& $this->array;
2068
    $path = \explode($this->pathSeparator, (string)$key);
2069
2070
    // Crawl through the keys
2071
    while (\count($path, COUNT_NORMAL) > 1) {
2072
      $key = \array_shift($path);
2073
2074 1
      $array =& $array[$key];
2075
    }
2076
2077 1
    $array[\array_shift($path)] = $value;
2078 1
2079 1
    return true;
2080 1
  }
2081 1
2082
  /**
2083
   * Return an array with all elements found in input array.
2084
   *
2085 1
   * @param array $search
2086 1
   *
2087
   * @return static <p>(Immutable)</p>
2088 1
   */
2089
  public function intersection(array $search)
2090
  {
2091 1
    return static::create(\array_values(\array_intersect($this->array, $search)));
2092
  }
2093
2094
  /**
2095
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
2096
   *
2097
   * @param array $search
2098
   *
2099
   * @return bool
2100
   */
2101 15
  public function intersects(array $search): bool
2102
  {
2103 15
    return \count($this->intersection($search)->array, COUNT_NORMAL) > 0;
2104 3
  }
2105
2106
  /**
2107 13
   * Invoke a function on all of an array's values.
2108 13
   *
2109 13
   * @param mixed $callable
2110
   * @param mixed $arguments
2111
   *
2112
   * @return static <p>(Immutable)</p>
2113 3
   */
2114
  public function invoke($callable, $arguments = [])
2115
  {
2116
    // If one argument given for each iteration, create an array for it.
2117
    if (!\is_array($arguments)) {
2118
      $arguments = StaticArrayy::repeat(
2119
          $arguments,
2120
          \count($this->array, COUNT_NORMAL)
2121 88
      )->getArray();
2122
    }
2123 88
2124
    // If the callable has arguments, pass them.
2125
    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...
2126
      $array = \array_map($callable, $this->array, $arguments);
2127
    } else {
2128
      $array = \array_map($callable, $this->array);
2129
    }
2130
2131
    return static::create($array);
2132
  }
2133
2134
  /**
2135
   * Check whether array is associative or not.
2136
   *
2137
   * @param bool $recursive
2138
   *
2139
   * @return bool <p>Returns true if associative, false otherwise.</p>
2140
   */
2141
  public function isAssoc(bool $recursive = false): bool
2142
  {
2143 14
    if ($this->isEmpty()) {
2144
      return false;
2145
    }
2146 14
2147
    foreach ($this->keys($recursive)->getArray() as $key) {
2148 14
      if (!\is_string($key)) {
2149
        return false;
2150
      }
2151
    }
2152
2153
    return true;
2154
  }
2155
2156
  /**
2157 5
   * Check whether the array is empty or not.
2158
   *
2159 5
   * @return bool <p>Returns true if empty, false otherwise.</p>
2160 2
   */
2161
  public function isEmpty(): bool
2162
  {
2163 4
    return !$this->array;
2164 4
  }
2165 4
2166
  /**
2167
   * Check if the current array is equal to the given "$array" or not.
2168
   *
2169 2
   * @param array $array
2170
   *
2171
   * @return bool
2172
   */
2173
  public function isEqual(array $array): bool
2174
  {
2175
    return ($this->array === $array);
2176
  }
2177
2178
  /**
2179 1
   * Check if the current array is a multi-array.
2180
   *
2181
   * @return bool
2182
   */
2183
  public function isMultiArray(): bool
2184 1
  {
2185
    return !(
2186
        \count($this->array, COUNT_NORMAL)
2187
        ===
2188
        \count($this->array, COUNT_RECURSIVE)
2189
    );
2190
  }
2191
2192 1
  /**
2193
   * Check whether array is numeric or not.
2194 1
   *
2195
   * @return bool <p>Returns true if numeric, false otherwise.</p>
2196
   */
2197
  public function isNumeric(): bool
2198
  {
2199
    if ($this->isEmpty()) {
2200
      return false;
2201
    }
2202
2203
    foreach ($this->keys() as $key) {
2204
      if (!\is_int($key)) {
2205
        return false;
2206
      }
2207
    }
2208
2209
    return true;
2210
  }
2211
2212
  /**
2213
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2214
   *
2215
   * @param bool $recursive
2216
   *
2217
   * @return bool
2218
   */
2219
  public function isSequential(bool $recursive = false): bool
2220 26
  {
2221
2222
    // recursive
2223
2224
    if ($recursive === true) {
2225 26
      return $this->array_keys_recursive($this->array)
2226 3
             ===
2227 3
             \range(0, \count($this->array, COUNT_RECURSIVE) - 1);
2228
    }
2229
2230
    // non recursive
2231
2232 3
    return \array_keys($this->array)
2233
           ===
2234
           \range(0, \count($this->array, COUNT_NORMAL) - 1);
2235
  }
2236
2237 25
  /**
2238 25
   * @return array
2239
   */
2240
  public function jsonSerialize(): array
2241
  {
2242
    return $this->getArray();
2243 25
  }
2244
2245
  /**
2246
   * Get all keys from the current array.
2247
   *
2248
   * @param bool  $recursive    [optional] <p>
2249
   *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2250
   *                            </p>
2251
   * @param mixed $search_value [optional] <p>
2252
   *                            If specified, then only keys containing these values are returned.
2253
   *                            </p>
2254
   * @param bool  $strict       [optional] <p>
2255
   *                            Determines if strict comparison (===) should be used during the search.
2256
   *                            </p>
2257 4
   *
2258
   * @return static <p>(Immutable) An array of all the keys in input.</p>
2259 4
   */
2260
  public function keys(bool $recursive = false, $search_value = null, bool $strict = true)
2261 4
  {
2262
2263
    // recursive
2264
2265
    if ($recursive === true) {
2266
      if ($search_value === null) {
2267
        $array = $this->array_keys_recursive($this->array);
2268
      } else {
2269 4
        $array = $this->array_keys_recursive($this->array, $search_value, $strict);
2270
      }
2271 4
2272
      return static::create($array);
2273
    }
2274
2275
    // non recursive
2276
2277
    if ($search_value === null) {
2278
      $array = \array_keys($this->array);
2279
    } else {
2280
      $array = \array_keys($this->array, $search_value, $strict);
2281 13
    }
2282
2283 13
    return static::create($array);
2284 1
  }
2285
2286
  /**
2287 12
   * Sort an array by key in reverse order.
2288 8
   *
2289
   * @param int $sort_flags [optional] <p>
2290 8
   *                        You may modify the behavior of the sort using the optional
2291 1
   *                        parameter sort_flags, for details
2292
   *                        see sort.
2293 7
   *                        </p>
2294
   *
2295
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2296 8
   */
2297
  public function krsort(int $sort_flags = 0)
2298 4
  {
2299 4
    krsort($this->array, $sort_flags);
2300
2301
    return $this;
2302 12
  }
2303
2304
  /**
2305
   * Get the last value from the current array.
2306
   *
2307
   * @return mixed <p>Return null if there wasn't a element.</p>
2308
   */
2309
  public function last()
2310
  {
2311
    return $this->pop();
2312 13
  }
2313
2314 13
  /**
2315 1
   * Get the last value(s) from the current array.
2316
   *
2317
   * @param int|null $number
2318 12
   *
2319 8
   * @return static <p>(Immutable)</p>
2320
   */
2321 8
  public function lastsImmutable(int $number = null)
2322 1
  {
2323
    if ($this->isEmpty()) {
2324 7
      return static::create();
2325
    }
2326
2327 8
    if ($number === null) {
2328
      $poppedValue = $this->pop();
2329 4
2330 4
      if ($poppedValue === null) {
2331
        $poppedValue = [$poppedValue];
2332
      } else {
2333 12
        $poppedValue = (array)$poppedValue;
2334
      }
2335
2336
      $arrayy = static::create($poppedValue);
2337
    } else {
2338
      $number = (int)$number;
2339
      $arrayy = $this->rest(-$number);
2340
    }
2341
2342
    return $arrayy;
2343
  }
2344
2345
  /**
2346
   * Get the last value(s) from the current array.
2347 20
   *
2348
   * @param int|null $number
2349 20
   *
2350
   * @return static <p>(Mutable)</p>
2351
   */
2352
  public function lastsMutable(int $number = null)
2353
  {
2354
    if ($this->isEmpty()) {
2355
      return $this;
2356
    }
2357
2358
    if ($number === null) {
2359
      $poppedValue = $this->pop();
2360 4
2361
      if ($poppedValue === null) {
2362 4
        $poppedValue = [$poppedValue];
2363
      } else {
2364 4
        $poppedValue = (array)$poppedValue;
2365
      }
2366
2367
      $this->array = static::create($poppedValue)->array;
2368
    } else {
2369
      $number = (int)$number;
2370
      $this->array = $this->rest(-$number)->array;
2371
    }
2372
2373
    return $this;
2374 15
  }
2375
2376 15
  /**
2377 2
   * Count the values from the current array.
2378
   *
2379
   * alias: for "Arrayy->count()"
2380
   *
2381 13
   * @see Arrayy::count()
2382
   *
2383 13
   * @param int $mode
2384 13
   *
2385
   * @return int
2386 13
   */
2387 13
  public function length(int $mode = COUNT_NORMAL): int
2388
  {
2389
    return $this->count($mode);
2390
  }
2391 7
2392
  /**
2393
   * Apply the given function to the every element of the array,
2394
   * collecting the results.
2395
   *
2396
   * @param \callable $callable
2397
   *
2398
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
2399
   */
2400
  public function map($callable)
2401 14
  {
2402
    $result = \array_map($callable, $this->array);
2403 14
2404 2
    return static::create($result);
2405
  }
2406
2407
  /**
2408 12
   * Check if all items in current array match a truth test.
2409
   *
2410 12
   * @param \Closure $closure
2411 12
   *
2412
   * @return bool
2413 12
   */
2414 12 View Code Duplication
  public function matches(\Closure $closure): bool
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...
2415
  {
2416
    if (\count($this->array, COUNT_NORMAL) === 0) {
2417
      return false;
2418 4
    }
2419
2420
    // init
2421
    $array = $this->array;
2422
2423
    foreach ($array as $key => $value) {
2424
      $value = $closure($value, $key);
2425
2426 10
      if ($value === false) {
2427
        return false;
2428 10
      }
2429 1
    }
2430
2431
    return true;
2432 9
  }
2433
2434
  /**
2435
   * Check if any item in the current array matches a truth test.
2436
   *
2437
   * @param \Closure $closure
2438
   *
2439
   * @return bool
2440
   */
2441 View Code Duplication
  public function matchesAny(\Closure $closure): bool
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...
2442
  {
2443
    if (\count($this->array, COUNT_NORMAL) === 0) {
2444
      return false;
2445 25
    }
2446
2447 25
    // init
2448 4
    $array = $this->array;
2449
2450 21
    foreach ($array as $key => $value) {
2451
      $value = $closure($value, $key);
2452
2453 25
      if ($value === true) {
2454
        return true;
2455
      }
2456
    }
2457
2458
    return false;
2459
  }
2460
2461
  /**
2462
   * Get the max value from an array.
2463
   *
2464
   * @return mixed
2465
   */
2466 View Code Duplication
  public function max()
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...
2467 16
  {
2468
    if (\count($this->array, COUNT_NORMAL) === 0) {
2469 16
      return false;
2470 4
    }
2471
2472 12
    return max($this->array);
2473
  }
2474
2475 16
  /**
2476
   * Merge the new $array into the current array.
2477
   *
2478
   * - keep key,value from the current array, also if the index is in the new $array
2479
   *
2480
   * @param array $array
2481
   * @param bool  $recursive
2482
   *
2483
   * @return static <p>(Immutable)</p>
2484
   */
2485 View Code Duplication
  public function mergeAppendKeepIndex(array $array = [], bool $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...
2486
  {
2487
    if (true === $recursive) {
2488 16
      $result = \array_replace_recursive($this->array, $array);
2489
    } else {
2490 16
      $result = \array_replace($this->array, $array);
2491 4
    }
2492
2493 12
    return static::create($result);
2494
  }
2495
2496 16
  /**
2497
   * Merge the new $array into the current array.
2498
   *
2499
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2500
   * - create new indexes
2501
   *
2502
   * @param array $array
2503
   * @param bool  $recursive
2504
   *
2505
   * @return static <p>(Immutable)</p>
2506
   */
2507 View Code Duplication
  public function mergeAppendNewIndex(array $array = [], bool $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...
2508
  {
2509
    if (true === $recursive) {
2510 17
      $result = \array_merge_recursive($this->array, $array);
2511
    } else {
2512 17
      $result = \array_merge($this->array, $array);
2513 4
    }
2514
2515 13
    return static::create($result);
2516
  }
2517
2518 17
  /**
2519
   * Merge the the current array into the $array.
2520
   *
2521
   * - use key,value from the new $array, also if the index is in the current array
2522
   *
2523
   * @param array $array
2524
   * @param bool  $recursive
2525
   *
2526 10
   * @return static <p>(Immutable)</p>
2527
   */
2528 10 View Code Duplication
  public function mergePrependKeepIndex(array $array = [], bool $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...
2529 1
  {
2530
    if (true === $recursive) {
2531
      $result = \array_replace_recursive($array, $this->array);
2532 9
    } else {
2533
      $result = \array_replace($array, $this->array);
2534
    }
2535
2536
    return static::create($result);
2537
  }
2538
2539
  /**
2540
   * Merge the current array into the new $array.
2541
   *
2542
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
2543
   * - create new indexes
2544
   *
2545 1
   * @param array $array
2546
   * @param bool  $recursive
2547 1
   *
2548
   * @return static <p>(Immutable)</p>
2549 1
   */
2550 1 View Code Duplication
  public function mergePrependNewIndex(array $array = [], bool $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...
2551 1
  {
2552 1
    if (true === $recursive) {
2553 1
      $result = \array_merge_recursive($array, $this->array);
2554 1
    } else {
2555 1
      $result = \array_merge($array, $this->array);
2556 1
    }
2557 1
2558 1
    return static::create($result);
2559 1
  }
2560 1
2561 1
  /**
2562
   * Get the min value from an array.
2563 1
   *
2564 1
   * @return mixed
2565
   */
2566 View Code Duplication
  public function min()
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...
2567
  {
2568
    if (\count($this->array, COUNT_NORMAL) === 0) {
2569
      return false;
2570 1
    }
2571
2572
    return min($this->array);
2573
  }
2574
2575
  /**
2576
   * Move an array element to a new index.
2577
   *
2578
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2579
   *
2580 5
   * @param int|string $from
2581
   * @param int|string $to
2582 5
   *
2583 4
   * @return static <p>(Immutable)</p>
2584
   */
2585
  public function moveElement($from, $to)
2586 5
  {
2587 5
    $array = $this->array;
2588
2589
    if (\is_int($from)) {
2590 5
      $tmp = \array_splice($array, $from, 1);
2591
      \array_splice($array, $to, 0, $tmp);
2592
      $output = $array;
2593
    } elseif (\is_string($from)) {
2594
      $indexToMove = \array_search($from, \array_keys($array), true);
2595
      $itemToMove = $array[$from];
2596
      \array_splice($array, $indexToMove, 1);
2597
      $i = 0;
2598
      $output = [];
2599
      foreach ($array as $key => $item) {
2600
        if ($i == $to) {
2601
          $output[$from] = $itemToMove;
2602
        }
2603
        $output[$key] = $item;
2604
        $i++;
2605
      }
2606
    } else {
2607
      $output = [];
2608
    }
2609
2610
    return static::create($output);
2611
  }
2612
2613
  /**
2614
   * Convert a object into an array.
2615 4
   *
2616
   * @param object $object
2617 4
   *
2618
   * @return mixed
2619 4
   */
2620
  protected static function objectToArray($object)
2621
  {
2622
    if (!\is_object($object)) {
2623
      return $object;
2624
    }
2625
2626
    if (\is_object($object)) {
2627 16
      $object = \get_object_vars($object);
2628
    }
2629 16
2630
    return \array_map(['self', 'objectToArray'], $object);
2631
  }
2632
2633
  /**
2634
   * Get a subset of the items from the given array.
2635
   *
2636
   * @param mixed[] $keys
2637
   *
2638
   * @return static <p>(Immutable)</p>
2639
   */
2640 8
  public function only(array $keys)
2641
  {
2642 8
    $array = $this->array;
2643 8
2644
    return static::create(\array_intersect_key($array, \array_flip($keys)));
2645
  }
2646 1
2647
  /**
2648
   * Pad array to the specified size with a given value.
2649 8
   *
2650
   * @param int   $size  <p>Size of the result array.</p>
2651
   * @param mixed $value <p>Empty value by default.</p>
2652
   *
2653
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
2654
   */
2655
  public function pad(int $size, $value)
2656
  {
2657
    $result = \array_pad($this->array, $size, $value);
2658
2659 10
    return static::create($result);
2660
  }
2661 10
2662 10
  /**
2663 9
   * Pop a specified value off the end of the current array.
2664
   *
2665 9
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
2666
   */
2667
  public function pop()
2668 9
  {
2669
    return \array_pop($this->array);
2670
  }
2671
2672
  /**
2673 10
   * Prepend a (key) + value to the current array.
2674
   *
2675
   * @param mixed $value
2676
   * @param mixed $key
2677
   *
2678
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2679
   */
2680
  public function prepend($value, $key = null)
2681
  {
2682
    if ($key === null) {
2683 10
      \array_unshift($this->array, $value);
2684
    } else {
2685 10
      /** @noinspection AdditionOperationOnArraysInspection */
2686 10
      $this->array = [$key => $value] + $this->array;
2687 9
    }
2688
2689 9
    return $this;
2690
  }
2691 9
2692 1
  /**
2693
   * Add a suffix to each key.
2694 9
   *
2695
   * @param mixed $suffix
2696
   *
2697
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2698 10
   */
2699 View Code Duplication
  public function prependToEachKey($suffix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2700
  {
2701
    $result = [];
2702
    foreach ($this->array as $key => $item) {
2703
      if ($item instanceof self) {
2704
        $result[$key] = $item->prependToEachKey($suffix);
2705
      } elseif (\is_array($item)) {
2706 4
        $result[$key] = self::create($item)->prependToEachKey($suffix)->toArray();
2707
      } else {
2708 4
        $result[$key . $suffix] = $item;
2709 4
      }
2710 4
2711
    }
2712
2713 4
    return self::create($result);
2714
  }
2715
2716
  /**
2717
   * Add a suffix to each value.
2718
   *
2719
   * @param mixed $suffix
2720
   *
2721
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2722
   */
2723 18 View Code Duplication
  public function prependToEachValue($suffix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2724
  {
2725 18
    $result = [];
2726 1
    foreach ($this->array as $key => $item) {
2727
      if ($item instanceof self) {
2728
        $result[$key] = $item->prependToEachValue($suffix);
2729 17
      } elseif (\is_array($item)) {
2730 14
        $result[$key] = self::create($item)->prependToEachValue($suffix)->toArray();
2731
      } elseif (\is_object($item)) {
2732 14
        $result[$key] = $item;
2733
      } else {
2734
        $result[$key] = $item . $suffix;
2735 5
      }
2736 5
    }
2737
2738 5
    return self::create($result);
2739
  }
2740
2741
  /**
2742
   * Push one or more values onto the end of array at once.
2743
   *
2744
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2745
   */
2746 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...
2747
  {
2748 4
    if (\func_num_args()) {
2749
      $args = \array_merge([&$this->array], \func_get_args());
2750 4
      \array_push(...$args);
2751
    }
2752 4
2753
    return $this;
2754
  }
2755
2756 4
  /**
2757
   * Get a random value from the current array.
2758
   *
2759
   * @param null|int $number <p>How many values you will take?</p>
2760
   *
2761
   * @return static <p>(Immutable)</p>
2762
   */
2763
  public function randomImmutable(int $number = null)
2764
  {
2765
    if (\count($this->array, COUNT_NORMAL) === 0) {
2766
      return static::create();
2767
    }
2768 13
2769 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...
2770 13
      /** @noinspection NonSecureArrayRandUsageInspection */
2771
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2772 13
2773 2
      return static::create($arrayRandValue);
2774 2
    }
2775 2
2776 2
    $arrayTmp = $this->array;
2777 2
    /** @noinspection NonSecureShuffleUsageInspection */
2778
    \shuffle($arrayTmp);
2779
2780
    return static::create($arrayTmp)->firstsImmutable($number);
2781
  }
2782 11
2783
  /**
2784 11
   * Pick a random key/index from the keys of this array.
2785
   *
2786
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
2787
   *
2788
   * @throws \RangeException If array is empty
2789
   */
2790
  public function randomKey()
2791
  {
2792
    $result = $this->randomKeys(1);
2793
2794 17
    if (!isset($result[0])) {
2795
      $result[0] = null;
2796 17
    }
2797
2798
    return $result[0];
2799
  }
2800 17
2801 7
  /**
2802 7
   * Pick a given number of random keys/indexes out of this array.
2803
   *
2804 7
   * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2805
   *
2806
   * @return static <p>(Immutable)</p>
2807 11
   *
2808
   * @throws \RangeException If array is empty
2809 11
   */
2810
  public function randomKeys(int $number)
2811
  {
2812
    $count = \count($this->array, COUNT_NORMAL);
2813
2814
    if ($number === 0 || $number > $count) {
2815
      throw new \RangeException(
2816
          \sprintf(
2817 4
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2818
              $number,
2819 4
              $count
2820
          )
2821 4
      );
2822
    }
2823
2824
    $result = (array)\array_rand($this->array, $number);
2825 4
2826
    return static::create($result);
2827
  }
2828
2829
  /**
2830
   * Get a random value from the current array.
2831
   *
2832
   * @param null|int $number <p>How many values you will take?</p>
2833
   *
2834
   * @return static <p>(Mutable)</p>
2835 7
   */
2836
  public function randomMutable(int $number = null)
2837 7
  {
2838
    if (\count($this->array, COUNT_NORMAL) === 0) {
2839
      return static::create();
2840
    }
2841
2842 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...
2843
      /** @noinspection NonSecureArrayRandUsageInspection */
2844
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2845
      $this->array = $arrayRandValue;
2846
2847
      return $this;
2848
    }
2849
2850 9
    /** @noinspection NonSecureShuffleUsageInspection */
2851
    \shuffle($this->array);
2852 9
2853 9
    return $this->firstsMutable($number);
2854 9
  }
2855 9
2856 1
  /**
2857
   * Pick a random value from the values of this array.
2858
   *
2859
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2860
   */
2861 9
  public function randomValue()
2862
  {
2863
    $result = $this->randomImmutable();
2864
2865
    if (!isset($result[0])) {
2866
      $result[0] = null;
2867
    }
2868
2869
    return $result[0];
2870
  }
2871
2872 4
  /**
2873
   * Pick a given number of random values out of this array.
2874 4
   *
2875
   * @param int $number
2876 4
   *
2877
   * @return static <p>(Mutable)</p>
2878
   */
2879 4
  public function randomValues(int $number)
2880
  {
2881
    return $this->randomMutable($number);
2882 4
  }
2883
2884
  /**
2885
   * Get a random value from an array, with the ability to skew the results.
2886
   *
2887
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2888
   *
2889
   * @param array    $array
2890 9
   * @param null|int $number <p>How many values you will take?</p>
2891
   *
2892 9
   * @return static <p>(Immutable)</p>
2893
   */
2894 9
  public function randomWeighted(array $array, int $number = null)
2895
  {
2896
    $options = [];
2897
    foreach ($array as $option => $weight) {
2898
      if ($this->searchIndex($option) !== false) {
2899
        for ($i = 0; $i < $weight; ++$i) {
2900
          $options[] = $option;
2901
        }
2902
      }
2903
    }
2904 1
2905
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2906 1
  }
2907
2908 1
  /**
2909 1
   * Reduce the current array via callable e.g. anonymous-function.
2910 1
   *
2911
   * @param \callable $callable
2912
   * @param array     $init
2913
   *
2914 1
   * @return static <p>(Immutable)</p>
2915
   */
2916
  public function reduce($callable, array $init = [])
2917
  {
2918
    $result = \array_reduce($this->array, $callable, $init);
2919
2920
    if ($result === null) {
2921
      $this->array = [];
2922
    } else {
2923
      $this->array = (array)$result;
2924 18
    }
2925
2926
    return static::create($this->array);
2927 18
  }
2928
2929
  /**
2930
   * Create a numerically re-indexed Arrayy object.
2931
   *
2932
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2933
   */
2934
  public function reindex()
2935 18
  {
2936
    $this->array = \array_values($this->array);
2937 18
2938
    return $this;
2939
  }
2940
2941
  /**
2942
   * Return all items that fail the truth test.
2943
   *
2944
   * @param \Closure $closure
2945 7
   *
2946
   * @return static <p>(Immutable)</p>
2947 7
   */
2948 7 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...
2949
  {
2950 7
    $filtered = [];
2951
2952
    foreach ($this->array as $key => $value) {
2953
      if (!$closure($value, $key)) {
2954
        $filtered[$key] = $value;
2955
      }
2956
    }
2957
2958 7
    return static::create($filtered);
2959
  }
2960 7
2961 7
  /**
2962
   * Remove a value from the current array (optional using dot-notation).
2963 7
   *
2964
   * @param mixed $key
2965
   *
2966
   * @return static <p>(Immutable)</p>
2967
   */
2968
  public function remove($key)
2969
  {
2970
    // recursive call
2971
    if (\is_array($key)) {
2972
      foreach ($key as $k) {
2973 7
        $this->internalRemove($k);
2974
      }
2975 7
2976 7
      return static::create($this->array);
2977 6
    }
2978 6
2979
    $this->internalRemove($key);
2980
2981 6
    return static::create($this->array);
2982
  }
2983
2984
  /**
2985 7
   * Remove the first value from the current array.
2986 7
   *
2987
   * @return static <p>(Immutable)</p>
2988
   */
2989 7
  public function removeFirst()
2990
  {
2991
    $tmpArray = $this->array;
2992
    \array_shift($tmpArray);
2993
2994
    return static::create($tmpArray);
2995
  }
2996
2997
  /**
2998
   * Remove the last value from the current array.
2999 1
   *
3000
   * @return static <p>(Immutable)</p>
3001 1
   */
3002 1
  public function removeLast()
3003
  {
3004
    $tmpArray = $this->array;
3005 1
    \array_pop($tmpArray);
3006
3007
    return static::create($tmpArray);
3008
  }
3009
3010
  /**
3011
   * Removes a particular value from an array (numeric or associative).
3012
   *
3013
   * @param mixed $value
3014
   *
3015
   * @return static <p>(Immutable)</p>
3016
   */
3017 2
  public function removeValue($value)
3018
  {
3019 2
    $isNumericArray = true;
3020
    foreach ($this->array as $key => $item) {
3021 2
      if ($item === $value) {
3022
        if (!\is_int($key)) {
3023
          $isNumericArray = false;
3024
        }
3025
        unset($this->array[$key]);
3026
      }
3027
    }
3028
3029
    if ($isNumericArray) {
3030
      $this->array = \array_values($this->array);
3031 2
    }
3032
3033 2
    return static::create($this->array);
3034
  }
3035 2
3036
  /**
3037
   * Generate array of repeated arrays.
3038
   *
3039
   * @param int $times <p>How many times has to be repeated.</p>
3040
   *
3041
   * @return Arrayy
3042
   */
3043
  public function repeat($times): self
3044
  {
3045 2
    if ($times === 0) {
3046
      return new static();
3047 2
    }
3048
3049 2
    return static::create(\array_fill(0, (int)$times, $this->array));
3050
  }
3051
3052
  /**
3053
   * Replace a key with a new key/value pair.
3054
   *
3055
   * @param mixed $replace
3056
   * @param mixed $key
3057
   * @param mixed $value
3058
   *
3059 1
   * @return static <p>(Immutable)</p>
3060
   */
3061 1
  public function replace($replace, $key, $value)
3062 1
  {
3063
    $this->remove($replace);
3064 1
3065
    return $this->set($key, $value);
3066
  }
3067
3068
  /**
3069
   * Create an array using the current array as values and the other array as keys.
3070
   *
3071
   * @param array $keys <p>An array of keys.</p>
3072
   *
3073
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
3074
   */
3075 3
  public function replaceAllKeys(array $keys)
3076
  {
3077 3
    $result = \array_combine($keys, $this->array);
3078 3
3079
    return static::create($result);
3080 3
  }
3081 3
3082
  /**
3083
   * Create an array using the current array as keys and the other array as values.
3084 3
   *
3085
   * @param array $array <p>An array o values.</p>
3086
   *
3087
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
3088
   */
3089
  public function replaceAllValues(array $array)
3090
  {
3091
    $result = \array_combine($this->array, $array);
3092
3093
    return static::create($result);
3094
  }
3095 1
3096
  /**
3097 1
   * Replace the keys in an array with another set.
3098 1
   *
3099 1
   * @param array $keys <p>An array of keys matching the array's size</p>
3100 1
   *
3101
   * @return static <p>(Immutable)</p>
3102
   */
3103 1
  public function replaceKeys(array $keys)
3104
  {
3105
    $values = \array_values($this->array);
3106
    $result = \array_combine($keys, $values);
3107
3108
    return static::create($result);
3109
  }
3110
3111
  /**
3112
   * Replace the first matched value in an array.
3113 15
   *
3114
   * @param mixed $search      <p>The value to replace.</p>
3115 15
   * @param mixed $replacement <p>The value to replace.</p>
3116
   *
3117 15
   * @return static <p>(Immutable)</p>
3118
   */
3119
  public function replaceOneValue($search, $replacement = '')
3120
  {
3121
    $array = $this->array;
3122
    $key = \array_search($search, $array, true);
3123
3124
    if ($key !== false) {
3125 8
      $array[$key] = $replacement;
3126
    }
3127 8
3128
    return static::create($array);
3129 8
  }
3130
3131
  /**
3132
   * Replace values in the current array.
3133
   *
3134
   * @param mixed $search      <p>The value to replace.</p>
3135
   * @param mixed $replacement <p>What to replace it with.</p>
3136
   *
3137
   * @return static <p>(Immutable)</p>
3138
   */
3139
  public function replaceValues($search, $replacement = '')
3140
  {
3141
    $array = $this->each(
3142
        function ($value) use ($search, $replacement) {
3143 4
          return UTF8::str_replace($search, $replacement, $value);
3144
        }
3145 4
    );
3146
3147 4
    return $array;
3148
  }
3149
3150
  /**
3151
   * Get the last elements from index $from until the end of this array.
3152
   *
3153
   * @param int $from
3154
   *
3155
   * @return static <p>(Immutable)</p>
3156
   */
3157 20
  public function rest(int $from = 1)
3158
  {
3159 20
    $tmpArray = $this->array;
3160
3161
    return static::create(\array_splice($tmpArray, $from));
3162
  }
3163
3164
  /**
3165
   * Return the array in the reverse order.
3166
   *
3167
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3168
   */
3169 9
  public function reverse()
3170
  {
3171
    $this->array = \array_reverse($this->array);
3172 9
3173
    return $this;
3174 9
  }
3175
3176
  /**
3177
   * Sort an array in reverse order.
3178
   *
3179 9
   * @param int $sort_flags [optional] <p>
3180 1
   *                        You may modify the behavior of the sort using the optional
3181
   *                        parameter sort_flags, for details
3182
   *                        see sort.
3183 9
   *                        </p>
3184 7
   *
3185
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3186
   */
3187
  public function rsort(int $sort_flags = 0)
3188 9
  {
3189
    \rsort($this->array, $sort_flags);
3190
3191
    return $this;
3192
  }
3193
3194
  /**
3195
   * Search for the first index of the current array via $value.
3196
   *
3197
   * @param mixed $value
3198
   *
3199 17
   * @return int|float|string
3200
   */
3201 17
  public function searchIndex($value)
3202
  {
3203 17
    return \array_search($value, $this->array, true);
3204
  }
3205
3206
  /**
3207
   * Search for the value of the current array via $index.
3208
   *
3209
   * @param mixed $index
3210
   *
3211
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3212
   */
3213
  public function searchValue($index)
3214
  {
3215
    // init
3216 11
    $return = [];
3217
3218
    if ($this->isEmpty()) {
3219 11
      return static::create();
3220 4
    }
3221
3222
    // php cast "bool"-index into "int"-index
3223 11
    if ((bool)$index === $index) {
3224
      $index = (int)$index;
3225
    }
3226
3227
    if (\array_key_exists($index, $this->array) === true) {
3228
      $return = [$this->array[$index]];
3229
    }
3230
3231 4
3232
    return static::create($return);
3233 4
  }
3234
3235
  /**
3236
   * Set a value for the current array (optional using dot-notation).
3237
   *
3238
   * @param mixed $key   <p>The key to set.</p>
3239
   * @param mixed $value <p>Its value.</p>
3240
   *
3241
   * @return static <p>(Immutable)</p>
3242
   */
3243
  public function set($key, $value)
3244 1
  {
3245
    $this->internalSet($key, $value);
3246 1
3247 1
    return static::create($this->array);
3248
  }
3249
3250 1
  /**
3251 1
   * Get a value from a array and set it if it was not.
3252
   *
3253 1
   * WARNING: this method only set the value, if the $key is not already set
3254 1
   *
3255 1
   * @param mixed $key      <p>The key</p>
3256
   * @param mixed $fallback <p>The default value to set if it isn't.</p>
3257 1
   *
3258
   * @return mixed <p>(Mutable)</p>
3259
   */
3260
  public function setAndGet($key, $fallback = null)
3261 1
  {
3262 1
    // If the key doesn't exist, set it.
3263 1
    if (!$this->has($key)) {
3264 1
      $this->array = $this->set($key, $fallback)->getArray();
3265
    }
3266
3267
    return $this->get($key);
3268
  }
3269 1
3270
  /**
3271
   * Shifts a specified value off the beginning of array.
3272 1
   *
3273
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
3274 1
   */
3275 1
  public function shift()
3276
  {
3277
    return \array_shift($this->array);
3278
  }
3279 1
3280
  /**
3281
   * Shuffle the current array.
3282
   *
3283
   * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3284
   * @param array $array  [optional]
3285
   *
3286
   * @return static <p>(Immutable)</p>
3287
   */
3288
  public function shuffle(bool $secure = false, array $array = null)
3289
  {
3290
    if ($array === null) {
3291 20
      $array = $this->array;
3292
    }
3293 20
3294
    if ($secure !== true) {
3295
      /** @noinspection NonSecureShuffleUsageInspection */
3296
      \shuffle($array);
3297
    } else {
3298
      $size = \count($array, COUNT_NORMAL);
3299
      $keys = \array_keys($array);
3300
      for ($i = $size - 1; $i > 0; --$i) {
3301
        try {
3302
          $r = \random_int(0, $i);
3303
        } catch (\Exception $e) {
3304
          $r = \mt_rand();
3305
        }
3306
        if ($r !== $i) {
3307
          $temp = $array[$keys[$r]];
3308
          $array[$keys[$r]] = $array[$keys[$i]];
3309
          $array[$keys[$i]] = $temp;
3310
        }
3311
      }
3312
3313
      // reset indices
3314
      $array = \array_values($array);
3315
    }
3316
3317
    foreach ($array as $key => $value) {
3318
      // check if recursive is needed
3319
      if (\is_array($value) === true) {
3320
        $array[$key] = $this->shuffle($secure, $value);
3321 10
      }
3322
    }
3323 10
3324
    return static::create($array);
3325
  }
3326
3327
  /**
3328
   * Count the values from the current array.
3329
   *
3330
   * alias: for "Arrayy->count()"
3331
   *
3332
   * @param int $mode
3333
   *
3334
   * @return int
3335 4
   */
3336
  public function size(int $mode = COUNT_NORMAL): int
3337 4
  {
3338
    return $this->count($mode);
3339 4
  }
3340
3341
  /**
3342
   * Counts all elements in an array, or something in an object.
3343
   * <p>For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3344
   * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3345
   * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3346
   * implemented and used in PHP.
3347
   *
3348
   * @return int the number of elements in var, which is
3349
   * typically an array, since anything else will have one
3350
   * element.
3351
   * </p>
3352 19
   * <p>
3353
   * If var is not an array or an object with
3354 19
   * implemented Countable interface,
3355
   * 1 will be returned.
3356 19
   * There is one exception, if var is &null;,
3357
   * 0 will be returned.
3358
   * </p>
3359
   * <p>
3360
   * Caution: count may return 0 for a variable that isn't set,
3361
   * but it may also return 0 for a variable that has been initialized with an
3362
   * empty array. Use isset to test if a variable is set.
3363
   *
3364
   * @return int
3365
   */
3366
  public function sizeRecursive(): int
3367
  {
3368
    return \count($this->array, COUNT_RECURSIVE);
3369
  }
3370
3371 18
  /**
3372
   * Extract a slice of the array.
3373 18
   *
3374
   * @param int      $offset       <p>Slice begin index.</p>
3375 18
   * @param int|null $length       <p>Length of the slice.</p>
3376
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3377
   *
3378
   * @return static <p>A slice of the original array with length $length.</p>
3379
   */
3380
  public function slice(int $offset, int $length = null, bool $preserveKeys = false)
3381
  {
3382
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
3383
3384
    return static::create($result);
3385
  }
3386
3387 1
  /**
3388
   * Sort the current array and optional you can keep the keys.
3389 1
   *
3390
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3391
   * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3392
   *                              <strong>SORT_NATURAL</strong></p>
3393
   * @param bool       $keepKeys
3394
   *
3395
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3396
   */
3397
  public function sort($direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3398
  {
3399
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
3400
3401 1
    return $this;
3402
  }
3403 1
3404
  /**
3405
   * Sort the current array by key.
3406
   *
3407
   * @link http://php.net/manual/en/function.ksort.php
3408
   * @link http://php.net/manual/en/function.krsort.php
3409
   *
3410
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3411
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3412
   *                              <strong>SORT_NATURAL</strong></p>
3413
   *
3414
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3415
   */
3416
  public function sortKeys($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3417
  {
3418
    $this->sorterKeys($this->array, $direction, $strategy);
3419 1
3420
    return $this;
3421 1
  }
3422 1
3423
  /**
3424
   * Sort the current array by value.
3425 1
   *
3426 1
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3427
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3428 1
   *                              <strong>SORT_NATURAL</strong></p>
3429 1
   *
3430 1
   * @return static <p>(Mutable)</p>
3431 1
   */
3432 1
  public function sortValueKeepIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3433
  {
3434
    return $this->sort($direction, $strategy, true);
3435 1
  }
3436
3437 1
  /**
3438
   * Sort the current array by value.
3439
   *
3440
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3441 1
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3442
   *                              <strong>SORT_NATURAL</strong></p>
3443 1
   *
3444
   * @return static <p>(Mutable)</p>
3445
   */
3446
  public function sortValueNewIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3447
  {
3448
    return $this->sort($direction, $strategy, false);
3449
  }
3450
3451
  /**
3452
   * Sort a array by value, by a closure or by a property.
3453
   *
3454
   * - If the sorter is null, the array is sorted naturally.
3455
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3456 18
   *
3457
   * @param \callable|null $sorter
3458 18
   * @param string|int     $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3459
   * @param int            $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3460
   *                                  <strong>SORT_NATURAL</strong></p>
3461 18
   *
3462 18
   * @return static <p>(Immutable)</p>
3463 6
   */
3464 6
  public function sorter($sorter = null, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3465 13
  {
3466 13
    $array = (array)$this->array;
3467
    $direction = $this->getDirection($direction);
3468 13
3469
    // Transform all values into their results.
3470
    if ($sorter) {
3471 18
      $arrayy = static::create($array);
3472
3473
      $that = $this;
3474
      $results = $arrayy->each(
3475
          function ($value) use ($sorter, $that) {
3476
            return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3477
          }
3478
      );
3479
3480
      $results = $results->getArray();
3481
    } else {
3482
      $results = $array;
3483 19
    }
3484
3485 19
    // Sort by the results and replace by original values
3486
    \array_multisort($results, $direction, $strategy, $array);
3487 19
3488 19
    return static::create($array);
3489
  }
3490
3491
  /**
3492 19
   * sorting keys
3493 19
   *
3494 9
   * @param array      $elements
3495 5
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3496
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3497 4
   *                              <strong>SORT_NATURAL</strong></p>
3498
   *
3499 9
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3500 10
   */
3501 10
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3502
  {
3503 10
    $direction = $this->getDirection($direction);
3504 4
3505
    switch ($direction) {
3506 6
      case 'desc':
3507
      case SORT_DESC:
3508
        \krsort($elements, $strategy);
3509
        break;
3510 19
      case 'asc':
3511
      case SORT_ASC:
3512
      default:
3513
        \ksort($elements, $strategy);
3514
    }
3515
3516
    return $this;
3517
  }
3518
3519
  /**
3520
   * @param array      &$elements
3521 1
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3522
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3523 1
   *                              <strong>SORT_NATURAL</strong></p>
3524
   * @param bool       $keepKeys
3525 1
   *
3526 1
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3527
   */
3528 1
  protected function sorting(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3529 1
  {
3530
    $direction = $this->getDirection($direction);
3531
3532 1
    if (!$strategy) {
3533
      $strategy = SORT_REGULAR;
3534
    }
3535
3536
    switch ($direction) {
3537
      case 'desc':
3538
      case SORT_DESC:
3539
        if ($keepKeys) {
3540 1
          \arsort($elements, $strategy);
3541
        } else {
3542 1
          \rsort($elements, $strategy);
3543 1
        }
3544 1
        break;
3545 1
      case 'asc':
3546
      case SORT_ASC:
3547
      default:
3548 1
        if ($keepKeys) {
3549 1
          \asort($elements, $strategy);
3550
        } else {
3551
          \sort($elements, $strategy);
3552
        }
3553
    }
3554
3555
    return $this;
3556
  }
3557
3558
  /**
3559
   * Split an array in the given amount of pieces.
3560
   *
3561 1
   * @param int  $numberOfPieces
3562
   * @param bool $keepKeys
3563 1
   *
3564
   * @return static <p>(Immutable)</p>
3565 1
   */
3566
  public function split(int $numberOfPieces = 2, bool $keepKeys = false)
3567 1
  {
3568
    $arrayCount = \count($this->array, COUNT_NORMAL);
3569
3570
    if ($arrayCount === 0) {
3571
      $result = [];
3572
    } else {
3573
      $splitSize = (int)\ceil($arrayCount / $numberOfPieces);
3574
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
3575 186
    }
3576
3577 186
    return static::create($result);
3578
  }
3579
3580
  /**
3581
   * Stripe all empty items.
3582
   *
3583
   * @return static <p>(Immutable)</p>
3584
   */
3585
  public function stripEmpty()
3586
  {
3587
    return $this->filter(
3588 6
        function ($item) {
3589
          if ($item === null) {
3590 6
            return false;
3591
          }
3592
3593
          return (bool)\trim((string)$item);
3594
        }
3595
    );
3596
  }
3597
3598
  /**
3599
   * Swap two values between positions by key.
3600 19
   *
3601
   * @param string|int $swapA <p>a key in the array</p>
3602 19
   * @param string|int $swapB <p>a key in the array</p>
3603
   *
3604
   * @return static <p>(Immutable)</p>
3605
   */
3606
  public function swap($swapA, $swapB)
3607
  {
3608
    $array = $this->array;
3609
3610 9
    list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3611
3612
    return static::create($array);
3613
  }
3614 9
3615 9
  /**
3616 9
   * alias: for "Arrayy->getArray()"
3617 8
   *
3618 8
   * @see Arrayy::getArray()
3619
   */
3620
  public function toArray()
3621 8
  {
3622 9
    return $this->getArray();
3623 9
  }
3624
3625
  /**
3626 9
   * Convert the current array to JSON.
3627
   *
3628
   * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3629 9
   * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3630
   *
3631
   * @return string
3632 9
   */
3633
  public function toJson(int $options = 0, int $depth = 512): string
3634
  {
3635
    return UTF8::json_encode($this->array, $options, $depth);
3636
  }
3637
3638
  /**
3639
   * Implodes array to a string with specified separator.
3640 9
   *
3641
   * @param string $separator [optional] <p>The element's separator.</p>
3642
   *
3643
   * @return string <p>The string representation of array, separated by ",".</p>
3644
   */
3645 9
  public function toString(string $separator = ','): string
3646
  {
3647 9
    return $this->implode($separator);
3648 9
  }
3649 9
3650 8
  /**
3651 8
   * Return a duplicate free copy of the current array.
3652
   *
3653
   * @return static <p>(Mutable)</p>
3654 8
   */
3655 9
  public function unique()
3656 9
  {
3657
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3658
3659 9
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce($this->arr...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

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

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

Loading history...
3660
        $this->array,
3661
        function ($resultArray, $value) {
3662 9
          if (!\in_array($value, $resultArray, true)) {
3663
            $resultArray[] = $value;
3664
          }
3665 9
3666
          return $resultArray;
3667
        },
3668
        []
3669
    );
3670
3671 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3672
      $this->array = [];
3673
    } else {
3674
      $this->array = (array)$this->array;
3675 9
    }
3676
3677 9
    return $this;
3678
  }
3679
3680
  /**
3681
   * Return a duplicate free copy of the current array. (with the old keys)
3682
   *
3683
   * @return static <p>(Mutable)</p>
3684
   */
3685 4
  public function uniqueKeepIndex()
3686
  {
3687 4
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3688 4
3689 4
    // init
3690
    $array = $this->array;
3691
3692 4
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce(\array_key...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

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

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

Loading history...
3693
        \array_keys($array),
3694
        function ($resultArray, $key) use ($array) {
3695
          if (!\in_array($array[$key], $resultArray, true)) {
3696
            $resultArray[$key] = $array[$key];
3697
          }
3698
3699
          return $resultArray;
3700 2
        },
3701
        []
3702 2
    );
3703
3704 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3705
      $this->array = [];
3706
    } else {
3707
      $this->array = (array)$this->array;
3708
    }
3709
3710
    return $this;
3711
  }
3712
3713 35
  /**
3714
   * alias: for "Arrayy->unique()"
3715 35
   *
3716 30
   * @see Arrayy::unique()
3717
   *
3718 18
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3719
   */
3720
  public function uniqueNewIndex()
3721 35
  {
3722
    return $this->unique();
3723
  }
3724
3725
  /**
3726
   * Prepends one or more values to the beginning of array at once.
3727
   *
3728
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3729
   */
3730 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...
3731
  {
3732
    if (\func_num_args()) {
3733
      $args = \array_merge([&$this->array], \func_get_args());
3734
      \array_unshift(...$args);
3735
    }
3736
3737
    return $this;
3738
  }
3739
3740
  /**
3741
   * Get all values from a array.
3742
   *
3743
   * @return static <p>(Immutable)</p>
3744
   */
3745
  public function values()
3746
  {
3747
    return static::create(\array_values((array)$this->array));
3748
  }
3749
3750
  /**
3751
   * Apply the given function to every element in the array, discarding the results.
3752
   *
3753
   * @param \callable $callable
3754
   * @param bool      $recursive <p>Whether array will be walked recursively or no</p>
3755
   *
3756
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3757
   */
3758
  public function walk($callable, bool $recursive = false)
3759
  {
3760
    if (true === $recursive) {
3761
      \array_walk_recursive($this->array, $callable);
3762
    } else {
3763
      \array_walk($this->array, $callable);
3764
    }
3765
3766
    return $this;
3767
  }
3768
}
3769