Completed
Push — master ( 9d7f2b...8fe48d )
by Lars
24:45
created

Arrayy::meta()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
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
  /**
35
   * @var bool
36
   */
37
  protected $checkPropertyTypes = false;
38
39
  /**
40
   * @var bool
41
   */
42
  protected $checkPropertiesMismatchInConstructor = false;
43
44
  /**
45
   * @var array|Property[]
46
   */
47
  protected $properties = [];
48
49
  /** @noinspection MagicMethodsValidityInspection */
50
  /**
51
   * Initializes
52
   *
53
   * @param mixed  $array <p>Should be an array, otherwise it will try to convert it into an array.</p>
54
   * @param string $iteratorClass
55
   */
56 878
  public function __construct($array = [], $iteratorClass = ArrayyIterator::class)
57
  {
58 878
    $array = $this->fallbackForArray($array);
59
60
    if (
61 876
        $this->checkPropertyTypes === true
62
        ||
63 876
        $this->checkForMissingPropertiesInConstructor === true
0 ignored issues
show
Bug introduced by
The property checkForMissingPropertiesInConstructor does not seem to exist. Did you mean properties?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

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