Completed
Push — master ( fa4b94...514782 )
by Lars
01:47
created

src/Arrayy.php (34 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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

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

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

Loading history...
2529
  {
2530 15
    if (\count($this->array, COUNT_NORMAL) === 0) {
2531 2
      return false;
2532
    }
2533
2534 13
    foreach ($this->getGenerator() as $key => $value) {
2535 13
      $value = $closure($value, $key);
2536
2537 13
      if ($value === false) {
2538 13
        return false;
2539
      }
2540
    }
2541
2542 7
    return true;
2543
  }
2544
2545
  /**
2546
   * Check if any item in the current array matches a truth test.
2547
   *
2548
   * @param \Closure $closure
2549
   *
2550
   * @return bool
2551
   */
2552 14 View Code Duplication
  public function matchesAny(\Closure $closure): bool
0 ignored issues
show
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...
2553
  {
2554 14
    if (\count($this->array, COUNT_NORMAL) === 0) {
2555 2
      return false;
2556
    }
2557
2558 12
    foreach ($this->getGenerator() as $key => $value) {
2559 12
      $value = $closure($value, $key);
2560
2561 12
      if ($value === true) {
2562 12
        return true;
2563
      }
2564
    }
2565
2566 4
    return false;
2567
  }
2568
2569
  /**
2570
   * Get the max value from an array.
2571
   *
2572
   * @return mixed
2573
   */
2574 10 View Code Duplication
  public function max()
0 ignored issues
show
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...
2575
  {
2576 10
    if (\count($this->array, COUNT_NORMAL) === 0) {
2577 1
      return false;
2578
    }
2579
2580 9
    return max($this->array);
2581
  }
2582
2583
  /**
2584
   * Merge the new $array into the current array.
2585
   *
2586
   * - keep key,value from the current array, also if the index is in the new $array
2587
   *
2588
   * @param array $array
2589
   * @param bool  $recursive
2590
   *
2591
   * @return static <p>(Immutable)</p>
2592
   */
2593 25 View Code Duplication
  public function mergeAppendKeepIndex(array $array = [], bool $recursive = false)
0 ignored issues
show
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...
2594
  {
2595 25
    if (true === $recursive) {
2596 4
      $result = \array_replace_recursive($this->array, $array);
2597
    } else {
2598 21
      $result = \array_replace($this->array, $array);
2599
    }
2600
2601 25
    return static::create($result);
2602
  }
2603
2604
  /**
2605
   * Merge the new $array into the current array.
2606
   *
2607
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2608
   * - create new indexes
2609
   *
2610
   * @param array $array
2611
   * @param bool  $recursive
2612
   *
2613
   * @return static <p>(Immutable)</p>
2614
   */
2615 16 View Code Duplication
  public function mergeAppendNewIndex(array $array = [], bool $recursive = false)
0 ignored issues
show
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...
2616
  {
2617 16
    if (true === $recursive) {
2618 4
      $result = \array_merge_recursive($this->array, $array);
2619
    } else {
2620 12
      $result = \array_merge($this->array, $array);
2621
    }
2622
2623 16
    return static::create($result);
2624
  }
2625
2626
  /**
2627
   * Merge the the current array into the $array.
2628
   *
2629
   * - use key,value from the new $array, also if the index is in the current array
2630
   *
2631
   * @param array $array
2632
   * @param bool  $recursive
2633
   *
2634
   * @return static <p>(Immutable)</p>
2635
   */
2636 16 View Code Duplication
  public function mergePrependKeepIndex(array $array = [], bool $recursive = false)
0 ignored issues
show
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...
2637
  {
2638 16
    if (true === $recursive) {
2639 4
      $result = \array_replace_recursive($array, $this->array);
2640
    } else {
2641 12
      $result = \array_replace($array, $this->array);
2642
    }
2643
2644 16
    return static::create($result);
2645
  }
2646
2647
  /**
2648
   * Merge the current array into the new $array.
2649
   *
2650
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
2651
   * - create new indexes
2652
   *
2653
   * @param array $array
2654
   * @param bool  $recursive
2655
   *
2656
   * @return static <p>(Immutable)</p>
2657
   */
2658 17 View Code Duplication
  public function mergePrependNewIndex(array $array = [], bool $recursive = false)
0 ignored issues
show
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...
2659
  {
2660 17
    if (true === $recursive) {
2661 4
      $result = \array_merge_recursive($array, $this->array);
2662
    } else {
2663 13
      $result = \array_merge($array, $this->array);
2664
    }
2665
2666 17
    return static::create($result);
2667
  }
2668
2669
  /**
2670
   * @return ArrayyMeta|static
2671
   */
2672 7
  public static function meta()
2673
  {
2674 7
    return (new ArrayyMeta())->getMetaObject(static::class);
2675
  }
2676
2677
  /**
2678
   * Get the min value from an array.
2679
   *
2680
   * @return mixed
2681
   */
2682 10 View Code Duplication
  public function min()
0 ignored issues
show
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...
2683
  {
2684 10
    if (\count($this->array, COUNT_NORMAL) === 0) {
2685 1
      return false;
2686
    }
2687
2688 9
    return min($this->array);
2689
  }
2690
2691
  /**
2692
   * Move an array element to a new index.
2693
   *
2694
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2695
   *
2696
   * @param int|string $from
2697
   * @param int|string $to
2698
   *
2699
   * @return static <p>(Immutable)</p>
2700
   */
2701 1
  public function moveElement($from, $to)
2702
  {
2703 1
    $array = $this->array;
2704
2705 1
    if (\is_int($from)) {
2706 1
      $tmp = \array_splice($array, $from, 1);
2707 1
      \array_splice($array, $to, 0, $tmp);
2708 1
      $output = $array;
2709 1
    } elseif (\is_string($from)) {
2710 1
      $indexToMove = \array_search($from, \array_keys($array), true);
2711 1
      $itemToMove = $array[$from];
2712 1
      \array_splice($array, $indexToMove, 1);
2713 1
      $i = 0;
2714 1
      $output = [];
2715 1
      foreach ($array as $key => $item) {
2716 1
        if ($i == $to) {
2717 1
          $output[$from] = $itemToMove;
2718
        }
2719 1
        $output[$key] = $item;
2720 1
        $i++;
2721
      }
2722
    } else {
2723
      $output = [];
2724
    }
2725
2726 1
    return static::create($output);
2727
  }
2728
2729
  /**
2730
   * Convert a object into an array.
2731
   *
2732
   * @param object $object
2733
   *
2734
   * @return mixed
2735
   */
2736 5
  protected static function objectToArray($object)
2737
  {
2738 5
    if (!\is_object($object)) {
2739 4
      return $object;
2740
    }
2741
2742 5
    if (\is_object($object)) {
2743 5
      $object = \get_object_vars($object);
2744
    }
2745
2746 5
    return \array_map(['self', 'objectToArray'], $object);
2747
  }
2748
2749
  /**
2750
   * Get a subset of the items from the given array.
2751
   *
2752
   * @param mixed[] $keys
2753
   *
2754
   * @return static <p>(Immutable)</p>
2755
   */
2756
  public function only(array $keys)
2757
  {
2758
    $array = $this->array;
2759
2760
    return static::create(\array_intersect_key($array, \array_flip($keys)));
2761
  }
2762
2763
  /**
2764
   * Pad array to the specified size with a given value.
2765
   *
2766
   * @param int   $size  <p>Size of the result array.</p>
2767
   * @param mixed $value <p>Empty value by default.</p>
2768
   *
2769
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
2770
   */
2771 4
  public function pad(int $size, $value)
2772
  {
2773 4
    $result = \array_pad($this->array, $size, $value);
2774
2775 4
    return static::create($result);
2776
  }
2777
2778
  /**
2779
   * Pop a specified value off the end of the current array.
2780
   *
2781
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
2782
   */
2783 16
  public function pop()
2784
  {
2785 16
    return \array_pop($this->array);
2786
  }
2787
2788
  /**
2789
   * Prepend a (key) + value to the current array.
2790
   *
2791
   * @param mixed $value
2792
   * @param mixed $key
2793
   *
2794
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2795
   */
2796 8
  public function prepend($value, $key = null)
2797
  {
2798 8
    if ($key === null) {
2799 8
      \array_unshift($this->array, $value);
2800
    } else {
2801
      /** @noinspection AdditionOperationOnArraysInspection */
2802 1
      $this->array = [$key => $value] + $this->array;
2803
    }
2804
2805 8
    return $this;
2806
  }
2807
2808
  /**
2809
   * Add a suffix to each key.
2810
   *
2811
   * @param mixed $suffix
2812
   *
2813
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2814
   */
2815 10 View Code Duplication
  public function prependToEachKey($suffix)
0 ignored issues
show
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...
2816
  {
2817
    // init
2818 10
    $result = [];
2819
2820 10
    foreach ($this->getGenerator() as $key => $item) {
2821 9
      if ($item instanceof self) {
2822
        $result[$key] = $item->prependToEachKey($suffix);
2823 9
      } elseif (\is_array($item)) {
2824
        $result[$key] = self::create($item)->prependToEachKey($suffix)->toArray();
2825
      } else {
2826 9
        $result[$key . $suffix] = $item;
2827
      }
2828
2829
    }
2830
2831 10
    return self::create($result);
2832
  }
2833
2834
  /**
2835
   * Add a suffix to each value.
2836
   *
2837
   * @param mixed $suffix
2838
   *
2839
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2840
   */
2841 10 View Code Duplication
  public function prependToEachValue($suffix)
0 ignored issues
show
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...
2842
  {
2843
    // init
2844 10
    $result = [];
2845
2846 10
    foreach ($this->getGenerator() as $key => $item) {
2847 9
      if ($item instanceof self) {
2848
        $result[$key] = $item->prependToEachValue($suffix);
2849 9
      } elseif (\is_array($item)) {
2850
        $result[$key] = self::create($item)->prependToEachValue($suffix)->toArray();
2851 9
      } elseif (\is_object($item)) {
2852 1
        $result[$key] = $item;
2853
      } else {
2854 9
        $result[$key] = $item . $suffix;
2855
      }
2856
    }
2857
2858 10
    return self::create($result);
2859
  }
2860
2861
  /**
2862
   * Push one or more values onto the end of array at once.
2863
   *
2864
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2865
   */
2866 4 View Code Duplication
  public function push(/* variadic arguments allowed */)
0 ignored issues
show
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...
2867
  {
2868 4
    if (\func_num_args()) {
2869 4
      $args = \array_merge([&$this->array], \func_get_args());
2870 4
      \array_push(...$args);
2871
    }
2872
2873 4
    return $this;
2874
  }
2875
2876
  /**
2877
   * Get a random value from the current array.
2878
   *
2879
   * @param null|int $number <p>How many values you will take?</p>
2880
   *
2881
   * @return static <p>(Immutable)</p>
2882
   */
2883 18
  public function randomImmutable(int $number = null)
2884
  {
2885 18
    if (\count($this->array, COUNT_NORMAL) === 0) {
2886 1
      return static::create();
2887
    }
2888
2889 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
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...
2890
      /** @noinspection NonSecureArrayRandUsageInspection */
2891 14
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2892
2893 14
      return static::create($arrayRandValue);
2894
    }
2895
2896 5
    $arrayTmp = $this->array;
2897
    /** @noinspection NonSecureShuffleUsageInspection */
2898 5
    \shuffle($arrayTmp);
2899
2900 5
    return static::create($arrayTmp)->firstsImmutable($number);
2901
  }
