Completed
Push — master ( f191ed...acf765 )
by Lars
81:18
created

Arrayy::__set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
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 871
  public function __construct($array = [], $iteratorClass = ArrayyIterator::class)
42
  {
43 871
    $array = $this->fallbackForArray($array);
44 869
    $this->array = $array;
45
46 869
    $this->setIteratorClass($iteratorClass);
47 869
  }
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 1
  public function appendArrayValues(array $values, $key = null)
153
  {
154 1
    if ($key !== null) {
155
      if (
156 1
          isset($this->array[$key])
157
          &&
158 1
          is_array($this->array[$key])
159
      ) {
160 1
        foreach ($values as $value) {
161 1
          $this->array[$key][] = $value;
162
        }
163
      } else {
164
        foreach ($values as $value) {
165 1
          $this->array[$key] = $value;
166
        }
167
      }
168
    } else {
169
      foreach ($values as $value) {
170
        $this->array[] = $value;
171
      }
172
    }
173
174 1
    return $this;
175
  }
176
177
  /**
178
   * 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 9
  public function append($value, $key = null)
186
  {
187 9
    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 9
      $this->array[] = $value;
199
    }
200
201 9
    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
   * @return static <p>(Mutable) Return this Arrayy object.</p>
214
   */
215 4
  public function asort(int $sort_flags = 0)
216
  {
217 4
    \asort($this->array, $sort_flags);
218
219 4
    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
   * 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
   * implemented and used in PHP.
228
   *
229
   * @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
   * typically an array, since anything else will have one
238
   * element.
239
   * </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
   * <p>
248
   * Caution: count may return 0 for a variable that isn't set,
249
   * 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
   *
252
   * @return int
253
   */
254 37
  public function count(int $mode = COUNT_NORMAL): int
255
  {
256 37
    return \count($this->array, $mode);
257
  }
258
259
  /**
260
   * Exchange the array for another one.
261
   *
262
   * @param array|static $data
263
   *
264
   * @return array
265
   */
266 1
  public function exchangeArray($data): array
267
  {
268 1
    $this->array = $this->fallbackForArray($data);
269
270 1
    return $this->array;
271
  }
272
273
  /**
274
   * Creates a copy of the ArrayyObject.
275
   *
276
   * @return array
277
   */
278 1
  public function getArrayCopy(): array
279
  {
280 1
    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 20
  public function getIterator(): \ArrayIterator
289
  {
290 20
    $iterator = $this->getIteratorClass();
291
292 20
    return new $iterator($this->array);
293
  }
294
295
  /**
296
   * Gets the iterator classname for the ArrayObject.
297
   *
298
   * @return string
299
   */
300 20
  public function getIteratorClass(): string
301
  {
302 20
    return $this->iteratorClass;
303
  }
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
   *
314
   * @return static <p>(Mutable) Return this Arrayy object.</p>
315
   */
316 4
  public function ksort(int $sort_flags = 0)
317
  {
318 4
    \ksort($this->array, $sort_flags);
319
320 4
    return $this;
321
  }
322
323
  /**
324
   * Sort an array using a case insensitive "natural order" algorithm
325
   *
326
   * @return static <p>(Mutable) Return this Arrayy object.</p>
327
   */
328
  public function natcasesort()
329
  {
330
    \natcasesort($this->array);
331
332
    return $this;
333
  }
334
335
  /**
336
   * Sort entries using a "natural order" algorithm
337
   *
338
   * @return static <p>(Mutable) Return this Arrayy object.</p>
339
   */
340 1
  public function natsort()
341
  {
342 1
    \natsort($this->array);
343
344 1
    return $this;
345
  }
346
347
  /**
348
   * Whether or not an offset exists.
349
   *
350
   * @param int|float|string $offset
351
   *
352
   * @return bool
353
   */
354 40
  public function offsetExists($offset): bool
355
  {
356 40
    if ($this->isEmpty()) {
357 4
      return false;
358
    }
359
360
    // php cast "bool"-index into "int"-index
361 36
    if ((bool)$offset === $offset) {
362 1
      $offset = (int)$offset;
363
    }
364
365 36
    $tmpReturn = \array_key_exists($offset, $this->array);
366
367
    if (
368 36
        $tmpReturn === true
369
        ||
370
        (
371 12
            $tmpReturn === false
372
            &&
373 36
            \strpos((string)$offset, $this->pathSeparator) === false
374
        )
375
    ) {
376 34
      return $tmpReturn;
377
    }
378
379 3
    $offsetExists = false;
380
381 3
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
382
383 3
      $offsetExists = false;
384 3
      $explodedPath = \explode($this->pathSeparator, (string)$offset);
385 3
      $lastOffset = \array_pop($explodedPath);
386 3
      $containerPath = \implode($this->pathSeparator, $explodedPath);
387
388 3
      $this->callAtPath(
389 3
          $containerPath,
390 3
          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 3
            $offsetExists = \array_key_exists($lastOffset, $container);
392 3
          }
393
      );
394
    }
395
396 3
    return $offsetExists;
397
  }
398
399
  /**
400
   * Returns the value at specified offset.
401
   *
402
   * @param int|float|string $offset
403
   *
404
   * @return mixed <p>Will return null if the offset did not exists.</p>
405
   */
406 26
  public function offsetGet($offset)
407
  {
408 26
    return $this->offsetExists($offset) ? $this->get($offset) : null;
409
  }
410
411
  /**
412
   * Assigns a value to the specified offset.
413
   *
414
   * @param int|float|string $offset
415
   * @param mixed            $value
416
   */
417 17
  public function offsetSet($offset, $value)
418
  {
419 17
    if ($offset === null) {
420 4
      $this->array[] = $value;
421
    } else {
422 13
      $this->internalSet($offset, $value);
423
    }
424 17
  }
425
426
  /**
427
   * Unset an offset.
428
   *
429
   * @param int|float|string $offset
430
   */
431 7
  public function offsetUnset($offset)
432
  {
433 7
    if ($this->isEmpty()) {
434 1
      return;
435
    }
436
437 6
    if (\array_key_exists($offset, $this->array)) {
438 4
      unset($this->array[$offset]);
439
440 4
      return;
441
    }
442
443 3
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
444
445 2
      $path = \explode($this->pathSeparator, (string)$offset);
446 2
      $pathToUnset = \array_pop($path);
447
448 2
      $this->callAtPath(
449 2
          \implode($this->pathSeparator, $path),
450 2
          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 2
            unset($offset[$pathToUnset]);
452 2
          }
453
      );
454
455
    }
456 3
  }
457
458
  /**
459
   * Serialize the current "Arrayy"-object.
460
   *
461
   * @return string
462
   */
463 1
  public function serialize()