2902
2903
  /**
2904
   * Pick a random key/index from the keys of this array.
2905
   *
2906
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
2907
   *
2908
   * @throws \RangeException If array is empty
2909
   */
2910 4
  public function randomKey()
2911
  {
2912 4
    $result = $this->randomKeys(1);
2913
2914 4
    if (!isset($result[0])) {
2915
      $result[0] = null;
2916
    }
2917
2918 4
    return $result[0];
2919
  }
2920
2921
  /**
2922
   * Pick a given number of random keys/indexes out of this array.
2923
   *
2924
   * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2925
   *
2926
   * @return static <p>(Immutable)</p>
2927
   *
2928
   * @throws \RangeException If array is empty
2929
   */
2930 13
  public function randomKeys(int $number)
2931
  {
2932 13
    $count = \count($this->array, COUNT_NORMAL);
2933
2934 13
    if ($number === 0 || $number > $count) {
2935 2
      throw new \RangeException(
2936 2
          \sprintf(
2937 2
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2938 2
              $number,
2939 2
              $count
2940
          )
2941
      );
2942
    }
2943
2944 11
    $result = (array)\array_rand($this->array, $number);
2945
2946 11
    return static::create($result);
2947
  }
2948
2949
  /**
2950
   * Get a random value from the current array.
2951
   *
2952
   * @param null|int $number <p>How many values you will take?</p>
2953
   *
2954
   * @return static <p>(Mutable)</p>
2955
   */
2956 17
  public function randomMutable(int $number = null)
2957
  {
2958 17
    if (\count($this->array, COUNT_NORMAL) === 0) {
2959
      return static::create();
2960
    }
2961
2962 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
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...
2963
      /** @noinspection NonSecureArrayRandUsageInspection */
2964 7
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2965 7
      $this->array = $arrayRandValue;
2966
2967 7
      return $this;
2968
    }
2969
2970
    /** @noinspection NonSecureShuffleUsageInspection */
2971 11
    \shuffle($this->array);
2972
2973 11
    return $this->firstsMutable($number);
2974
  }
2975
2976
  /**
2977
   * Pick a random value from the values of this array.
2978
   *
2979
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2980
   */
2981 4
  public function randomValue()
2982
  {
2983 4
    $result = $this->randomImmutable();
2984
2985 4
    if (!isset($result[0])) {
2986
      $result[0] = null;
2987
    }
2988
2989 4
    return $result[0];
2990
  }
2991
2992
  /**
2993
   * Pick a given number of random values out of this array.
2994
   *
2995
   * @param int $number
2996
   *
2997
   * @return static <p>(Mutable)</p>
2998
   */
2999 7
  public function randomValues(int $number)
3000
  {
3001 7
    return $this->randomMutable($number);
3002
  }
3003
3004
  /**
3005
   * Get a random value from an array, with the ability to skew the results.
3006
   *
3007
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3008
   *
3009
   * @param array    $array
3010
   * @param null|int $number <p>How many values you will take?</p>
3011
   *
3012
   * @return static <p>(Immutable)</p>
3013
   */
3014 9
  public function randomWeighted(array $array, int $number = null)
3015
  {
3016
    // init
3017 9
    $options = [];
3018
3019 9
    foreach ($array as $option => $weight) {
3020 9
      if ($this->searchIndex($option) !== false) {
3021 9
        for ($i = 0; $i < $weight; ++$i) {
3022 1
          $options[] = $option;
3023
        }
3024
      }
3025
    }
3026
3027 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3028
  }