464
  {
465 1
    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 869
  public function setIteratorClass($class)
478
  {
479 869
    if (\class_exists($class)) {
480 869
      $this->iteratorClass = $class;
481
482 869
      return;
483
    }
484
485
    if (\strpos($class, '\\') === 0) {
486
      $class = '\\' . $class;
487
      if (\class_exists($class)) {
488
        $this->iteratorClass = $class;
489
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
   *
500
   * @param \callable $function
501
   *
502
   * @return static <p>(Mutable) Return this Arrayy object.</p>
503
   *
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
514
    \uasort($this->array, $function);
515
516
    return $this;
517
  }
518
519
  /**
520
   * Sort the entries by keys using a user-defined comparison function.
521
   *
522
   * @param \callable $function
523
   *
524
   * @return static <p>(Mutable) Return this Arrayy object.</p>
525
   *
526
   * @throws \InvalidArgumentException
527
   */
528 5
  public function uksort($function)
529
  {
530 5
    return $this->customSortKeys($function);
531
  }
532
533
  /**
534
   * Unserialize an string and return this object.
535
   *
536
   * @param string $string
537
   *
538
   * @return static <p>(Mutable)</p>
539
   */
540 1
  public function unserialize($string)
541
  {
542 1
    parent::unserialize($string);
543
544 1
    return $this;
545
  }
546
547
  /**
548
   * Add a suffix to each key.
549
   *
550
   * @param mixed $prefix
551
   *
552
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
553
   */
554 10 View Code Duplication
  public function appendToEachKey($prefix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

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

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

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

Loading history...
578
  {
579 10
    $result = [];
580 10
    foreach ($this->array as $key => $item) {
581 9
      if ($item instanceof self) {
582
        $result[$key] = $item->appendToEachValue($prefix);
583 9
      } elseif (\is_array($item)) {
584
        $result[$key] = self::create($item)->appendToEachValue($prefix)->toArray();
585 9
      } elseif (\is_object($item)) {
586 1
        $result[$key] = $item;
587
      } else {
588 9
        $result[$key] = $prefix . $item;
589
      }
590
    }
591
592 10
    return self::create($result);
593
  }
594
595
  /**
596
   * Convert an array into a object.
597
   *
598
   * @param array $array PHP array
599
   *
600
   * @return \stdClass (object)
601
   */
602 4
  protected static function arrayToObject(array $array = []): \stdClass
603
  {
604 4
    $object = new \stdClass();
605
606 4
    if (!\is_array($array) || \count($array, COUNT_NORMAL) <= 0) {
607 1
      return $object;
608
    }
609
610 3
    foreach ($array as $name => $value) {
611 3
      if (\is_array($value)) {
612 1
        $object->{$name} = self::arrayToObject($value);
613 1
        continue;
614
      }
615 3
      $object->{$name} = $value;
616
    }
617
618 3
    return $object;
619
  }
620
621
  /**
622
   * @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
   *                            </p>
631
   *
632
   * @return array an array of all the keys in input.
633
   */
634 10
  protected function array_keys_recursive(array $input = null, $search_value = null, bool $strict = true): array
635
  {
636
    // init
637 10
    $keys = [];
638
639 10
    if ($input === null) {
640
      $input = $this->array;
641
    }
642
643 10
    foreach ($input as $key => $value) {
644
645
      if (
646 10
          $search_value === null
647
          ||
648
          (
649
              \is_array($search_value) === true
650
              &&
651 10
              \in_array($key, $search_value, $strict)
652
          )
653
      ) {
654 10
        $keys[] = $key;
655
      }
656
657
      // check if recursive is needed
658 10
      if (\is_array($value) === true) {
659 10
        $keys = \array_merge($keys, $this->array_keys_recursive($value));
660
      }
661
    }
662
663 10
    return $keys;
664
  }
665
666
  /**
667
   * Sort an array in reverse order and maintain index association.
668
   *
669
   * @return static <p>(Mutable) Return this Arrayy object.</p>
670
   */
671 4
  public function arsort()
672
  {
673 4
    \arsort($this->array);
674
675 4
    return $this;
676
  }
677
678
  /**
679
   * Iterate over the current array and execute a callback for each loop.
680
   *
681
   * @param \Closure $closure
682
   *
683
   * @return static <p>(Immutable)</p>
684
   */
685 2 View Code Duplication
  public function at(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
686
  {
687 2
    $array = $this->array;
688
689 2
    foreach ($array as $key => $value) {
690 2
      $closure($value, $key);
691
    }
692
693 2
    return static::create($array);
694
  }
695
696
  /**
697
   * Returns the average value of the current array.
698
   *
699
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
700
   *
701
   * @return int|double <p>The average value.</p>
702
   */
703 10
  public function average($decimals = 0)
704
  {
705 10
    $count = \count($this->array, COUNT_NORMAL);
706
707 10
    if (!$count) {
708 2
      return 0;
709
    }
710
711 8
    if (!\is_int($decimals)) {
712 3
      $decimals = 0;
713
    }
714
715 8
    return \round(\array_sum($this->array) / $count, $decimals);
716
  }
717
718
  /**
719
   * @param mixed      $path
720
   * @param \callable  $callable
721
   * @param null|array $currentOffset
722
   */
723 4
  protected function callAtPath($path, $callable, &$currentOffset = null)
724
  {
725 4
    if ($currentOffset === null) {
726 4
      $currentOffset = &$this->array;
727
    }
728
729 4
    $explodedPath = \explode($this->pathSeparator, $path);
730 4
    $nextPath = \array_shift($explodedPath);
731
732 4
    if (!isset($currentOffset[$nextPath])) {
733
      return;
734
    }
735
736 4
    if (!empty($explodedPath)) {
737 1
      $this->callAtPath(
738 1
          \implode($this->pathSeparator, $explodedPath),
739 1
          $callable,
740 1
          $currentOffset[$nextPath]
741
      );
742
    } else {
743 4
      $callable($currentOffset[$nextPath]);
744
    }
745 4
  }
746
747
  /**
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 1
  public function changeKeyCase(int $case = CASE_LOWER)
756
  {
757 1
    return static::create(UTF8::array_change_key_case($this->array, $case));
758
  }
759
760
  /**
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 1
  public function changeSeparator($separator)
770
  {
771 1
    $this->pathSeparator = $separator;
772
773 1
    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 4
  public function chunk($size, $preserveKeys = false)
785
  {
786 4
    $result = \array_chunk($this->array, $size, $preserveKeys);
787
788 4
    return static::create($result);
789
  }
790
791
  /**
792
   * Clean all falsy values from the current array.
793
   *
794
   * @return static <p>(Immutable)</p>
795
   */
796 8
  public function clean()
797
  {
798 8
    return $this->filter(
799 8
        function ($value) {
800 7
          return (bool)$value;
801 8
        }
802
    );
803
  }
804
805
  /**
806
   * WARNING!!! -> Clear the current array.
807
   *
808
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
809
   */
810 4
  public function clear()
811
  {
812 4
    $this->array = [];
813
814 4
    return $this;
815
  }
816
817
  /**
818
   * Check if an item is in the current array.
819
   *
820
   * @param string|int|float $value
821
   * @param bool             $recursive
822
   * @param bool             $strict
823
   *
824
   * @return bool
825
   */
826 23
  public function contains($value, $recursive = false, $strict = true): bool
827
  {
828 23
    if ($recursive === true) {
829 19
      return $this->in_array_recursive($value, $this->array, $strict);
830
    }
831
832 13
    return \in_array($value, $this->array, $strict);
833
  }
834
835
  /**
836
   * Check if an (case-insensitive) string is in the current array.
837
   *
838
   * @param string $value
839
   * @param bool   $recursive
840
   *
841
   * @return bool
842
   */
843 26
  public function containsCaseInsensitive($value, $recursive = false): bool
844
  {
845 26
    if ($recursive === true) {
846 26
      return $this->in_array_recursive(
847 26
          UTF8::strtoupper($value),
848 26
          $this->walk(
849 26
              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 22
                $val = UTF8::strtoupper($val);
851 26
              },
852 26
              true
853 26
          )->getArray(),
854 26
          true
855
      );
856
    }
857
858 13
    return \in_array(
859 13
        UTF8::strtoupper($value),
860 13
        $this->walk(
861 13
            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 11
              $val = UTF8::strtoupper($val);
863 13
            },
864 13
            false
865 13
        )->getArray(),
866 13
        true
867
    );
868
  }
869
870
  /**
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 4
  public function containsKey($key): bool
878
  {
879 4
    return $this->offsetExists($key);
880
  }
881
882
  /**
883
   * 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 2
  public function containsKeys(array $needles, $recursive = false): bool
891
  {
892 2
    if ($recursive === true) {
893 2
      return \count(
894 2
                 \array_intersect($needles, $this->keys(true)->getArray()),
895 2
                 COUNT_RECURSIVE
896
             )
897
             ===
898 2
             \count(
899 2
                 $needles,
900 2
                 COUNT_RECURSIVE
901
             );
902
    }
903
904 1
    return \count(
905 1
               \array_intersect($needles, $this->keys()->getArray()),
906 1
               COUNT_NORMAL
907
           )
908
           ===
909 1
           \count(
910 1
               $needles,
911 1
               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
   */
922 1
  public function containsKeysRecursive(array $needles): bool
923
  {
924 1
    return $this->containsKeys($needles, true);
925
  }
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 9
  public function containsValue($value): bool
937
  {
938 9
    return $this->contains($value);
939
  }
940
941
  /**
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 18
  public function containsValueRecursive($value): bool
951
  {
952 18
    return $this->contains($value, true);
953
  }
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 1
  public function containsValues(array $needles): bool
963
  {
964 1
    return \count(\array_intersect($needles, $this->array), COUNT_NORMAL)
965
           ===
966 1
           \count($needles, COUNT_NORMAL);
967
  }
968
969
  /**
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
   */
980 1
  public function countValues(): self
981
  {
982 1
    return new static(\array_count_values($this->array));
983
  }
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 540
  public static function create($array = []): self
993
  {
994 540
    return new static($array);
995
  }
996
997
  /**
998
   * WARNING: Creates an Arrayy object by reference.
999
   *
1000
   * @param array $array
1001
   *
1002
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1003
   */
1004 1
  public function createByReference(array &$array = []): self
1005
  {
1006 1
    $array = $this->fallbackForArray($array);
1007
1008 1
    $this->array = &$array;
1009
1010 1
    return $this;
1011
  }
1012
1013
  /**
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 5
  public static function createFromJson(string $json)
1021
  {
1022 5
    $array = UTF8::json_decode($json, true);
1023
1024 5
    return static::create($array);
1025
  }
1026
1027
  /**
1028
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
1029
   *
1030
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
1031
   *
1032
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1033
   */
1034 4
  public static function createFromObject(\ArrayAccess $object)
1035
  {
1036 4
    $array = new static();
1037 4
    foreach ($object as $key => $value) {
1038
      /** @noinspection OffsetOperationsInspection */
1039 3
      $array[$key] = $value;
1040
    }
1041
1042 4
    return $array;
1043
  }
1044
1045
  /**
1046
   * Create an new instance filled with values from an object.
1047
   *
1048
   * @param object $object
1049
   *
1050
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1051
   */
1052 5
  public static function createFromObjectVars($object): self
1053
  {
1054 5
    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
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1063
   *                               used.</p>
1064
   *
1065
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1066
   */
1067 8
  public static function createFromString(string $str, string $delimiter = null, string $regEx = null)
1068
  {
1069 8
    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 1
      \preg_match_all($regEx, $str, $array);
1071
1072 1
      if (!empty($array)) {
1073 1
        $array = $array[0];
1074
      }
1075
1076
    } else {
1077 7
      $array = \explode($delimiter, $str);
1078
    }
1079
1080
    // trim all string in the array
1081 8
    \array_walk(
1082 8
        $array,
1083 8
        function (&$val) {
1084
          /** @noinspection ReferenceMismatchInspection */
1085 8
          if (\is_string($val)) {
1086 8
            $val = \trim($val);
1087
          }
1088 8
        }
1089
    );
1090
1091 8
    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
   */
1103 1
  public static function createWithRange($low, $high, int $step = 1)
1104
  {
1105 1
    return static::create(\range($low, $high, $step));
1106
  }
1107
1108
  /**
1109
   * Custom sort by index via "uksort".
1110
   *
1111
   * @link http://php.net/manual/en/function.uksort.php
1112
   *
1113
   * @param \callable $function
1114
   *
1115
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1116
   *
1117
   * @throws \InvalidArgumentException
1118
   */
1119 5 View Code Duplication
  public function customSortKeys($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1120
  {
1121 5
    if (!\is_callable($function)) {
1122
      throw new \InvalidArgumentException(
1123
          'Passed function must be callable'
1124
      );
1125
    }
1126
1127 5
    \uksort($this->array, $function);
1128
1129 5
    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
   * @param \callable $function
1138
   *
1139
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1140
   *
1141
   * @throws \InvalidArgumentException
1142
   */
1143 5 View Code Duplication
  public function customSortValues($function)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1144
  {
1145 5
    if (!\is_callable($function)) {
1146
      throw new \InvalidArgumentException(
1147
          'Passed function must be callable'
1148
      );
1149
    }
1150
1151 5
    \usort($this->array, $function);
1152
1153 5
    return $this;
1154
  }
1155
1156
  /**
1157
   * Return values that are only in the current array.
1158
   *
1159
   * @param array $array
1160
   *
1161
   * @return static <p>(Immutable)</p>
1162
   */
1163 12
  public function diff(array $array = [])
1164
  {
1165 12
    $result = \array_diff($this->array, $array);
1166
1167 12
    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
   * @return static <p>(Immutable)</p>
1177
   */
1178 1
  public function diffRecursive(array $array = [], $helperVariableForRecursion = null)
1179
  {
1180 1
    $result = [];
1181
1182
    if (
1183 1
        $helperVariableForRecursion !== null
1184
        &&
1185 1
        \is_array($helperVariableForRecursion)
1186
    ) {
1187 1
      $arrayForTheLoop = $helperVariableForRecursion;
1188
    } else {
1189 1
      $arrayForTheLoop = $this->array;
1190
    }
1191
1192 1
    foreach ($arrayForTheLoop as $key => $value) {
1193 1
      if (\array_key_exists($key, $array)) {
1194 1
        if (\is_array($value)) {
1195 1
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
1196 1
          if (!empty($recursiveDiff)) {
1197 1
            $result[$key] = $recursiveDiff;
1198
          }
1199 1
        } elseif ($value != $array[$key]) {
1200 1
          $result[$key] = $value;
1201
        }
1202
      } else {
1203 1
        $result[$key] = $value;
1204
      }
1205
    }
1206
1207 1
    return static::create($result);
1208
  }
1209
1210
  /**
1211
   * Return values that are only in the new $array.
1212
   *
1213
   * @param array $array
1214
   *
1215
   * @return static <p>(Immutable)</p>
1216
   */
1217 8
  public function diffReverse(array $array = [])
1218
  {
1219 8
    $result = \array_diff($array, $this->array);
1220
1221 8
    return static::create($result);
1222
  }
1223
1224
  /**
1225
   * Divide an array into two arrays. One with keys and the other with values.
1226
   *
1227
   * @return static <p>(Immutable)</p>
1228
   */
1229 1
  public function divide()
1230
  {
1231 1
    return static::create(
1232
        [
1233 1
            $this->keys(),
1234 1
            $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 4 View Code Duplication
  public function each(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1247
  {
1248 4
    $array = $this->array;
1249
1250 4
    foreach ($array as $key => $value) {
1251 4
      $array[$key] = $closure($value, $key);
1252
    }
1253
1254 4
    return static::create($array);
1255
  }
1256
1257
  /**
1258
   * Check if a value is in the current array using a closure.
1259
   *
1260
   * @param \Closure $closure
1261
   *
1262
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
1263
   */
1264 4
  public function exists(\Closure $closure): bool
1265
  {
1266 4
    $isExists = false;
1267 4
    foreach ($this->array as $key => $value) {
1268 3
      if ($closure($value, $key)) {
1269 1
        $isExists = true;
1270 3
        break;
1271
      }
1272
    }
1273
1274 4
    return $isExists;
1275
  }
1276
1277
  /**
1278
   * 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
   * 5. call "__toArray()" on object, if the method exists
1285
   * 6. cast a string or object with "__toString()" into an array
1286
   * 7. throw a "InvalidArgumentException"-Exception
1287
   *
1288
   * @param $array
1289
   *
1290
   * @return array
1291
   *
1292
   * @throws \InvalidArgumentException
1293
   */
1294 871
  protected function fallbackForArray(&$array): array
1295
  {
1296 871
    if (\is_array($array)) {
1297 868
      return $array;
1298
    }
1299
1300 11
    if ($array instanceof self) {
1301 1
      return $array->getArray();
1302
    }
1303
1304 10
    if (!$array) {
1305 6
      return [];
1306
    }
1307
1308 9
    $isObject = \is_object($array);
1309
1310 9
    if ($isObject && $array instanceof \ArrayAccess) {
1311
      /** @noinspection ReferenceMismatchInspection */
1312
      return static::createFromObject($array)->getArray();
1313
    }
1314
1315 9
    if ($isObject && $array instanceof \ArrayObject) {
1316
      return $array->getArrayCopy();
1317
    }
1318
1319 9
    if ($isObject && \method_exists($array, '__toArray')) {
1320
      return (array)$array->__toArray();
1321
    }
1322
1323
    /** @noinspection ReferenceMismatchInspection */
1324
    if (
1325 9
        \is_string($array)
1326
        ||
1327 9
        ($isObject && \method_exists($array, '__toString'))
1328
    ) {
1329 7
      return [(string)$array];
1330
    }
1331
1332 2
    throw new \InvalidArgumentException(
1333 2
        '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 8
  public function fillWithDefaults(int $num, $default = null)
1346
  {
1347 8
    if ($num < 0) {
1348 1
      throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1349
    }
1350
1351 7
    $tmpArray = $this->array;
1352
1353 7
    $count = \count($tmpArray);
1354
1355 7
    while ($count < $num) {
1356 4
      $tmpArray[] = $default;
1357 4
      $count++;
1358
    }
1359
1360 7
    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
   *                               <li>
1384
   *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1385
   *                               arguments to <i>callback</i> instead of the value</span>
1386
   *                               </li>
1387
   *                               </ul>
1388
   *
1389
   * @return static <p>(Immutable)</p>
1390
   */
1391 10
  public function filter($closure = null, int $flag = ARRAY_FILTER_USE_BOTH)
1392
  {
1393 10
    if (!$closure) {
1394 1
      return $this->clean();
1395
    }
1396
1397 10
    $array = \array_filter($this->array, $closure, $flag);
1398
1399 10
    return static::create($array);
1400
  }
1401
1402
  /**
1403
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
1404
   * within that.
1405
   *
1406
   * @param string          $property
1407
   * @param string|string[] $value
1408
   * @param string          $comparisonOp
1409
   *                            <p>
1410
   *                            'eq' (equals),<br />
1411
   *                            'gt' (greater),<br />
1412
   *                            'gte' || 'ge' (greater or equals),<br />
1413
   *                            'lt' (less),<br />
1414
   *                            'lte' || 'le' (less or equals),<br />
1415
   *                            'ne' (not equals),<br />
1416
   *                            'contains',<br />
1417
   *                            'notContains',<br />
1418
   *                            'newer' (via strtotime),<br />
1419
   *                            'older' (via strtotime),<br />
1420
   *                            </p>
1421
   *
1422
   * @return static <p>(Immutable)</p>
1423
   */
1424 1
  public function filterBy(string $property, $value, string $comparisonOp = null)
1425
  {
1426 1
    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 1
      $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1428
    }
1429
1430
    $ops = [
1431 1
        'eq'          => function ($item, $prop, $value) {
1432 1
          return $item[$prop] === $value;
1433 1
        },
1434 1
        'gt'          => function ($item, $prop, $value) {
1435
          return $item[$prop] > $value;
1436 1
        },
1437 1
        'ge'          => function ($item, $prop, $value) {
1438
          return $item[$prop] >= $value;
1439 1
        },
1440 1
        'gte'         => function ($item, $prop, $value) {
1441
          return $item[$prop] >= $value;
1442 1
        },
1443 1
        'lt'          => function ($item, $prop, $value) {
1444 1
          return $item[$prop] < $value;
1445 1
        },
1446 1
        'le'          => function ($item, $prop, $value) {
1447
          return $item[$prop] <= $value;
1448 1
        },
1449 1
        'lte'         => function ($item, $prop, $value) {
1450
          return $item[$prop] <= $value;
1451 1
        },
1452 1
        'ne'          => function ($item, $prop, $value) {
1453
          return $item[$prop] !== $value;
1454 1
        },
1455 1
        'contains'    => function ($item, $prop, $value) {
1456 1
          return \in_array($item[$prop], (array)$value, true);
1457 1
        },
1458 1
        'notContains' => function ($item, $prop, $value) {
1459
          return !\in_array($item[$prop], (array)$value, true);
1460 1
        },
1461 1
        'newer'       => function ($item, $prop, $value) {
1462
          return \strtotime($item[$prop]) > \strtotime($value);
1463 1
        },
1464 1
        'older'       => function ($item, $prop, $value) {
1465
          return \strtotime($item[$prop]) < \strtotime($value);
1466 1
        },
1467
    ];
1468
1469 1
    $result = \array_values(
1470 1
        \array_filter(
1471 1
            (array)$this->array,
1472 1
            function ($item) use (
1473 1
                $property,
1474 1
                $value,
1475 1
                $ops,
1476 1
                $comparisonOp
1477
            ) {
1478 1
              $item = (array)$item;
1479 1
              $itemArrayy = new Arrayy($item);
1480 1
              $item[$property] = $itemArrayy->get($property, []);
1481
1482 1
              return $ops[$comparisonOp]($item, $property, $value);
1483 1
            }
1484
        )
1485
    );
1486
1487 1
    return static::create($result);
1488
  }
1489
1490
  /**
1491
   * Find the first item in an array that passes the truth test,
1492
   *  otherwise return false
1493
   *
1494
   * @param \Closure $closure
1495
   *
1496
   * @return mixed|false <p>Return false if we did not find the value.</p>
1497
   */
1498 8 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 8
    foreach ($this->array as $key => $value) {
1501 6
      if ($closure($value, $key)) {
1502 6
        return $value;
1503
      }
1504
    }
1505
1506 3
    return false;
1507
  }
1508
1509
  /**
1510
   * find by ...
1511
   *
1512
   * @param string          $property
1513
   * @param string|string[] $value
1514
   * @param string          $comparisonOp
1515
   *
1516
   * @return static <p>(Immutable)</p>
1517
   */
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
   */
1528 14
  public function first()
1529
  {
1530 14
    $tmpArray = $this->array;
1531 14
    $result = \array_shift($tmpArray);
1532
1533 14
    if ($result === null) {
1534 3
      return null;
1535
    }
1536
1537 11
    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
   *
1545
   * @return static <p>(Immutable)</p>
1546
   */
1547 28
  public function firstsImmutable(int $number = null)
1548
  {
1549 28
    if ($number === null) {
1550 7
      $arrayTmp = $this->array;
1551 7
      $array = (array)\array_shift($arrayTmp);
1552
    } else {
1553 21
      $number = (int)$number;
1554 21
      $arrayTmp = $this->array;
1555 21
      $array = \array_splice($arrayTmp, 0, $number, true);
1556
    }
1557
1558 28
    return static::create($array);
1559
  }
1560
1561
  /**
1562
   * Get the first value(s) from the current array.
1563
   *
1564
   * @param int|null $number <p>How many values you will take?</p>
1565
   *
1566
   * @return static <p>(Mutable)</p>
1567
   */
1568 26
  public function firstsMutable(int $number = null)
1569
  {
1570 26
    if ($number === null) {
1571 11
      $this->array = (array)\array_shift($this->array);
1572
    } else {
1573 15
      $number = (int)$number;
1574 15
      $this->array = \array_splice($this->array, 0, $number, true);
1575
    }
1576
1577 26
    return $this;
1578
  }
1579
1580
  /**
1581
   * Exchanges all keys with their associated values in an array.
1582
   *
1583
   * @return static <p>(Immutable)</p>
1584
   */
1585 1
  public function flip()
1586
  {
1587 1
    $result = \array_flip($this->array);
1588
1589 1
    return static::create($result);
1590
  }
1591
1592
  /**
1593
   * Get a value from an array (optional using dot-notation).
1594
   *
1595
   * @param mixed $key       <p>The key to look for.</p>
1596
   * @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
   *
1600
   * @return mixed|static
1601
   */
1602 63
  public function get($key, $fallback = null, array $array = null)
1603
  {
1604 63
    if ($array !== null) {
1605 3
      $usedArray = $array;
1606
    } else {
1607 60
      $usedArray = $this->array;
1608
    }
1609
1610 63
    if ($key === null) {
1611 1
      return static::create($usedArray);
1612
    }
1613
1614
    // php cast "bool"-index into "int"-index
1615 63
    if ((bool)$key === $key) {
1616 2
      $key = (int)$key;
1617
    }
1618
1619 63
    if (\array_key_exists($key, $usedArray) === true) {
1620 53
      if (\is_array($usedArray[$key])) {
1621 8
        return static::create($usedArray[$key]);
1622
      }
1623
1624 47
      return $usedArray[$key];
1625
    }
1626
1627
    // Crawl through array, get key according to object or not
1628 21
    foreach (\explode($this->pathSeparator, (string)$key) as $segment) {
1629 21
      if (!isset($usedArray[$segment])) {
1630 20
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1631
      }
1632
1633 6
      $usedArray = $usedArray[$segment];
1634
    }
1635
1636 6
    if (\is_array($usedArray)) {
1637 1
      return static::create($usedArray);
1638
    }
1639
1640 6
    return $usedArray;
1641
  }
1642
1643
  /**
1644
   * Get the current array from the "Arrayy"-object.
1645
   *
1646
   * @return array
1647
   */
1648 579
  public function getArray(): array
1649
  {
1650 579
    \array_map(['self', 'internalGetArray'], $this->array);
1651
1652 579
    foreach ($this->array as $key => $item) {
1653 477
      if ($item instanceof self) {
1654 477
        $this->array[$key] = $item->getArray();
1655
      }
1656
    }
1657
1658 579
    return $this->array;
1659
  }
1660
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
   *
1671
   * @return static <p>(Immutable)</p>
1672
   */
1673 1
  public function getColumn($columnKey = null, $indexKey = null)
1674
  {
1675 1
    $result = \array_column($this->array, $columnKey, $indexKey);
1676
1677 1
    return static::create($result);
1678
  }
1679
1680
  /**
1681
   * Get correct PHP constant for direction.
1682
   *
1683
   * @param int|string $direction
1684
   *
1685
   * @return int
1686
   */
1687 38
  protected function getDirection($direction): int
1688
  {
1689 38
    if (\is_string($direction)) {
1690 10
      $direction = \strtolower($direction);
1691
1692 10
      if ($direction === 'desc') {
1693 2
        $direction = SORT_DESC;
1694
      } else {
1695 8
        $direction = SORT_ASC;
1696
      }
1697
    }
1698
1699
    if (
1700 38
        $direction !== SORT_DESC
1701
        &&
1702 38
        $direction !== SORT_ASC
1703
    ) {
1704
      $direction = SORT_ASC;
1705
    }
1706
1707 38
    return $direction;
1708
  }
1709
1710
  /**
1711
   * alias: for "Arrayy->keys()"
1712
   *
1713
   * @see Arrayy::keys()
1714
   *
1715
   * @return static <p>(Immutable)</p>
1716
   */
1717 1
  public function getKeys()
1718
  {
1719 1
    return $this->keys();
1720
  }
1721
1722
  /**
1723
   * Get the current array from the "Arrayy"-object as object.
1724
   *
1725
   * @return \stdClass (object)
1726
   */
1727 4
  public function getObject(): \stdClass
1728
  {
1729 4
    return self::arrayToObject($this->getArray());
1730
  }
1731
1732
  /**
1733
   * alias: for "Arrayy->randomImmutable()"
1734
   *
1735
   * @see Arrayy::randomImmutable()
1736
   *
1737
   * @return static <p>(Immutable)</p>
1738
   */
1739 4
  public function getRandom()
1740
  {
1741 4
    return $this->randomImmutable();
1742
  }
1743
1744
  /**
1745
   * alias: for "Arrayy->randomKey()"
1746
   *
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 3
  public function getRandomKey()
1752
  {
1753 3
    return $this->randomKey();
1754
  }
1755
1756
  /**
1757
   * alias: for "Arrayy->randomKeys()"
1758
   *
1759
   * @see Arrayy::randomKeys()
1760
   *
1761
   * @param int $number
1762
   *
1763
   * @return static <p>(Immutable)</p>
1764
   */
1765 8
  public function getRandomKeys(int $number)
1766
  {
1767 8
    return $this->randomKeys($number);
1768
  }
1769
1770
  /**
1771
   * alias: for "Arrayy->randomValue()"
1772
   *
1773
   * @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
  {
1779 3
    return $this->randomValue();
1780
  }
1781
1782
  /**
1783
   * alias: for "Arrayy->randomValues()"
1784
   *
1785
   * @see Arrayy::randomValues()
1786
   *
1787
   * @param int $number
1788
   *
1789
   * @return static <p>(Immutable)</p>
1790
   */
1791 6
  public function getRandomValues(int $number)
1792
  {
1793 6
    return $this->randomValues($number);
1794
  }
1795
1796
  /**
1797
   * Group values from a array according to the results of a closure.
1798
   *
1799
   * @param \callable $grouper <p>A callable function name.</p>
1800
   * @param bool      $saveKeys
1801
   *
1802
   * @return static <p>(Immutable)</p>
1803
   */
1804 3
  public function group($grouper, bool $saveKeys = false)
1805
  {
1806 3
    $array = (array)$this->array;
1807 3
    $result = [];
1808
1809
    // Iterate over values, group by property/results from closure.
1810 3
    foreach ($array as $key => $value) {
1811
1812 3
      $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $array);
1813 3
      $newValue = $this->get($groupKey, null, $result);
1814
1815 3
      if ($groupKey instanceof self) {
1816
        $groupKey = $groupKey->getArray();
1817
      }
1818
1819 3
      if ($newValue instanceof self) {
1820 3
        $newValue = $newValue->getArray();
1821
      }
1822
1823
      // Add to results.
1824 3
      if ($groupKey !== null) {
1825 2
        if ($saveKeys) {
1826 1
          $result[$groupKey] = $newValue;
1827 1
          $result[$groupKey][$key] = $value;
1828
        } else {
1829 1
          $result[$groupKey] = $newValue;
1830 3
          $result[$groupKey][] = $value;
1831
        }
1832
      }
1833
1834
    }
1835
1836 3
    return static::create($result);
1837
  }
1838
1839
  /**
1840
   * Check if an array has a given key.
1841
   *
1842
   * @param mixed $key
1843
   *
1844
   * @return bool
1845
   */
1846 23
  public function has($key): bool
1847
  {
1848 23
    static $UN_FOUND = null;
1849
1850 23
    if ($UN_FOUND === null) {
1851
      // Generate unique string to use as marker.
1852 1
      $UN_FOUND = \uniqid('arrayy', true);
1853
    }
1854
1855 23
    return $this->get($key, $UN_FOUND) !== $UN_FOUND;
1856
  }
1857
1858
  /**
1859
   * Implodes the values of this array.
1860
   *
1861
   * @param string $glue
1862
   *
1863
   * @return string
1864
   */
1865 27
  public function implode(string $glue = ''): string
1866
  {
1867 27
    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 8
  public function implodeKeys(string $glue = ''): string
1878
  {
1879 8
    return $this->implode_recursive($glue, $this->array, true);
1880
  }
1881
1882
  /**
1883
   * @param mixed               $glue
1884
   * @param string|array|static $pieces
1885
   * @param bool                $useKeys
1886
   *
1887
   * @return string
1888
   */
1889 35
  protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
1890
  {
1891 35
    if ($pieces instanceof self) {
1892 1
      $pieces = $pieces->getArray();
1893
    }
1894
1895 35
    if (\is_array($pieces)) {
1896 35
      $pieces_count = \count($pieces, COUNT_NORMAL);
1897 35
      $pieces_count_not_zero = $pieces_count > 0;
1898
1899 35
      return \implode(
1900 35
          $glue,
1901 35
          \array_map(
1902 35
              [$this, 'implode_recursive'],
1903 35
              \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
1904 35
              ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
1905
          )
1906
      );
1907
    }
1908
1909 35
    return (string)$pieces;
1910
  }
1911
1912
  /**
1913
   * @param mixed $needle   <p>
1914
   *                        The searched value.
1915
   *                        </p>
1916
   *                        <p>
1917
   *                        If needle is a string, the comparison is done
1918
   *                        in a case-sensitive manner.
1919
   *                        </p>
1920
   * @param array $haystack <p>
1921
   *                        The array.
1922
   *                        </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
   *                        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 45
  protected function in_array_recursive($needle, array $haystack = null, $strict = true): bool
1933
  {
1934 45
    if ($haystack === null) {
1935
      $haystack = $this->array;
1936
    }
1937
1938 45
    foreach ($haystack as $item) {
1939
1940 37
      if (\is_array($item) === true) {
1941 9
        $returnTmp = $this->in_array_recursive($needle, $item, $strict);
1942
      } else {
1943 37
        $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
1944
      }
1945
1946 37
      if ($returnTmp === true) {
1947 37
        return true;
1948
      }
1949
    }
1950
1951 18
    return false;
1952
  }
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
   *
1959
   * @param mixed $key
1960
   *
1961
   * @return static <p>(Immutable)</p>
1962
   */
1963 3
  public function indexBy($key)
1964
  {
1965 3
    $results = [];
1966
1967 3
    foreach ($this->array as $a) {
1968 3
      if (\array_key_exists($key, $a) === true) {
1969 3
        $results[$a[$key]] = $a;
1970
      }
1971
    }
1972
1973 3
    return static::create($results);
1974
  }
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
   * @return mixed
1984
   */
1985 4
  public function indexOf($value)
1986
  {
1987 4
    return $this->searchIndex($value);
1988
  }
1989
1990
  /**
1991
   * Get everything but the last..$to items.
1992
   *
1993
   * @param int $to
1994
   *
1995
   * @return static <p>(Immutable)</p>
1996
   */
1997 12
  public function initial(int $to = 1)
1998
  {
1999 12
    return $this->firstsImmutable(\count($this->array, COUNT_NORMAL) - $to);
2000
  }
2001
2002
  /**
2003
   * @param mixed $value
2004
   */
2005 477
  protected function internalGetArray(&$value)
2006
  {
2007 477
    if ($value instanceof self) {
2008
2009
      $valueTmp = $value->getArray();
2010
      if (\count($valueTmp, COUNT_NORMAL) === 0) {
2011
        $value = [];
2012
      } else {
2013
        /** @noinspection PhpUnusedLocalVariableInspection */
2014
        $value = &$valueTmp;
2015
      }
2016
2017 477
    } 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
    }
2021 477
  }
2022
2023
  /**
2024
   * Internal mechanics of remove method.
2025
   *
2026
   * @param mixed $key
2027
   *
2028
   * @return bool
2029
   */
2030 18
  protected function internalRemove($key): bool
2031
  {
2032 18
    $path = \explode($this->pathSeparator, (string)$key);
2033
2034
    // Crawl though the keys
2035 18
    while (\count($path, COUNT_NORMAL) > 1) {
2036
      $key = \array_shift($path);
2037
2038
      if (!$this->has($key)) {
2039
        return false;
2040
      }
2041
2042
      $this->array = &$this->array[$key];
2043
    }
2044
2045 18
    $key = \array_shift($path);
2046
2047 18
    unset($this->array[$key]);
2048
2049 18
    return true;
2050
  }
2051
2052
  /**
2053
   * Internal mechanic of set method.
2054
   *
2055
   * @param mixed $key
2056
   * @param mixed $value
2057
   *
2058
   * @return bool
2059
   */
2060 30
  protected function internalSet($key, $value): bool
2061
  {
2062 30
    if ($key === null) {
2063
      return false;
2064
    }
2065
2066
    // init
2067 30
    $array =& $this->array;
2068 30
    $path = \explode($this->pathSeparator, (string)$key);
2069
2070
    // Crawl through the keys
2071 30
    while (\count($path, COUNT_NORMAL) > 1) {
2072 3
      $key = \array_shift($path);
2073
2074 3
      $array =& $array[$key];
2075
    }
2076
2077 30
    $array[\array_shift($path)] = $value;
2078
2079 30
    return true;
2080
  }
2081
2082
  /**
2083
   * Return an array with all elements found in input array.
2084
   *
2085
   * @param array $search
2086
   *
2087
   * @return static <p>(Immutable)</p>
2088
   */
2089 2
  public function intersection(array $search)
2090
  {
2091 2
    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 1
  public function intersects(array $search): bool
2102
  {
2103 1
    return \count($this->intersection($search)->array, COUNT_NORMAL) > 0;
2104
  }
2105
2106
  /**
2107
   * Invoke a function on all of an array's values.
2108
   *
2109
   * @param mixed $callable
2110
   * @param mixed $arguments
2111
   *
2112
   * @return static <p>(Immutable)</p>
2113
   */
2114 1
  public function invoke($callable, $arguments = [])
2115
  {
2116
    // If one argument given for each iteration, create an array for it.
2117 1
    if (!\is_array($arguments)) {
2118 1
      $arguments = StaticArrayy::repeat(
2119 1
          $arguments,
2120 1
          \count($this->array, COUNT_NORMAL)
2121 1
      )->getArray();
2122
    }
2123
2124
    // If the callable has arguments, pass them.
2125 1
    if ($arguments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arguments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2126 1
      $array = \array_map($callable, $this->array, $arguments);
2127
    } else {
2128 1
      $array = \array_map($callable, $this->array);
2129
    }
2130
2131 1
    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 15
  public function isAssoc(bool $recursive = false): bool
2142
  {
2143 15
    if ($this->isEmpty()) {
2144 3
      return false;
2145
    }
2146
2147 13
    foreach ($this->keys($recursive)->getArray() as $key) {
2148 13
      if (!\is_string($key)) {
2149 13
        return false;
2150
      }
2151
    }
2152
2153 3
    return true;
2154
  }
2155
2156
  /**
2157
   * Check whether the array is empty or not.
2158
   *
2159
   * @return bool <p>Returns true if empty, false otherwise.</p>
2160
   */
2161 88
  public function isEmpty(): bool
2162
  {
2163 88
    return !$this->array;
2164
  }
2165
2166
  /**
2167
   * Check if the current array is equal to the given "$array" or not.
2168
   *
2169
   * @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
   * Check if the current array is a multi-array.
2180
   *
2181
   * @return bool
2182
   */
2183 14
  public function isMultiArray(): bool
2184
  {
2185
    return !(
2186 14
        \count($this->array, COUNT_NORMAL)
2187
        ===
2188 14
        \count($this->array, COUNT_RECURSIVE)
2189
    );
2190
  }
2191
2192
  /**
2193
   * Check whether array is numeric or not.
2194
   *
2195
   * @return bool <p>Returns true if numeric, false otherwise.</p>
2196
   */
2197 5
  public function isNumeric(): bool
2198
  {
2199 5
    if ($this->isEmpty()) {
2200 2
      return false;
2201
    }
2202
2203 4
    foreach ($this->keys() as $key) {
2204 4
      if (!\is_int($key)) {
2205 4
        return false;
2206
      }
2207
    }
2208
2209 2
    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 1
  public function isSequential(bool $recursive = false): bool
2220
  {
2221
2222
    // recursive
2223
2224 1
    if ($recursive === true) {
2225
      return $this->array_keys_recursive($this->array)
2226
             ===
2227
             \range(0, \count($this->array, COUNT_RECURSIVE) - 1);
2228
    }
2229
2230
    // non recursive
2231
2232 1
    return \array_keys($this->array)
2233
           ===
2234 1
           \range(0, \count($this->array, COUNT_NORMAL) - 1);
2235
  }
2236
2237
  /**
2238
   * @return array
2239
   */
2240
  public function jsonSerialize(): array
2241
  {
2242
    return $this->getArray();
2243
  }
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
   *
2258
   * @return static <p>(Immutable) An array of all the keys in input.</p>
2259
   */
2260 26
  public function keys(bool $recursive = false, $search_value = null, bool $strict = true)
2261
  {
2262
2263
    // recursive
2264
2265 26
    if ($recursive === true) {
2266 3
      if ($search_value === null) {
2267 3
        $array = $this->array_keys_recursive($this->array);
2268
      } else {
2269
        $array = $this->array_keys_recursive($this->array, $search_value, $strict);
2270
      }
2271
2272 3
      return static::create($array);
2273
    }
2274
2275
    // non recursive
2276
2277 25
    if ($search_value === null) {
2278 25
      $array = \array_keys($this->array);
2279
    } else {
2280
      $array = \array_keys($this->array, $search_value, $strict);
2281
    }
2282
2283 25
    return static::create($array);
2284
  }
2285
2286
  /**
2287
   * Sort an array by key in reverse order.
2288
   *
2289
   * @param int $sort_flags [optional] <p>
2290
   *                        You may modify the behavior of the sort using the optional
2291
   *                        parameter sort_flags, for details
2292
   *                        see sort.
2293
   *                        </p>
2294
   *
2295
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2296
   */
2297 4
  public function krsort(int $sort_flags = 0)
2298
  {
2299 4
    krsort($this->array, $sort_flags);
2300
2301 4
    return $this;
2302
  }
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 4
  public function last()
2310
  {
2311 4
    return $this->pop();
2312
  }
2313
2314
  /**
2315
   * Get the last value(s) from the current array.
2316
   *
2317
   * @param int|null $number
2318
   *
2319
   * @return static <p>(Immutable)</p>
2320
   */
2321 13
  public function lastsImmutable(int $number = null)
2322
  {
2323 13
    if ($this->isEmpty()) {
2324 1
      return static::create();
2325
    }
2326
2327 12
    if ($number === null) {
2328 8
      $poppedValue = $this->pop();
2329
2330 8
      if ($poppedValue === null) {
2331 1
        $poppedValue = [$poppedValue];
2332
      } else {
2333 7
        $poppedValue = (array)$poppedValue;
2334
      }
2335
2336 8
      $arrayy = static::create($poppedValue);
2337
    } else {
2338 4
      $number = (int)$number;
2339 4
      $arrayy = $this->rest(-$number);
2340
    }
2341
2342 12
    return $arrayy;
2343
  }
2344
2345
  /**
2346
   * Get the last value(s) from the current array.
2347
   *
2348
   * @param int|null $number
2349
   *
2350
   * @return static <p>(Mutable)</p>
2351
   */
2352 13
  public function lastsMutable(int $number = null)
2353
  {
2354 13
    if ($this->isEmpty()) {
2355 1
      return $this;
2356
    }
2357
2358 12
    if ($number === null) {
2359 8
      $poppedValue = $this->pop();
2360
2361 8
      if ($poppedValue === null) {
2362 1
        $poppedValue = [$poppedValue];
2363
      } else {
2364 7
        $poppedValue = (array)$poppedValue;
2365
      }
2366
2367 8
      $this->array = static::create($poppedValue)->array;
2368
    } else {
2369 4
      $number = (int)$number;
2370 4
      $this->array = $this->rest(-$number)->array;
2371
    }
2372
2373 12
    return $this;
2374
  }
2375
2376
  /**
2377
   * Count the values from the current array.
2378
   *
2379
   * alias: for "Arrayy->count()"
2380
   *
2381
   * @see Arrayy::count()
2382
   *
2383
   * @param int $mode
2384
   *
2385
   * @return int
2386
   */
2387 20
  public function length(int $mode = COUNT_NORMAL): int
2388
  {
2389 20
    return $this->count($mode);
2390
  }
2391
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 4
  public function map($callable)
2401
  {
2402 4
    $result = \array_map($callable, $this->array);
2403
2404 4
    return static::create($result);
2405
  }
2406
2407
  /**
2408
   * Check if all items in current array match a truth test.
2409
   *
2410
   * @param \Closure $closure
2411
   *
2412
   * @return bool
2413
   */
2414 15 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 15
    if (\count($this->array, COUNT_NORMAL) === 0) {
2417 2
      return false;
2418
    }
2419
2420
    // init
2421 13
    $array = $this->array;
2422
2423 13
    foreach ($array as $key => $value) {
2424 13
      $value = $closure($value, $key);
2425
2426 13
      if ($value === false) {
2427 13
        return false;
2428
      }
2429
    }
2430
2431 7
    return true;
2432
  }
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 14 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 14
    if (\count($this->array, COUNT_NORMAL) === 0) {
2444 2
      return false;
2445
    }
2446
2447
    // init
2448 12
    $array = $this->array;
2449
2450 12
    foreach ($array as $key => $value) {
2451 12
      $value = $closure($value, $key);
2452
2453 12
      if ($value === true) {
2454 12
        return true;
2455
      }
2456
    }
2457
2458 4
    return false;
2459
  }
2460
2461
  /**
2462
   * Get the max value from an array.
2463
   *
2464
   * @return mixed
2465
   */
2466 10 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
  {
2468 10
    if (\count($this->array, COUNT_NORMAL) === 0) {
2469 1
      return false;
2470
    }
2471
2472 9
    return max($this->array);
2473
  }
2474
2475
  /**
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 25 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 25
    if (true === $recursive) {
2488 4
      $result = \array_replace_recursive($this->array, $array);
2489
    } else {
2490 21
      $result = \array_replace($this->array, $array);
2491
    }
2492
2493 25
    return static::create($result);
2494
  }
2495
2496
  /**
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 16 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 16
    if (true === $recursive) {
2510 4
      $result = \array_merge_recursive($this->array, $array);
2511
    } else {
2512 12
      $result = \array_merge($this->array, $array);
2513
    }
2514
2515 16
    return static::create($result);
2516
  }
2517
2518
  /**
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
   * @return static <p>(Immutable)</p>
2527
   */
2528 16 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
  {
2530 16
    if (true === $recursive) {
2531 4
      $result = \array_replace_recursive($array, $this->array);
2532
    } else {
2533 12
      $result = \array_replace($array, $this->array);
2534
    }
2535
2536 16
    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
   * @param array $array
2546
   * @param bool  $recursive
2547
   *
2548
   * @return static <p>(Immutable)</p>
2549
   */
2550 17 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
  {
2552 17
    if (true === $recursive) {
2553 4
      $result = \array_merge_recursive($array, $this->array);
2554
    } else {
2555 13
      $result = \array_merge($array, $this->array);
2556
    }
2557
2558 17
    return static::create($result);
2559
  }
2560
2561
  /**
2562
   * Get the min value from an array.
2563
   *
2564
   * @return mixed
2565
   */
2566 10 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 10
    if (\count($this->array, COUNT_NORMAL) === 0) {
2569 1
      return false;
2570
    }
2571
2572 9
    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
   * @param int|string $from
2581
   * @param int|string $to
2582
   *
2583
   * @return static <p>(Immutable)</p>
2584
   */
2585 1
  public function moveElement($from, $to)
2586
  {
2587 1
    $array = $this->array;
2588
2589 1
    if (\is_int($from)) {
2590 1
      $tmp = \array_splice($array, $from, 1);
2591 1
      \array_splice($array, $to, 0, $tmp);
2592 1
      $output = $array;
2593 1
    } elseif (\is_string($from)) {
2594 1
      $indexToMove = \array_search($from, \array_keys($array), true);
2595 1
      $itemToMove = $array[$from];
2596 1
      \array_splice($array, $indexToMove, 1);
2597 1
      $i = 0;
2598 1
      $output = [];
2599 1
      foreach ($array as $key => $item) {
2600 1
        if ($i == $to) {
2601 1
          $output[$from] = $itemToMove;
2602
        }
2603 1
        $output[$key] = $item;
2604 1
        $i++;
2605
      }
2606
    } else {
2607
      $output = [];
2608
    }
2609
2610 1
    return static::create($output);
2611
  }
2612
2613
  /**
2614
   * Convert a object into an array.
2615
   *
2616
   * @param object $object
2617
   *
2618
   * @return mixed
2619
   */
2620 5
  protected static function objectToArray($object)
2621
  {
2622 5
    if (!\is_object($object)) {
2623 4
      return $object;
2624
    }
2625
2626 5
    if (\is_object($object)) {
2627 5
      $object = \get_object_vars($object);
2628
    }
2629
2630 5
    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
  public function only(array $keys)
2641
  {
2642
    $array = $this->array;
2643
2644
    return static::create(\array_intersect_key($array, \array_flip($keys)));
2645
  }
2646
2647
  /**
2648
   * Pad array to the specified size with a given value.
2649
   *
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 4
  public function pad(int $size, $value)
2656
  {
2657 4
    $result = \array_pad($this->array, $size, $value);
2658
2659 4
    return static::create($result);
2660
  }
2661
2662
  /**
2663
   * Pop a specified value off the end of the current array.
2664
   *
2665
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
2666
   */
2667 16
  public function pop()
2668
  {
2669 16
    return \array_pop($this->array);
2670
  }
2671
2672
  /**
2673
   * 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 8
  public function prepend($value, $key = null)
2681
  {
2682 8
    if ($key === null) {
2683 8
      \array_unshift($this->array, $value);
2684
    } else {
2685
      /** @noinspection AdditionOperationOnArraysInspection */
2686 1
      $this->array = [$key => $value] + $this->array;
2687
    }
2688
2689 8
    return $this;
2690
  }
2691
2692
  /**
2693
   * Add a suffix to each key.
2694
   *
2695
   * @param mixed $suffix
2696
   *
2697
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2698
   */
2699 10 View Code Duplication
  public function prependToEachKey($suffix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2700
  {
2701 10
    $result = [];
2702 10
    foreach ($this->array as $key => $item) {
2703 9
      if ($item instanceof self) {
2704
        $result[$key] = $item->prependToEachKey($suffix);
2705 9
      } elseif (\is_array($item)) {
2706
        $result[$key] = self::create($item)->prependToEachKey($suffix)->toArray();
2707
      } else {
2708 9
        $result[$key . $suffix] = $item;
2709
      }
2710
2711
    }
2712
2713 10
    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 10 View Code Duplication
  public function prependToEachValue($suffix)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2724
  {
2725 10
    $result = [];
2726 10
    foreach ($this->array as $key => $item) {
2727 9
      if ($item instanceof self) {
2728
        $result[$key] = $item->prependToEachValue($suffix);
2729 9
      } elseif (\is_array($item)) {
2730
        $result[$key] = self::create($item)->prependToEachValue($suffix)->toArray();
2731 9
      } elseif (\is_object($item)) {
2732 1
        $result[$key] = $item;
2733
      } else {
2734 9
        $result[$key] = $item . $suffix;
2735
      }
2736
    }
2737
2738 10
    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 4 View Code Duplication
  public function push(/* variadic arguments allowed */)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2747
  {
2748 4
    if (\func_num_args()) {
2749 4
      $args = \array_merge([&$this->array], \func_get_args());
2750 4
      \array_push(...$args);
2751
    }
2752
2753 4
    return $this;
2754
  }
2755
2756
  /**
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 18
  public function randomImmutable(int $number = null)
2764
  {
2765 18
    if (\count($this->array, COUNT_NORMAL) === 0) {
2766 1
      return static::create();
2767
    }
2768
2769 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2770
      /** @noinspection NonSecureArrayRandUsageInspection */
2771 14
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2772
2773 14
      return static::create($arrayRandValue);
2774
    }
2775
2776 5
    $arrayTmp = $this->array;
2777
    /** @noinspection NonSecureShuffleUsageInspection */
2778 5
    \shuffle($arrayTmp);
2779
2780 5
    return static::create($arrayTmp)->firstsImmutable($number);
2781
  }
2782
2783
  /**
2784
   * 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 4
  public function randomKey()
2791
  {
2792 4
    $result = $this->randomKeys(1);
2793
2794 4
    if (!isset($result[0])) {
2795
      $result[0] = null;
2796
    }
2797
2798 4
    return $result[0];
2799
  }
2800
2801
  /**
2802
   * Pick a given number of random keys/indexes out of this array.
2803
   *
2804
   * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2805
   *
2806
   * @return static <p>(Immutable)</p>
2807
   *
2808
   * @throws \RangeException If array is empty
2809
   */
2810 13
  public function randomKeys(int $number)
2811
  {
2812 13
    $count = \count($this->array, COUNT_NORMAL);
2813
2814 13
    if ($number === 0 || $number > $count) {
2815 2
      throw new \RangeException(
2816 2
          \sprintf(
2817 2
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2818 2
              $number,
2819 2
              $count
2820
          )
2821
      );
2822
    }
2823
2824 11
    $result = (array)\array_rand($this->array, $number);
2825
2826 11
    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
   */
2836 17
  public function randomMutable(int $number = null)
2837
  {
2838 17
    if (\count($this->array, COUNT_NORMAL) === 0) {
2839
      return static::create();
2840
    }
2841
2842 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2843
      /** @noinspection NonSecureArrayRandUsageInspection */
2844 7
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2845 7
      $this->array = $arrayRandValue;
2846
2847 7
      return $this;
2848
    }
2849
2850
    /** @noinspection NonSecureShuffleUsageInspection */
2851 11
    \shuffle($this->array);
2852
2853 11
    return $this->firstsMutable($number);
2854
  }
2855
2856
  /**
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 4
  public function randomValue()
2862
  {
2863 4
    $result = $this->randomImmutable();
2864
2865 4
    if (!isset($result[0])) {
2866
      $result[0] = null;
2867
    }
2868
2869 4
    return $result[0];
2870
  }
2871
2872
  /**
2873
   * Pick a given number of random values out of this array.
2874
   *
2875
   * @param int $number
2876
   *
2877
   * @return static <p>(Mutable)</p>
2878
   */
2879 7
  public function randomValues(int $number)
2880
  {
2881 7
    return $this->randomMutable($number);
2882
  }
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
   * @param null|int $number <p>How many values you will take?</p>
2891
   *
2892
   * @return static <p>(Immutable)</p>
2893
   */
2894 9
  public function randomWeighted(array $array, int $number = null)
2895
  {
2896 9
    $options = [];
2897 9
    foreach ($array as $option => $weight) {
2898 9
      if ($this->searchIndex($option) !== false) {
2899 9
        for ($i = 0; $i < $weight; ++$i) {
2900 1
          $options[] = $option;
2901
        }
2902
      }
2903
    }
2904
2905 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2906
  }
2907
2908
  /**
2909
   * Reduce the current array via callable e.g. anonymous-function.
2910
   *
2911
   * @param \callable $callable
2912
   * @param array     $init
2913
   *
2914
   * @return static <p>(Immutable)</p>
2915
   */
2916 4
  public function reduce($callable, array $init = [])
2917
  {
2918 4
    $result = \array_reduce($this->array, $callable, $init);
2919
2920 4
    if ($result === null) {
2921
      $this->array = [];
2922
    } else {
2923 4
      $this->array = (array)$result;
2924
    }
2925
2926 4
    return static::create($this->array);
2927
  }
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 9
  public function reindex()
2935
  {
2936 9
    $this->array = \array_values($this->array);
2937
2938 9
    return $this;
2939
  }
2940
2941
  /**
2942
   * Return all items that fail the truth test.
2943
   *
2944
   * @param \Closure $closure
2945
   *
2946
   * @return static <p>(Immutable)</p>
2947
   */
2948 1 View Code Duplication
  public function reject(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2949
  {
2950 1
    $filtered = [];
2951
2952 1
    foreach ($this->array as $key => $value) {
2953 1
      if (!$closure($value, $key)) {
2954 1
        $filtered[$key] = $value;
2955
      }
2956
    }
2957
2958 1
    return static::create($filtered);
2959
  }
2960
2961
  /**
2962
   * Remove a value from the current array (optional using dot-notation).
2963
   *
2964
   * @param mixed $key
2965
   *
2966
   * @return static <p>(Immutable)</p>
2967
   */
2968 18
  public function remove($key)
2969
  {
2970
    // recursive call
2971 18
    if (\is_array($key)) {
2972
      foreach ($key as $k) {
2973
        $this->internalRemove($k);
2974
      }
2975
2976
      return static::create($this->array);
2977
    }
2978
2979 18
    $this->internalRemove($key);
2980
2981 18
    return static::create($this->array);
2982
  }
2983
2984
  /**
2985
   * Remove the first value from the current array.
2986
   *
2987
   * @return static <p>(Immutable)</p>
2988
   */
2989 7
  public function removeFirst()
2990
  {
2991 7
    $tmpArray = $this->array;
2992 7
    \array_shift($tmpArray);
2993
2994 7
    return static::create($tmpArray);
2995
  }
2996
2997
  /**
2998
   * Remove the last value from the current array.
2999
   *
3000
   * @return static <p>(Immutable)</p>
3001
   */
3002 7
  public function removeLast()
3003
  {
3004 7
    $tmpArray = $this->array;
3005 7
    \array_pop($tmpArray);
3006
3007 7
    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 7
  public function removeValue($value)
3018
  {
3019 7
    $isNumericArray = true;
3020 7
    foreach ($this->array as $key => $item) {
3021 6
      if ($item === $value) {
3022 6
        if (!\is_int($key)) {
3023
          $isNumericArray = false;
3024
        }
3025 6
        unset($this->array[$key]);
3026
      }
3027
    }
3028
3029 7
    if ($isNumericArray) {
3030 7
      $this->array = \array_values($this->array);
3031
    }
3032
3033 7
    return static::create($this->array);
3034
  }
3035
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 1
  public function repeat($times): self
3044
  {
3045 1
    if ($times === 0) {
3046 1
      return new static();
3047
    }
3048
3049 1
    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
   * @return static <p>(Immutable)</p>
3060
   */
3061 2
  public function replace($replace, $key, $value)
3062
  {
3063 2
    $this->remove($replace);
3064
3065 2
    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 2
  public function replaceAllKeys(array $keys)
3076
  {
3077 2
    $result = \array_combine($keys, $this->array);
3078
3079 2
    return static::create($result);
3080
  }
3081
3082
  /**
3083
   * Create an array using the current array as keys and the other array as values.
3084
   *
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 2
  public function replaceAllValues(array $array)
3090
  {
3091 2
    $result = \array_combine($this->array, $array);
3092
3093 2
    return static::create($result);
3094
  }
3095
3096
  /**
3097
   * Replace the keys in an array with another set.
3098
   *
3099
   * @param array $keys <p>An array of keys matching the array's size</p>
3100
   *
3101
   * @return static <p>(Immutable)</p>
3102
   */
3103 1
  public function replaceKeys(array $keys)
3104
  {
3105 1
    $values = \array_values($this->array);
3106 1
    $result = \array_combine($keys, $values);
3107
3108 1
    return static::create($result);
3109
  }
3110
3111
  /**
3112
   * Replace the first matched value in an array.
3113
   *
3114
   * @param mixed $search      <p>The value to replace.</p>
3115
   * @param mixed $replacement <p>The value to replace.</p>
3116
   *
3117
   * @return static <p>(Immutable)</p>
3118
   */
3119 3
  public function replaceOneValue($search, $replacement = '')
3120
  {
3121 3
    $array = $this->array;
3122 3
    $key = \array_search($search, $array, true);
3123
3124 3
    if ($key !== false) {
3125 3
      $array[$key] = $replacement;
3126
    }
3127
3128 3
    return static::create($array);
3129
  }
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 1
  public function replaceValues($search, $replacement = '')
3140
  {
3141 1
    $array = $this->each(
3142 1
        function ($value) use ($search, $replacement) {
3143 1
          return UTF8::str_replace($search, $replacement, $value);
3144 1
        }
3145
    );
3146
3147 1
    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 15
  public function rest(int $from = 1)
3158
  {
3159 15
    $tmpArray = $this->array;
3160
3161 15
    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 8
  public function reverse()
3170
  {
3171 8
    $this->array = \array_reverse($this->array);
3172
3173 8
    return $this;
3174
  }
3175
3176
  /**
3177
   * Sort an array in reverse order.
3178
   *
3179
   * @param int $sort_flags [optional] <p>
3180
   *                        You may modify the behavior of the sort using the optional
3181
   *                        parameter sort_flags, for details
3182
   *                        see sort.
3183
   *                        </p>
3184
   *
3185
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3186
   */
3187 4
  public function rsort(int $sort_flags = 0)
3188
  {
3189 4
    \rsort($this->array, $sort_flags);
3190
3191 4
    return $this;
3192
  }
3193
3194
  /**
3195
   * Search for the first index of the current array via $value.
3196
   *
3197
   * @param mixed $value
3198
   *
3199
   * @return int|float|string
3200
   */
3201 20
  public function searchIndex($value)
3202
  {
3203 20
    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 9
  public function searchValue($index)
3214
  {
3215
    // init
3216 9
    $return = [];
3217
3218 9
    if ($this->isEmpty()) {
3219
      return static::create();
3220
    }
3221
3222
    // php cast "bool"-index into "int"-index
3223 9
    if ((bool)$index === $index) {
3224 1
      $index = (int)$index;
3225
    }
3226
3227 9
    if (\array_key_exists($index, $this->array) === true) {
3228 7
      $return = [$this->array[$index]];
3229
    }
3230
3231
3232 9
    return static::create($return);
3233
  }
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 17
  public function set($key, $value)
3244
  {
3245 17
    $this->internalSet($key, $value);
3246
3247 17
    return static::create($this->array);
3248
  }
3249
3250
  /**
3251
   * Get a value from a array and set it if it was not.
3252
   *
3253
   * WARNING: this method only set the value, if the $key is not already set
3254
   *
3255
   * @param mixed $key      <p>The key</p>
3256
   * @param mixed $fallback <p>The default value to set if it isn't.</p>
3257
   *
3258
   * @return mixed <p>(Mutable)</p>
3259
   */
3260 11
  public function setAndGet($key, $fallback = null)
3261
  {
3262
    // If the key doesn't exist, set it.
3263 11
    if (!$this->has($key)) {
3264 4
      $this->array = $this->set($key, $fallback)->getArray();
3265
    }
3266
3267 11
    return $this->get($key);
3268
  }
3269
3270
  /**
3271
   * Shifts a specified value off the beginning of array.
3272
   *
3273
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
3274
   */
3275 4
  public function shift()
3276
  {
3277 4
    return \array_shift($this->array);
3278
  }
3279
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 1
  public function shuffle(bool $secure = false, array $array = null)
3289
  {
3290 1
    if ($array === null) {
3291 1
      $array = $this->array;
3292
    }
3293
3294 1
    if ($secure !== true) {
3295
      /** @noinspection NonSecureShuffleUsageInspection */
3296 1
      \shuffle($array);
3297
    } else {
3298 1
      $size = \count($array, COUNT_NORMAL);
3299 1
      $keys = \array_keys($array);
3300 1
      for ($i = $size - 1; $i > 0; --$i) {
3301
        try {
3302 1
          $r = \random_int(0, $i);
3303
        } catch (\Exception $e) {
3304
          $r = \mt_rand();
3305
        }
3306 1
        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 1
      $array = \array_values($array);
3315
    }
3316
3317 1
    foreach ($array as $key => $value) {
3318
      // check if recursive is needed
3319 1
      if (\is_array($value) === true) {
3320 1
        $array[$key] = $this->shuffle($secure, $value);
3321
      }
3322
    }
3323
3324 1
    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
   */
3336 20
  public function size(int $mode = COUNT_NORMAL): int
3337
  {
3338 20
    return $this->count($mode);
3339
  }
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
   * <p>
3353
   * If var is not an array or an object with
3354
   * implemented Countable interface,
3355
   * 1 will be returned.
3356
   * 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 10
  public function sizeRecursive(): int
3367
  {
3368 10
    return \count($this->array, COUNT_RECURSIVE);
3369
  }
3370
3371
  /**
3372
   * Extract a slice of the array.
3373
   *
3374
   * @param int      $offset       <p>Slice begin index.</p>
3375
   * @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 4
  public function slice(int $offset, int $length = null, bool $preserveKeys = false)
3381
  {
3382 4
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
3383
3384 4
    return static::create($result);
3385
  }
3386
3387
  /**
3388
   * Sort the current array and optional you can keep the keys.
3389
   *
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 19
  public function sort($direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3398
  {
3399 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
3400
3401 19
    return $this;
3402
  }
3403
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 18
  public function sortKeys($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3417
  {
3418 18
    $this->sorterKeys($this->array, $direction, $strategy);
3419
3420 18
    return $this;
3421
  }
3422
3423
  /**
3424
   * Sort the current array by value.
3425
   *
3426
   * @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
   *                              <strong>SORT_NATURAL</strong></p>
3429
   *
3430
   * @return static <p>(Mutable)</p>
3431
   */
3432 1
  public function sortValueKeepIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3433
  {
3434 1
    return $this->sort($direction, $strategy, true);
3435
  }
3436
3437
  /**
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
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3442
   *                              <strong>SORT_NATURAL</strong></p>
3443
   *
3444
   * @return static <p>(Mutable)</p>
3445
   */
3446 1
  public function sortValueNewIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3447
  {
3448 1
    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
   *
3457
   * @param \callable|null $sorter
3458
   * @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
   *
3462
   * @return static <p>(Immutable)</p>
3463
   */
3464 1
  public function sorter($sorter = null, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3465
  {
3466 1
    $array = (array)$this->array;
3467 1
    $direction = $this->getDirection($direction);
3468
3469
    // Transform all values into their results.
3470 1
    if ($sorter) {
3471 1
      $arrayy = static::create($array);
3472
3473 1
      $that = $this;
3474 1
      $results = $arrayy->each(
3475 1
          function ($value) use ($sorter, $that) {
3476 1
            return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3477 1
          }
3478
      );
3479
3480 1
      $results = $results->getArray();
3481
    } else {
3482 1
      $results = $array;
3483
    }
3484
3485
    // Sort by the results and replace by original values
3486 1
    \array_multisort($results, $direction, $strategy, $array);
3487
3488 1
    return static::create($array);
3489
  }
3490
3491
  /**
3492
   * sorting keys
3493
   *
3494
   * @param array      $elements
3495
   * @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
   *                              <strong>SORT_NATURAL</strong></p>
3498
   *
3499
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3500
   */
3501 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3502
  {
3503 18
    $direction = $this->getDirection($direction);
3504
3505
    switch ($direction) {
3506 18
      case 'desc':
3507 18
      case SORT_DESC:
3508 6
        \krsort($elements, $strategy);
3509 6
        break;
3510 13
      case 'asc':
3511 13
      case SORT_ASC:
3512
      default:
3513 13
        \ksort($elements, $strategy);
3514
    }
3515
3516 18
    return $this;
3517
  }
3518
3519
  /**
3520
   * @param array      &$elements
3521
   * @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
   *                              <strong>SORT_NATURAL</strong></p>
3524
   * @param bool       $keepKeys
3525
   *
3526
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3527
   */
3528 19
  protected function sorting(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3529
  {
3530 19
    $direction = $this->getDirection($direction);
3531
3532 19
    if (!$strategy) {
3533 19
      $strategy = SORT_REGULAR;
3534
    }
3535
3536
    switch ($direction) {
3537 19
      case 'desc':
3538 19
      case SORT_DESC:
3539 9
        if ($keepKeys) {
3540 5
          \arsort($elements, $strategy);
3541
        } else {
3542 4
          \rsort($elements, $strategy);
3543
        }
3544 9
        break;
3545 10
      case 'asc':
3546 10
      case SORT_ASC:
3547
      default:
3548 10
        if ($keepKeys) {
3549 4
          \asort($elements, $strategy);
3550
        } else {
3551 6
          \sort($elements, $strategy);
3552
        }
3553
    }
3554
3555 19
    return $this;
3556
  }
3557
3558
  /**
3559
   * Split an array in the given amount of pieces.
3560
   *
3561
   * @param int  $numberOfPieces
3562
   * @param bool $keepKeys
3563
   *
3564
   * @return static <p>(Immutable)</p>
3565
   */
3566 1
  public function split(int $numberOfPieces = 2, bool $keepKeys = false)
3567
  {
3568 1
    $arrayCount = \count($this->array, COUNT_NORMAL);
3569
3570 1
    if ($arrayCount === 0) {
3571 1
      $result = [];
3572
    } else {
3573 1
      $splitSize = (int)\ceil($arrayCount / $numberOfPieces);
3574 1
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
3575
    }
3576
3577 1
    return static::create($result);
3578
  }
3579
3580
  /**
3581
   * Stripe all empty items.
3582
   *
3583
   * @return static <p>(Immutable)</p>
3584
   */
3585 1
  public function stripEmpty()
3586
  {
3587 1
    return $this->filter(
3588 1
        function ($item) {
3589 1
          if ($item === null) {
3590 1
            return false;
3591
          }
3592
3593 1
          return (bool)\trim((string)$item);
3594 1
        }
3595
    );
3596
  }
3597
3598
  /**
3599
   * Swap two values between positions by key.
3600
   *
3601
   * @param string|int $swapA <p>a key in the array</p>
3602
   * @param string|int $swapB <p>a key in the array</p>
3603
   *
3604
   * @return static <p>(Immutable)</p>
3605
   */
3606 1
  public function swap($swapA, $swapB)
3607
  {
3608 1
    $array = $this->array;
3609
3610 1
    list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3611
3612 1
    return static::create($array);
3613
  }
3614
3615
  /**
3616
   * alias: for "Arrayy->getArray()"
3617
   *
3618
   * @see Arrayy::getArray()
3619
   */
3620 186
  public function toArray()
3621
  {
3622 186
    return $this->getArray();
3623
  }
3624
3625
  /**
3626
   * Convert the current array to JSON.
3627
   *
3628
   * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3629
   * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3630
   *
3631
   * @return string
3632
   */
3633 6
  public function toJson(int $options = 0, int $depth = 512): string
3634
  {
3635 6
    return UTF8::json_encode($this->array, $options, $depth);
3636
  }
3637
3638
  /**
3639
   * Implodes array to a string with specified separator.
3640
   *
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 19
  public function toString(string $separator = ','): string
3646
  {
3647 19
    return $this->implode($separator);
3648
  }
3649
3650
  /**
3651
   * Return a duplicate free copy of the current array.
3652
   *
3653
   * @return static <p>(Mutable)</p>
3654
   */
3655 9
  public function unique()
3656
  {
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 9
        $this->array,
3661 9
        function ($resultArray, $value) {
3662 8
          if (!\in_array($value, $resultArray, true)) {
3663 8
            $resultArray[] = $value;
3664
          }
3665
3666 8
          return $resultArray;
3667 9
        },
3668 9
        []
3669
    );
3670
3671 9 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3672
      $this->array = [];
3673
    } else {
3674 9
      $this->array = (array)$this->array;
3675
    }
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 10
  public function uniqueKeepIndex()
3686
  {
3687
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3688
3689
    // init
3690 10
    $array = $this->array;
3691
3692 10
    $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 10
        \array_keys($array),
3694 10
        function ($resultArray, $key) use ($array) {
3695 9
          if (!\in_array($array[$key], $resultArray, true)) {
3696 9
            $resultArray[$key] = $array[$key];
3697
          }
3698
3699 9
          return $resultArray;
3700 10
        },
3701 10
        []
3702
    );
3703
3704 10 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 10
      $this->array = (array)$this->array;
3708
    }
3709
3710 10
    return $this;
3711
  }
3712
3713
  /**
3714
   * alias: for "Arrayy->unique()"
3715
   *
3716
   * @see Arrayy::unique()
3717
   *
3718
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3719
   */
3720 9
  public function uniqueNewIndex()
3721
  {
3722 9
    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 4 View Code Duplication
  public function unshift(/* variadic arguments allowed */)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3731
  {
3732 4
    if (\func_num_args()) {
3733 4
      $args = \array_merge([&$this->array], \func_get_args());
3734 4
      \array_unshift(...$args);
3735
    }
3736
3737 4
    return $this;
3738
  }
3739
3740
  /**
3741
   * Get all values from a array.
3742
   *
3743
   * @return static <p>(Immutable)</p>
3744
   */
3745 2
  public function values()
3746
  {
3747 2
    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 36
  public function walk($callable, bool $recursive = false)
3759
  {
3760 36
    if (true === $recursive) {
3761 31
      \array_walk_recursive($this->array, $callable);
3762
    } else {
3763 18
      \array_walk($this->array, $callable);
3764
    }
3765
3766 36
    return $this;
3767
  }
3768
}
3769