3029
3030
  /**
3031
   * Reduce the current array via callable e.g. anonymous-function.
3032
   *
3033
   * @param \callable $callable
3034
   * @param array     $init
3035
   *
3036
   * @return static <p>(Immutable)</p>
3037
   */
3038 4
  public function reduce($callable, array $init = [])
3039
  {
3040 4
    $result = \array_reduce($this->array, $callable, $init);
3041
3042 4
    if ($result === null) {
3043
      $this->array = [];
3044
    } else {
3045 4
      $this->array = (array)$result;
3046
    }
3047
3048 4
    return static::create($this->array);
3049
  }
3050
3051
  /**
3052
   * Create a numerically re-indexed Arrayy object.
3053
   *
3054
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
3055
   */
3056 9
  public function reindex()
3057
  {
3058 9
    $this->array = \array_values($this->array);
3059
3060 9
    return $this;
3061
  }
3062
3063
  /**
3064
   * Return all items that fail the truth test.
3065
   *
3066
   * @param \Closure $closure
3067
   *
3068
   * @return static <p>(Immutable)</p>
3069
   */
3070 1 View Code Duplication
  public function reject(\Closure $closure)
0 ignored issues
show
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...
3071
  {
3072 1
    $filtered = [];
3073
3074 1
    foreach ($this->getGenerator() as $key => $value) {
3075 1
      if (!$closure($value, $key)) {
3076 1
        $filtered[$key] = $value;
3077
      }
3078
    }
3079
3080 1
    return static::create($filtered);
3081
  }
3082
3083
  /**
3084
   * Remove a value from the current array (optional using dot-notation).
3085
   *
3086
   * @param mixed $key
3087
   *
3088
   * @return static <p>(Immutable)</p>
3089
   */
3090 18
  public function remove($key)
3091
  {
3092
    // recursive call
3093 18
    if (\is_array($key)) {
3094
      foreach ($key as $k) {
3095
        $this->internalRemove($k);
3096
      }
3097
3098
      return static::create($this->array);
3099
    }
3100
3101 18
    $this->internalRemove($key);
3102
3103 18
    return static::create($this->array);
3104
  }
3105
3106
  /**
3107
   * Remove the first value from the current array.
3108
   *
3109
   * @return static <p>(Immutable)</p>
3110
   */
3111 7
  public function removeFirst()
3112
  {
3113 7
    $tmpArray = $this->array;
3114 7
    \array_shift($tmpArray);
3115
3116 7
    return static::create($tmpArray);
3117
  }
3118
3119
  /**
3120
   * Remove the last value from the current array.
3121
   *
3122
   * @return static <p>(Immutable)</p>
3123
   */
3124 7
  public function removeLast()
3125
  {
3126 7
    $tmpArray = $this->array;
3127 7
    \array_pop($tmpArray);
3128
3129 7
    return static::create($tmpArray);
3130
  }
3131
3132
  /**
3133
   * Removes a particular value from an array (numeric or associative).
3134
   *
3135
   * @param mixed $value
3136
   *
3137
   * @return static <p>(Immutable)</p>
3138
   */
3139 7
  public function removeValue($value)
3140
  {
3141 7
    $isNumericArray = true;
3142 7
    foreach ($this->getGenerator() as $key => $item) {
3143 6
      if ($item === $value) {
3144 6
        if (!\is_int($key)) {
3145
          $isNumericArray = false;
3146
        }
3147 6
        unset($this->array[$key]);
3148
      }
3149
    }
3150
3151 7
    if ($isNumericArray) {
3152 7
      $this->array = \array_values($this->array);
3153
    }
3154
3155 7
    return static::create($this->array);
3156
  }
3157
3158
  /**
3159
   * Generate array of repeated arrays.
3160
   *
3161
   * @param int $times <p>How many times has to be repeated.</p>
3162
   *
3163
   * @return Arrayy
3164
   */
3165 1
  public function repeat($times): self
3166
  {
3167 1
    if ($times === 0) {
3168 1
      return new static();
3169
    }
3170
3171 1
    return static::create(\array_fill(0, (int)$times, $this->array));
3172
  }
3173
3174
  /**
3175
   * Replace a key with a new key/value pair.
3176
   *
3177
   * @param mixed $replace
3178
   * @param mixed $key
3179
   * @param mixed $value
3180
   *
3181
   * @return static <p>(Immutable)</p>
3182
   */
3183 2
  public function replace($replace, $key, $value)
3184
  {
3185 2
    $that = $this->remove($replace);
3186
3187 2
    return $that->set($key, $value);
3188
  }
3189
3190
  /**
3191
   * Create an array using the current array as values and the other array as keys.
3192
   *
3193
   * @param array $keys <p>An array of keys.</p>
3194
   *
3195
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
3196
   */
3197 2
  public function replaceAllKeys(array $keys)
3198
  {
3199 2
    $result = \array_combine($keys, $this->array);
3200
3201 2
    return static::create($result);
3202
  }
3203
3204
  /**
3205
   * Create an array using the current array as keys and the other array as values.
3206
   *
3207
   * @param array $array <p>An array o values.</p>
3208
   *
3209
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
3210
   */
3211 2
  public function replaceAllValues(array $array)
3212
  {
3213 2
    $result = \array_combine($this->array, $array);
3214
3215 2
    return static::create($result);
3216
  }
3217
3218
  /**
3219
   * Replace the keys in an array with another set.
3220
   *
3221
   * @param array $keys <p>An array of keys matching the array's size</p>
3222
   *
3223
   * @return static <p>(Immutable)</p>
3224
   */
3225 1
  public function replaceKeys(array $keys)
3226
  {
3227 1
    $values = \array_values($this->array);
3228 1
    $result = \array_combine($keys, $values);
3229
3230 1
    return static::create($result);
3231
  }
3232
3233
  /**
3234
   * Replace the first matched value in an array.
3235
   *
3236
   * @param mixed $search      <p>The value to replace.</p>
3237
   * @param mixed $replacement <p>The value to replace.</p>
3238
   *
3239
   * @return static <p>(Immutable)</p>
3240
   */
3241 3
  public function replaceOneValue($search, $replacement = '')
3242
  {
3243 3
    $array = $this->array;
3244 3
    $key = \array_search($search, $array, true);
3245
3246 3
    if ($key !== false) {
3247 3
      $array[$key] = $replacement;
3248
    }
3249
3250 3
    return static::create($array);
3251
  }
3252
3253
  /**
3254
   * Replace values in the current array.
3255
   *
3256
   * @param mixed $search      <p>The value to replace.</p>
3257
   * @param mixed $replacement <p>What to replace it with.</p>
3258
   *
3259
   * @return static <p>(Immutable)</p>
3260
   */
3261 1
  public function replaceValues($search, $replacement = '')
3262
  {
3263 1
    $array = $this->each(
3264 1
        function ($value) use ($search, $replacement) {
3265 1
          return UTF8::str_replace($search, $replacement, $value);
3266 1
        }
3267
    );
3268
3269 1
    return $array;
3270
  }
3271
3272
  /**
3273
   * Get the last elements from index $from until the end of this array.
3274
   *
3275
   * @param int $from
3276
   *
3277
   * @return static <p>(Immutable)</p>
3278
   */
3279 15
  public function rest(int $from = 1)
3280
  {
3281 15
    $tmpArray = $this->array;
3282
3283 15
    return static::create(\array_splice($tmpArray, $from));
3284
  }
3285
3286
  /**
3287
   * Return the array in the reverse order.
3288
   *
3289
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3290
   */
3291 8
  public function reverse()
3292
  {
3293 8
    $this->array = \array_reverse($this->array);
3294
3295 8
    return $this;
3296
  }
3297
3298
  /**
3299
   * Sort an array in reverse order.
3300
   *
3301
   * @param int $sort_flags [optional] <p>
3302
   *                        You may modify the behavior of the sort using the optional
3303
   *                        parameter sort_flags, for details
3304
   *                        see sort.
3305
   *                        </p>
3306
   *
3307
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3308
   */
3309 4
  public function rsort(int $sort_flags = 0)
3310
  {
3311 4
    \rsort($this->array, $sort_flags);
3312
3313 4
    return $this;
3314
  }
3315
3316
  /**
3317
   * Search for the first index of the current array via $value.
3318
   *
3319
   * @param mixed $value
3320
   *
3321
   * @return int|float|string
3322
   */
3323 20
  public function searchIndex($value)
3324
  {
3325 20
    return \array_search($value, $this->array, true);
3326
  }
3327
3328
  /**
3329
   * Search for the value of the current array via $index.
3330
   *
3331
   * @param mixed $index
3332
   *
3333
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3334
   */
3335 9
  public function searchValue($index)
3336
  {
3337
    // init
3338 9
    $return = [];
3339
3340 9
    if ($this->isEmpty()) {
3341
      return static::create();
3342
    }
3343
3344
    // php cast "bool"-index into "int"-index
3345 9
    if ((bool)$index === $index) {
3346 1
      $index = (int)$index;
3347
    }
3348
3349 9
    if (\array_key_exists($index, $this->array) === true) {
3350 7
      $return = [$this->array[$index]];
3351
    }
3352
3353
3354 9
    return static::create($return);
3355
  }
3356
3357
  /**
3358
   * Set a value for the current array (optional using dot-notation).
3359
   *
3360
   * @param string $key   <p>The key to set.</p>
3361
   * @param mixed  $value <p>Its value.</p>
3362
   *
3363
   * @return static <p>(Immutable)</p>
3364
   */
3365 17
  public function set($key, $value)
3366
  {
3367 17
    $this->internalSet($key, $value);
3368
3369 17
    return static::create($this->array);
3370
  }
3371
3372
  /**
3373
   * Get a value from a array and set it if it was not.
3374
   *
3375
   * WARNING: this method only set the value, if the $key is not already set
3376
   *
3377
   * @param mixed $key      <p>The key</p>
3378
   * @param mixed $fallback <p>The default value to set if it isn't.</p>
3379
   *
3380
   * @return mixed <p>(Mutable)</p>
3381
   */
3382 11
  public function setAndGet($key, $fallback = null)
3383
  {
3384
    // If the key doesn't exist, set it.
3385 11
    if (!$this->has($key)) {
3386 4
      $this->array = $this->set($key, $fallback)->getArray();
3387
    }
3388
3389 11
    return $this->get($key);
3390
  }
3391
3392
  /**
3393
   * Shifts a specified value off the beginning of array.
3394
   *
3395
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
3396
   */
3397 4
  public function shift()
3398
  {
3399 4
    return \array_shift($this->array);
3400
  }
3401
3402
  /**
3403
   * Shuffle the current array.
3404
   *
3405
   * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3406
   * @param array $array  [optional]
3407
   *
3408
   * @return static <p>(Immutable)</p>
3409
   */
3410 1
  public function shuffle(bool $secure = false, array $array = null)
3411
  {
3412 1
    if ($array === null) {
3413 1
      $array = $this->array;
3414
    }
3415
3416 1
    if ($secure !== true) {
3417
      /** @noinspection NonSecureShuffleUsageInspection */
3418 1
      \shuffle($array);
3419
    } else {
3420 1
      $size = \count($array, COUNT_NORMAL);
3421 1
      $keys = \array_keys($array);
3422 1
      for ($i = $size - 1; $i > 0; --$i) {
3423
        try {
3424 1
          $r = \random_int(0, $i);
3425
        } catch (\Exception $e) {
3426
          $r = \mt_rand();
3427
        }
3428 1
        if ($r !== $i) {
3429 1
          $temp = $array[$keys[$r]];
3430 1
          $array[$keys[$r]] = $array[$keys[$i]];
3431 1
          $array[$keys[$i]] = $temp;
3432
        }
3433
      }
3434
3435
      // reset indices
3436 1
      $array = \array_values($array);
3437
    }
3438
3439 1
    foreach ($array as $key => $value) {
3440
      // check if recursive is needed
3441 1
      if (\is_array($value) === true) {
3442 1
        $array[$key] = $this->shuffle($secure, $value);
3443
      }
3444
    }
3445
3446 1
    return static::create($array);
3447
  }
3448
3449
  /**
3450
   * Count the values from the current array.
3451
   *
3452
   * alias: for "Arrayy->count()"
3453
   *
3454
   * @param int $mode
3455
   *
3456
   * @return int
3457
   */
3458 20
  public function size(int $mode = COUNT_NORMAL): int
3459
  {
3460 20
    return $this->count($mode);
3461
  }
3462
3463
  /**
3464
   * Counts all elements in an array, or something in an object.
3465
   * <p>For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3466
   * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3467
   * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3468
   * implemented and used in PHP.
3469
   *
3470
   * @return int the number of elements in var, which is
3471
   * typically an array, since anything else will have one
3472
   * element.
3473
   * </p>
3474
   * <p>
3475
   * If var is not an array or an object with
3476
   * implemented Countable interface,
3477
   * 1 will be returned.
3478
   * There is one exception, if var is &null;,
3479
   * 0 will be returned.
3480
   * </p>
3481
   * <p>
3482
   * Caution: count may return 0 for a variable that isn't set,
3483
   * but it may also return 0 for a variable that has been initialized with an
3484
   * empty array. Use isset to test if a variable is set.
3485
   *
3486
   * @return int
3487
   */
3488 10
  public function sizeRecursive(): int
3489
  {
3490 10
    return \count($this->array, COUNT_RECURSIVE);
3491
  }
3492
3493
  /**
3494
   * Extract a slice of the array.
3495
   *
3496
   * @param int      $offset       <p>Slice begin index.</p>
3497
   * @param int|null $length       <p>Length of the slice.</p>
3498
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3499
   *
3500
   * @return static <p>A slice of the original array with length $length.</p>
3501
   */
3502 4
  public function slice(int $offset, int $length = null, bool $preserveKeys = false)
3503
  {
3504 4
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
3505
3506 4
    return static::create($result);
3507
  }
3508
3509
  /**
3510
   * Sort the current array and optional you can keep the keys.
3511
   *
3512
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3513
   * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3514
   *                              <strong>SORT_NATURAL</strong></p>
3515
   * @param bool       $keepKeys
3516
   *
3517
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3518
   */
3519 19
  public function sort($direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3520
  {
3521 19
    return $this->sorting($this->array, $direction, $strategy, $keepKeys);
3522
  }
3523
3524
  /**
3525
   * Sort the current array by key.
3526
   *
3527
   * @link http://php.net/manual/en/function.ksort.php
3528
   * @link http://php.net/manual/en/function.krsort.php
3529
   *
3530
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3531
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3532
   *                              <strong>SORT_NATURAL</strong></p>
3533
   *
3534
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3535
   */
3536 18
  public function sortKeys($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3537
  {
3538
    /** @noinspection UnusedFunctionResultInspection */
3539 18
    $this->sorterKeys($this->array, $direction, $strategy);
3540
3541 18
    return $this;
3542
  }
3543
3544
  /**
3545
   * Sort the current array by value.
3546
   *
3547
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3548
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3549
   *                              <strong>SORT_NATURAL</strong></p>
3550
   *
3551
   * @return static <p>(Mutable)</p>
3552
   */
3553 1
  public function sortValueKeepIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3554
  {
3555 1
    return $this->sort($direction, $strategy, true);
3556
  }
3557
3558
  /**
3559
   * Sort the current array by value.
3560
   *
3561
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3562
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3563
   *                              <strong>SORT_NATURAL</strong></p>
3564
   *
3565
   * @return static <p>(Mutable)</p>
3566
   */
3567 1
  public function sortValueNewIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3568
  {
3569 1
    return $this->sort($direction, $strategy, false);
3570
  }
3571
3572
  /**
3573
   * Sort a array by value, by a closure or by a property.
3574
   *
3575
   * - If the sorter is null, the array is sorted naturally.
3576
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3577
   *
3578
   * @param \callable|null $sorter
3579
   * @param string|int     $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3580
   * @param int            $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3581
   *                                  <strong>SORT_NATURAL</strong></p>
3582
   *
3583
   * @return static <p>(Immutable)</p>
3584
   */
3585 1
  public function sorter($sorter = null, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3586
  {
3587 1
    $array = (array)$this->array;
3588 1
    $direction = $this->getDirection($direction);
3589
3590
    // Transform all values into their results.
3591 1
    if ($sorter) {
3592 1
      $arrayy = static::create($array);
3593
3594 1
      $that = $this;
3595 1
      $results = $arrayy->each(
3596 1
          function ($value) use ($sorter, $that) {
3597 1
            return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3598 1
          }
3599
      );
3600
3601 1
      $results = $results->getArray();
3602
    } else {
3603 1
      $results = $array;
3604
    }
3605
3606
    // Sort by the results and replace by original values
3607 1
    \array_multisort($results, $direction, $strategy, $array);
3608
3609 1
    return static::create($array);
3610
  }
3611
3612
  /**
3613
   * sorting keys
3614
   *
3615
   * @param array      $elements
3616
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3617
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3618
   *                              <strong>SORT_NATURAL</strong></p>
3619
   *
3620
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3621
   */
3622 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3623
  {
3624 18
    $direction = $this->getDirection($direction);
3625
3626
    switch ($direction) {
3627 18
      case 'desc':
3628 18
      case SORT_DESC:
3629 6
        \krsort($elements, $strategy);
3630 6
        break;
3631 13
      case 'asc':
3632 13
      case SORT_ASC:
3633
      default:
3634 13
        \ksort($elements, $strategy);
3635
    }
3636
3637 18
    return $this;
3638
  }
3639
3640
  /**
3641
   * @param array      &$elements
3642
   * @param int|string  $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3643
   * @param int         $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3644
   *                               <strong>SORT_NATURAL</strong></p>
3645
   * @param bool        $keepKeys
3646
   *
3647
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3648
   */
3649 19
  protected function sorting(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3650
  {
3651 19
    $direction = $this->getDirection($direction);
3652
3653 19
    if (!$strategy) {
3654 19
      $strategy = SORT_REGULAR;
3655
    }
3656
3657
    switch ($direction) {
3658 19
      case 'desc':
3659 19
      case SORT_DESC:
3660 9
        if ($keepKeys) {
3661 5
          \arsort($elements, $strategy);
3662
        } else {
3663 4
          \rsort($elements, $strategy);
3664
        }
3665 9
        break;
3666 10
      case 'asc':
3667 10
      case SORT_ASC:
3668
      default:
3669 10
        if ($keepKeys) {
3670 4
          \asort($elements, $strategy);
3671
        } else {
3672 6
          \sort($elements, $strategy);
3673
        }
3674
    }
3675
3676 19
    return $this;
3677
  }
3678
3679
  /**
3680
   * Split an array in the given amount of pieces.
3681
   *
3682
   * @param int  $numberOfPieces
3683
   * @param bool $keepKeys
3684
   *
3685
   * @return static <p>(Immutable)</p>
3686
   */
3687 1
  public function split(int $numberOfPieces = 2, bool $keepKeys = false)
3688
  {
3689 1
    $arrayCount = \count($this->array, COUNT_NORMAL);
3690
3691 1
    if ($arrayCount === 0) {
3692 1
      $result = [];
3693
    } else {
3694 1
      $splitSize = (int)\ceil($arrayCount / $numberOfPieces);
3695 1
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
3696
    }
3697
3698 1
    return static::create($result);
3699
  }
3700
3701
  /**
3702
   * Stripe all empty items.
3703
   *
3704
   * @return static <p>(Immutable)</p>
3705
   */
3706 1
  public function stripEmpty()
3707
  {
3708 1
    return $this->filter(
3709 1
        function ($item) {
3710 1
          if ($item === null) {
3711 1
            return false;
3712
          }
3713
3714 1
          return (bool)\trim((string)$item);
3715 1
        }
3716
    );
3717
  }
3718
3719
  /**
3720
   * Swap two values between positions by key.
3721
   *
3722
   * @param string|int $swapA <p>a key in the array</p>
3723
   * @param string|int $swapB <p>a key in the array</p>
3724
   *
3725
   * @return static <p>(Immutable)</p>
3726
   */
3727 1
  public function swap($swapA, $swapB)
3728
  {
3729 1
    $array = $this->array;
3730
3731 1
    list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3732
3733 1
    return static::create($array);
3734
  }
3735
3736
  /**
3737
   * alias: for "Arrayy->getArray()"
3738
   *
3739
   * @see Arrayy::getArray()
3740
   */
3741 192
  public function toArray()
3742
  {
3743 192
    return $this->getArray();
3744
  }
3745
3746
  /**
3747
   * Convert the current array to JSON.
3748
   *
3749
   * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3750
   * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3751
   *
3752
   * @return string
3753
   */
3754 6
  public function toJson(int $options = 0, int $depth = 512): string
3755
  {
3756 6
    return UTF8::json_encode($this->array, $options, $depth);
3757
  }
3758
3759
  /**
3760
   * Implodes array to a string with specified separator.
3761
   *
3762
   * @param string $separator [optional] <p>The element's separator.</p>
3763
   *
3764
   * @return string <p>The string representation of array, separated by ",".</p>
3765
   */
3766 19
  public function toString(string $separator = ','): string
3767
  {
3768 19
    return $this->implode($separator);
3769
  }
3770
3771
  /**
3772
   * Return a duplicate free copy of the current array.
3773
   *
3774
   * @return static <p>(Mutable)</p>
3775
   */
3776 10
  public function unique()
3777
  {
3778
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3779
3780 10
    $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...
3781 10
        $this->array,
3782 10
        function ($resultArray, $value) {
3783 9
          if (!\in_array($value, $resultArray, true)) {
3784 9
            $resultArray[] = $value;
3785
          }
3786
3787 9
          return $resultArray;
3788 10
        },
3789 10
        []
3790
    );
3791
3792 10 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
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...
3793
      $this->array = [];
3794
    } else {
3795 10
      $this->array = (array)$this->array;
3796
    }
3797
3798 10
    return $this;
3799
  }
3800
3801
  /**
3802
   * Return a duplicate free copy of the current array. (with the old keys)
3803
   *
3804
   * @return static <p>(Mutable)</p>
3805
   */
3806 11
  public function uniqueKeepIndex()
3807
  {
3808
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3809
3810
    // init
3811 11
    $array = $this->array;
3812
3813 11
    $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...
3814 11
        \array_keys($array),
3815 11
        function ($resultArray, $key) use ($array) {
3816 10
          if (!\in_array($array[$key], $resultArray, true)) {
3817 10
            $resultArray[$key] = $array[$key];
3818
          }
3819
3820 10
          return $resultArray;
3821 11
        },
3822 11
        []
3823
    );
3824
3825 11 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
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...
3826
      $this->array = [];
3827
    } else {
3828 11
      $this->array = (array)$this->array;
3829
    }
3830
3831 11
    return $this;
3832
  }
3833
3834
  /**
3835
   * alias: for "Arrayy->unique()"
3836
   *
3837
   * @see Arrayy::unique()
3838
   *
3839
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3840
   */
3841 10
  public function uniqueNewIndex()
3842
  {
3843 10
    return $this->unique();
3844
  }
3845
3846
  /**
3847
   * Prepends one or more values to the beginning of array at once.
3848
   *
3849
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3850
   */
3851 4 View Code Duplication
  public function unshift(/* variadic arguments allowed */)
0 ignored issues
show
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...
3852
  {
3853 4
    if (\func_num_args()) {
3854 4
      $args = \array_merge([&$this->array], \func_get_args());
3855 4
      \array_unshift(...$args);
3856
    }
3857
3858 4
    return $this;
3859
  }
3860
3861
  /**
3862
   * Get all values from a array.
3863
   *
3864
   * @return static <p>(Immutable)</p>
3865
   */
3866 2
  public function values()
3867
  {
3868 2
    return static::create(\array_values((array)$this->array));
3869
  }
3870
3871
  /**
3872
   * Apply the given function to every element in the array, discarding the results.
3873
   *
3874
   * @param \callable $callable
3875
   * @param bool      $recursive <p>Whether array will be walked recursively or no</p>
3876
   *
3877
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3878
   */
3879 37
  public function walk($callable, bool $recursive = false)
3880
  {
3881 37
    if (true === $recursive) {
3882 32
      \array_walk_recursive($this->array, $callable);
3883
    } else {
3884 18
      \array_walk($this->array, $callable);
3885
    }
3886
3887 37
    return $this;
3888
  }
3889
}
3890