Completed
Push — master ( 24d33d...9acfcd )
by Lars
02:11
created

Arrayy::reduce_dimension()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
nc 6
nop 1
dl 0
loc 18
ccs 9
cts 9
cp 1
crap 4
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arrayy;
6
7
/** @noinspection ClassReImplementsParentInterfaceInspection */
8
/** @noinspection PhpComposerExtensionStubsInspection */
9
10
/**
11
 * Methods to manage arrays.
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 */
16
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \JsonSerializable, \Countable
17
{
18
    /**
19
     * @var array
20
     */
21
    protected $array = [];
22
23
    /**
24
     * @var ArrayyRewindableGenerator|null
25
     */
26
    protected $generator;
27
28
    /**
29
     * @var string
30
     */
31
    protected $iteratorClass = ArrayyIterator::class;
32
33
    /**
34
     * @var string
35
     */
36
    protected $pathSeparator = '.';
37
38
    /**
39
     * @var bool
40
     */
41
    protected $checkPropertyTypes = false;
42
43
    /**
44
     * @var bool
45
     */
46
    protected $checkForMissingPropertiesInConstructor = false;
47
48
    /**
49
     * @var bool
50
     */
51
    protected $checkPropertiesMismatchInConstructor = false;
52
53
    /**
54
     * @var Property[]
55
     */
56
    protected $properties = [];
57
58
    /** @noinspection MagicMethodsValidityInspection */
59
    /** @noinspection PhpMissingParentConstructorInspection */
60
61
    /**
62
     * Initializes
63
     *
64
     * @param mixed  $data                                   <p>
65
     *                                                       Should be an array or a generator, otherwise it will try
66
     *                                                       to convert it into an array.
67
     *                                                       </p>
68
     * @param string $iteratorClass                          optional <p>
69
     *                                                       You can overwrite the ArrayyIterator, but mostly you don't
70
     *                                                       need this option.
71
     *                                                       </p>
72
     * @param bool   $checkForMissingPropertiesInConstructor optional <p>
73
     *                                                       You need to extend the "Arrayy"-class and you need to set
74
     *                                                       the $checkPropertiesMismatchInConstructor class property
75
     *                                                       to
76
     *                                                       true, otherwise this option didn't not work anyway.
77
     *                                                       </p>
78
     */
79 936
    public function __construct(
80
        $data = [],
81
        string $iteratorClass = ArrayyIterator::class,
82
        bool $checkForMissingPropertiesInConstructor = true
83
    ) {
84 936
        $data = $this->fallbackForArray($data);
85
86
        // used only for serialize + unserialize, all other methods are overwritten
87 934
        parent::__construct([], 0, $iteratorClass);
88
89 934
        $checkForMissingPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
90
                                                  &&
91 934
                                                  $checkForMissingPropertiesInConstructor === true;
92
93
        if (
94 934
            $this->checkPropertyTypes === true
95
            ||
96 934
            $checkForMissingPropertiesInConstructor === true
97
        ) {
98 15
            $this->properties = $this->getPropertiesFromPhpDoc();
99
        }
100
101
        if (
102 934
            $this->checkPropertiesMismatchInConstructor === true
103
            &&
104 934
            \count($data) !== 0
105
            &&
106 934
            \count(\array_diff_key($this->properties, $data)) > 0
107
        ) {
108 1
            throw new \InvalidArgumentException('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($this->properties), true));
109
        }
110
111
        /** @noinspection AlterInForeachInspection */
112 933
        foreach ($data as $key => &$value) {
113 814
            $this->internalSet(
114 814
                $key,
115 814
                $value,
116 814
                $checkForMissingPropertiesInConstructor
117
            );
118
        }
119
120 929
        $this->setIteratorClass($iteratorClass);
121 929
    }
122
123
    /**
124
     * Call object as function.
125
     *
126
     * @param mixed $key
127
     *
128
     * @return mixed
129
     */
130 1
    public function __invoke($key = null)
131
    {
132 1
        if ($key !== null) {
133 1
            $this->generatorToArray();
134
135 1
            return $this->array[$key] ?? false;
136
        }
137
138
        return $this->getArray();
139
    }
140
141
    /**
142
     * Whether or not an element exists by key.
143
     *
144
     * @param mixed $key
145
     *
146
     * @return bool
147
     *              <p>True is the key/index exists, otherwise false.</p>
148
     */
149
    public function __isset($key): bool
150
    {
151
        return $this->offsetExists($key);
152
    }
153
154
    /**
155
     * Assigns a value to the specified element.
156
     *
157
     * @param mixed $key
158
     * @param mixed $value
159
     */
160 2
    public function __set($key, $value)
161
    {
162 2
        $this->internalSet($key, $value);
163 2
    }
164
165
    /**
166
     * magic to string
167
     *
168
     * @return string
169
     */
170 15
    public function __toString(): string
171
    {
172 15
        return $this->toString();
173
    }
174
175
    /**
176
     * Unset element by key.
177
     *
178
     * @param mixed $key
179
     */
180
    public function __unset($key)
181
    {
182
        $this->internalRemove($key);
183
    }
184
185
    /**
186
     * Get a value by key.
187
     *
188
     * @param mixed $key
189
     *
190
     * @return mixed
191
     *               <p>Get a Value from the current array.</p>
192
     */
193 4
    public function &__get($key)
194
    {
195 4
        $return = $this->get($key);
196
197 4
        if (\is_array($return)) {
198
            return static::create($return, $this->iteratorClass, false);
199
        }
200
201 4
        return $return;
202
    }
203
204
    /**
205
     * alias: for "Arrayy->append()"
206
     *
207
     * @param mixed $value
208
     *
209
     * @return static
210
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
211
     *
212
     * @see Arrayy::append()
213
     */
214 3
    public function add($value): self
215
    {
216 3
        return $this->append($value);
217
    }
218
219
    /**
220
     * Append a (key) + value to the current array.
221
     *
222
     * @param mixed $value
223
     * @param mixed $key
224
     *
225
     * @return static
226
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
227
     */
228 11
    public function append($value, $key = null): self
229
    {
230 11
        $this->generatorToArray();
231
232 11
        if ($key !== null) {
233
            if (
234
                isset($this->array[$key])
235
                &&
236
                \is_array($this->array[$key])
237
            ) {
238
                $this->array[$key][] = $value;
239
            } else {
240
                $this->array[$key] = $value;
241
            }
242
        } else {
243 11
            $this->array[] = $value;
244
        }
245
246 11
        return $this;
247
    }
248
249
    /**
250
     * Sort the entries by value.
251
     *
252
     * @param int $sort_flags [optional] <p>
253
     *                        You may modify the behavior of the sort using the optional
254
     *                        parameter sort_flags, for details
255
     *                        see sort.
256
     *                        </p>
257
     *
258
     * @return static
259
     *                <p>(Mutable) Return this Arrayy object.</p>
260
     */
261 4
    public function asort(int $sort_flags = 0): self
262
    {
263 4
        $this->generatorToArray();
264
265 4
        \asort($this->array, $sort_flags);
266
267 4
        return $this;
268
    }
269
270
    /**
271
     * Counts all elements in an array, or something in an object.
272
     *
273
     * <p>
274
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
275
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
276
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
277
     * implemented and used in PHP.
278
     * </p>
279
     *
280
     * @see http://php.net/manual/en/function.count.php
281
     *
282
     * @param int $mode [optional] If the optional mode parameter is set to
283
     *                  COUNT_RECURSIVE (or 1), count
284
     *                  will recursively count the array. This is particularly useful for
285
     *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
286
     *
287
     * @return int
288
     *             <p>
289
     *             The number of elements in var, which is
290
     *             typically an array, since anything else will have one
291
     *             element.
292
     *             </p>
293
     *             <p>
294
     *             If var is not an array or an object with
295
     *             implemented Countable interface,
296
     *             1 will be returned.
297
     *             There is one exception, if var is &null;,
298
     *             0 will be returned.
299
     *             </p>
300
     *             <p>
301
     *             Caution: count may return 0 for a variable that isn't set,
302
     *             but it may also return 0 for a variable that has been initialized with an
303
     *             empty array. Use isset to test if a variable is set.
304
     *             </p>
305
     */
306 46
    public function count(int $mode = \COUNT_NORMAL): int
307
    {
308 46
        return \count($this->getArray(), $mode);
309
    }
310
311
    /**
312
     * Exchange the array for another one.
313
     *
314
     * @param array|static $data
315
     *
316
     * @return array
317
     */
318 1
    public function exchangeArray($data): array
319
    {
320 1
        $this->array = $this->fallbackForArray($data);
321
322 1
        return $this->array;
323
    }
324
325
    /**
326
     * Creates a copy of the ArrayyObject.
327
     *
328
     * @return array
329
     */
330 1
    public function getArrayCopy(): array
331
    {
332 1
        $this->generatorToArray();
333
334 1
        return $this->array;
335
    }
336
337
    /**
338
     * Returns a new iterator, thus implementing the \Iterator interface.
339
     *
340
     * @return \Iterator
341
     *                   <p>An iterator for the values in the array.</p>
342
     */
343 23
    public function getIterator(): \Iterator
344
    {
345 23
        if ($this->generator instanceof ArrayyRewindableGenerator) {
346 1
            return $this->generator;
347
        }
348
349 22
        $iterator = $this->getIteratorClass();
350
351 22
        if ($iterator === ArrayyIterator::class) {
352 22
            return new $iterator($this->getArray(), 0, static::class, false);
353
        }
354
355
        return new $iterator($this->getArray());
356
    }
357
358
    /**
359
     * Gets the iterator classname for the ArrayObject.
360
     *
361
     * @return string
362
     */
363 22
    public function getIteratorClass(): string
364
    {
365 22
        return $this->iteratorClass;
366
    }
367
368
    /**
369
     * Sort the entries by key
370
     *
371
     * @param int $sort_flags [optional] <p>
372
     *                        You may modify the behavior of the sort using the optional
373
     *                        parameter sort_flags, for details
374
     *                        see sort.
375
     *                        </p>
376
     *
377
     * @return static
378
     *                <p>(Mutable) Return this Arrayy object.</p>
379
     */
380 4
    public function ksort(int $sort_flags = 0): self
381
    {
382 4
        $this->generatorToArray();
383
384 4
        \ksort($this->array, $sort_flags);
385
386 4
        return $this;
387
    }
388
389
    /**
390
     * Sort an array using a case insensitive "natural order" algorithm
391
     *
392
     * @return static
393
     *                <p>(Mutable) Return this Arrayy object.</p>
394
     */
395
    public function natcasesort(): self
396
    {
397
        $this->generatorToArray();
398
399
        \natcasesort($this->array);
400
401
        return $this;
402
    }
403
404
    /**
405
     * Sort entries using a "natural order" algorithm
406
     *
407
     * @return static
408
     *                <p>(Mutable) Return this Arrayy object.</p>
409
     */
410 1
    public function natsort(): self
411
    {
412 1
        $this->generatorToArray();
413
414 1
        \natsort($this->array);
415
416 1
        return $this;
417
    }
418
419
    /**
420
     * Whether or not an offset exists.
421
     *
422
     * @param bool|int|string $offset
423
     *
424
     * @return bool
425
     */
426 46
    public function offsetExists($offset): bool
427
    {
428 46
        $this->generatorToArray();
429
430 46
        if ($this->array === []) {
431 4
            return false;
432
        }
433
434
        // php cast "bool"-index into "int"-index
435 42
        if (\is_bool($offset)) {
436 1
            $offset = (int) $offset;
437
        }
438
439 42
        $tmpReturn = \array_key_exists($offset, $this->array);
440
441
        if (
442 42
            $tmpReturn === true
443
            ||
444
            (
445 16
                $tmpReturn === false
446
                &&
447 42
                \strpos((string) $offset, $this->pathSeparator) === false
448
            )
449
        ) {
450 40
            return $tmpReturn;
451
        }
452
453 3
        $offsetExists = false;
454
455
        if (
456 3
            $this->pathSeparator
457
            &&
458 3
            \is_string($offset)
459
            &&
460 3
            \strpos($offset, $this->pathSeparator) !== false
461
        ) {
462 3
            $explodedPath = \explode($this->pathSeparator, (string) $offset);
463 3
            if ($explodedPath !== false) {
464 3
                $lastOffset = \array_pop($explodedPath);
465 3
                if ($lastOffset !== null) {
466 3
                    $containerPath = \implode($this->pathSeparator, $explodedPath);
467
468 3
                    $this->callAtPath(
469 3
                        $containerPath,
470
                        static function ($container) use ($lastOffset, &$offsetExists) {
471 3
                            $offsetExists = \array_key_exists($lastOffset, $container);
472 3
                        }
473
                    );
474
                }
475
            }
476
        }
477
478 3
        return $offsetExists;
479
    }
480
481
    /**
482
     * Returns the value at specified offset.
483
     *
484
     * @param int|string $offset
485
     *
486
     * @return mixed
487
     *               <p>Will return null if the offset did not exists.</p>
488
     */
489 30
    public function offsetGet($offset)
490
    {
491 30
        return $this->offsetExists($offset) ? $this->get($offset) : null;
492
    }
493
494
    /**
495
     * Assigns a value to the specified offset.
496
     *
497
     * @param int|string|null $offset
498
     * @param mixed           $value
499
     */
500 20
    public function offsetSet($offset, $value)
501
    {
502 20
        $this->generatorToArray();
503
504 20
        if ($offset === null) {
505 4
            $this->array[] = $value;
506
        } else {
507 16
            $this->internalSet($offset, $value);
508
        }
509 20
    }
510
511
    /**
512
     * Unset an offset.
513
     *
514
     * @param int|string $offset
515
     */
516 7
    public function offsetUnset($offset)
517
    {
518 7
        $this->generatorToArray();
519
520 7
        if ($this->array === []) {
521 1
            return;
522
        }
523
524 6
        if (\array_key_exists($offset, $this->array)) {
525 4
            unset($this->array[$offset]);
526
527 4
            return;
528
        }
529
530
        if (
531 3
            $this->pathSeparator
532
            &&
533 3
            \is_string($offset)
534
            &&
535 3
            \strpos($offset, $this->pathSeparator) !== false
536
        ) {
537 2
            $path = \explode($this->pathSeparator, (string) $offset);
538
539 2
            if ($path !== false) {
540 2
                $pathToUnset = \array_pop($path);
541
542 2
                $this->callAtPath(
543 2
                    \implode($this->pathSeparator, $path),
544
                    static function (&$offset) use ($pathToUnset) {
545 2
                        unset($offset[$pathToUnset]);
546 2
                    }
547
                );
548
            }
549
        }
550
551 3
        unset($this->array[$offset]);
552 3
    }
553
554
    /** @noinspection SenselessProxyMethodInspection | can not add return type, because of the "Serializable" interface */
555
556
    /**
557
     * Serialize the current "Arrayy"-object.
558
     *
559
     * @return string
560
     */
561 2
    public function serialize(): string
562
    {
563 2
        $this->generatorToArray();
564
565 2
        return parent::serialize();
566
    }
567
568
    /**
569
     * Sets the iterator classname for the current "Arrayy"-object.
570
     *
571
     * @param string $class
572
     *
573
     * @throws \InvalidArgumentException
574
     */
575 929
    public function setIteratorClass($class)
576
    {
577 929
        if (\class_exists($class)) {
578 929
            $this->iteratorClass = $class;
579
580 929
            return;
581
        }
582
583
        if (\strpos($class, '\\') === 0) {
584
            $class = '\\' . $class;
585
            if (\class_exists($class)) {
586
                $this->iteratorClass = $class;
587
588
                return;
589
            }
590
        }
591
592
        throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
593
    }
594
595
    /**
596
     * Sort the entries with a user-defined comparison function and maintain key association.
597
     *
598
     * @param callable $function
599
     *
600
     * @throws \InvalidArgumentException
601
     *
602
     * @return static
603
     *                <p>(Mutable) Return this Arrayy object.</p>
604
     */
605 View Code Duplication
    public function uasort($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
606
    {
607
        if (!\is_callable($function)) {
608
            throw new \InvalidArgumentException(
609
                'Passed function must be callable'
610
            );
611
        }
612
613
        $this->generatorToArray();
614
615
        \uasort($this->array, $function);
616
617
        return $this;
618
    }
619
620
    /**
621
     * Sort the entries by keys using a user-defined comparison function.
622
     *
623
     * @param callable $function
624
     *
625
     * @throws \InvalidArgumentException
626
     *
627
     * @return static
628
     *                <p>(Mutable) Return this Arrayy object.</p>
629
     */
630 5
    public function uksort($function): self
631
    {
632 5
        return $this->customSortKeys($function);
633
    }
634
635
    /**
636
     * Unserialize an string and return the instance of the "Arrayy"-class.
637
     *
638
     * @param string $string
639
     *
640
     * @return static
641
     */
642 2
    public function unserialize($string): self
643
    {
644 2
        parent::unserialize($string);
645
646 2
        return $this;
647
    }
648
649
    /**
650
     * Append a (key) + values to the current array.
651
     *
652
     * @param array $values
653
     * @param mixed $key
654
     *
655
     * @return static
656
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
657
     */
658 1
    public function appendArrayValues(array $values, $key = null): self
659
    {
660 1
        $this->generatorToArray();
661
662 1
        if ($key !== null) {
663
            if (
664 1
                isset($this->array[$key])
665
                &&
666 1
                \is_array($this->array[$key])
667
            ) {
668 1
                foreach ($values as $value) {
669 1
                    $this->array[$key][] = $value;
670
                }
671
            } else {
672 1
                foreach ($values as $value) {
673
                    $this->array[$key] = $value;
674
                }
675
            }
676
        } else {
677
            foreach ($values as $value) {
678
                $this->array[] = $value;
679
            }
680
        }
681
682 1
        return $this;
683
    }
684
685
    /**
686
     * Add a suffix to each key.
687
     *
688
     * @param mixed $prefix
689
     *
690
     * @return static
691
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
692
     */
693 10 View Code Duplication
    public function appendToEachKey($prefix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
694
    {
695
        // init
696 10
        $result = [];
697
698 10
        foreach ($this->getGenerator() as $key => $item) {
699 9
            if ($item instanceof self) {
700
                $result[$prefix . $key] = $item->appendToEachKey($prefix);
701 9
            } elseif (\is_array($item)) {
702
                $result[$prefix . $key] = self::create($item, $this->iteratorClass, false)
703
                    ->appendToEachKey($prefix)
704
                    ->toArray();
705
            } else {
706 9
                $result[$prefix . $key] = $item;
707
            }
708
        }
709
710 10
        return self::create($result, $this->iteratorClass, false);
711
    }
712
713
    /**
714
     * Add a prefix to each value.
715
     *
716
     * @param mixed $prefix
717
     *
718
     * @return static
719
     *                <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
720
     */
721 10 View Code Duplication
    public function appendToEachValue($prefix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
722
    {
723
        // init
724 10
        $result = [];
725
726 10
        foreach ($this->getGenerator() as $key => $item) {
727 9
            if ($item instanceof self) {
728
                $result[$key] = $item->appendToEachValue($prefix);
729 9
            } elseif (\is_array($item)) {
730
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
731 9
            } elseif (\is_object($item)) {
732 1
                $result[$key] = $item;
733
            } else {
734 8
                $result[$key] = $prefix . $item;
735
            }
736
        }
737
738 10
        return self::create($result, $this->iteratorClass, false);
739
    }
740
741
    /**
742
     * Sort an array in reverse order and maintain index association.
743
     *
744
     * @return static
745
     *                <p>(Mutable) Return this Arrayy object.</p>
746
     */
747 4
    public function arsort(): self
748
    {
749 4
        $this->generatorToArray();
750
751 4
        \arsort($this->array);
752
753 4
        return $this;
754
    }
755
756
    /**
757
     * Iterate over the current array and execute a callback for each loop.
758
     *
759
     * @param \Closure $closure
760
     *
761
     * @return static
762
     *                <p>(Immutable)</p>
763
     */
764 2
    public function at(\Closure $closure): self
765
    {
766 2
        $arrayy = clone $this;
767
768 2
        foreach ($arrayy->getGenerator() as $key => $value) {
769 2
            $closure($value, $key);
770
        }
771
772 2
        return static::create(
773 2
            $arrayy->toArray(),
774 2
            $this->iteratorClass,
775 2
            false
776
        );
777
    }
778
779
    /**
780
     * Returns the average value of the current array.
781
     *
782
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
783
     *
784
     * @return float|int
785
     *                   <p>The average value.</p>
786
     */
787 10
    public function average($decimals = 0)
788
    {
789 10
        $count = \count($this->getArray(), \COUNT_NORMAL);
790
791 10
        if (!$count) {
792 2
            return 0;
793
        }
794
795 8
        if (!\is_int($decimals)) {
796 3
            $decimals = 0;
797
        }
798
799 8
        return \round(\array_sum($this->getArray()) / $count, $decimals);
800
    }
801
802
    /**
803
     * Changes all keys in an array.
804
     *
805
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
806
     *                  or <strong>CASE_LOWER</strong> (default)</p>
807
     *
808
     * @return static
809
     *                <p>(Immutable)</p>
810
     */
811 1
    public function changeKeyCase(int $case = \CASE_LOWER): self
812
    {
813
        if (
814 1
            $case !== \CASE_LOWER
815
            &&
816 1
            $case !== \CASE_UPPER
817
        ) {
818
            $case = \CASE_LOWER;
819
        }
820
821 1
        $return = [];
822 1
        foreach ($this->getGenerator() as $key => $value) {
823 1
            if ($case === \CASE_LOWER) {
824
                /** @noinspection PhpComposerExtensionStubsInspection */
825 1
                $key = \mb_strtolower((string) $key);
826
            } else {
827
                /** @noinspection PhpComposerExtensionStubsInspection */
828 1
                $key = \mb_strtoupper((string) $key);
829
            }
830
831 1
            $return[$key] = $value;
832
        }
833
834 1
        return static::create(
835 1
            $return,
836 1
            $this->iteratorClass,
837 1
            false
838
        );
839
    }
840
841
    /**
842
     * Change the path separator of the array wrapper.
843
     *
844
     * By default, the separator is: "."
845
     *
846
     * @param string $separator <p>Separator to set.</p>
847
     *
848
     * @return static
849
     *                <p>Mutable</p>
850
     */
851 10
    public function changeSeparator($separator): self
852
    {
853 10
        $this->pathSeparator = $separator;
854
855 10
        return $this;
856
    }
857
858
    /**
859
     * Create a chunked version of the current array.
860
     *
861
     * @param int  $size         <p>Size of each chunk.</p>
862
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
863
     *
864
     * @return static
865
     *                <p>(Immutable) A new array of chunks from the original array.</p>
866
     */
867 4
    public function chunk($size, $preserveKeys = false): self
868
    {
869 4
        return static::create(
870 4
            \array_chunk($this->getArray(), $size, $preserveKeys),
871 4
            $this->iteratorClass,
872 4
            false
873
        );
874
    }
875
876
    /**
877
     * Clean all falsy values from the current array.
878
     *
879
     * @return static
880
     *                <p>(Immutable)</p>
881
     */
882 8
    public function clean(): self
883
    {
884 8
        return $this->filter(
885
            static function ($value) {
886 7
                return (bool) $value;
887 8
            }
888
        );
889
    }
890
891
    /**
892
     * WARNING!!! -> Clear the current array.
893
     *
894
     * @return static
895
     *                <p>(Mutable) Return this Arrayy object, with an empty array.</p>
896
     */
897 4
    public function clear(): self
898
    {
899 4
        $this->array = [];
900 4
        $this->generator = null;
901
902 4
        return $this;
903
    }
904
905
    /**
906
     * Check if an item is in the current array.
907
     *
908
     * @param float|int|string $value
909
     * @param bool             $recursive
910
     * @param bool             $strict
911
     *
912
     * @return bool
913
     */
914 22
    public function contains($value, bool $recursive = false, bool $strict = true): bool
915
    {
916 22
        if ($recursive === true) {
917 18
            return $this->in_array_recursive($value, $this->getArray(), $strict);
918
        }
919
920 13
        return \in_array($value, $this->getArray(), $strict);
921
    }
922
923
    /**
924
     * Check if an (case-insensitive) string is in the current array.
925
     *
926
     * @param string $value
927
     * @param bool   $recursive
928
     *
929
     * @return bool
930
     */
931 26
    public function containsCaseInsensitive($value, $recursive = false): bool
932
    {
933 26
        if ($recursive === true) {
934
            /** @noinspection PhpComposerExtensionStubsInspection */
935 26
            return $this->in_array_recursive(
936 26
                \mb_strtoupper((string) $value),
937 26
                $this->walk(
938
                    static function (&$val) {
939
                        /** @noinspection PhpComposerExtensionStubsInspection */
940 22
                        $val = \mb_strtoupper((string) $val);
941 26
                    },
942 26
                    true
943 26
                )->getArray(),
944 26
                true
945
            );
946
        }
947
948
        /** @noinspection PhpComposerExtensionStubsInspection */
949 13
        return \in_array(
950 13
            \mb_strtoupper((string) $value),
951 13
            $this->walk(
952
                static function (&$val) {
953
                    /** @noinspection PhpComposerExtensionStubsInspection */
954 11
                    $val = \mb_strtoupper((string) $val);
955 13
                },
956 13
                false
957 13
            )->getArray(),
958 13
            true
959
        );
960
    }
961
962
    /**
963
     * Check if the given key/index exists in the array.
964
     *
965
     * @param int|string $key <p>key/index to search for</p>
966
     *
967
     * @return bool
968
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
969
     */
970 4
    public function containsKey($key): bool
971
    {
972 4
        return $this->offsetExists($key);
973
    }
974
975
    /**
976
     * Check if all given needles are present in the array as key/index.
977
     *
978
     * @param array $needles   <p>The keys you are searching for.</p>
979
     * @param bool  $recursive
980
     *
981
     * @return bool
982
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
983
     */
984 2
    public function containsKeys(array $needles, $recursive = false): bool
985
    {
986 2
        if ($recursive === true) {
987 2
            return \count(
988 2
                       \array_intersect($needles, $this->keys(true)->getArray()),
989 2
                       \COUNT_RECURSIVE
990
                   )
991
                   ===
992 2
                   \count(
993 2
                       $needles,
994 2
                       \COUNT_RECURSIVE
995
                   );
996
        }
997
998 1
        return \count(
999 1
                   \array_intersect($needles, $this->keys()->getArray()),
1000 1
                   \COUNT_NORMAL
1001
               )
1002
               ===
1003 1
               \count(
1004 1
                   $needles,
1005 1
                   \COUNT_NORMAL
1006
               );
1007
    }
1008
1009
    /**
1010
     * Check if all given needles are present in the array as key/index.
1011
     *
1012
     * @param array $needles <p>The keys you are searching for.</p>
1013
     *
1014
     * @return bool
1015
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1016
     */
1017 1
    public function containsKeysRecursive(array $needles): bool
1018
    {
1019 1
        return $this->containsKeys($needles, true);
1020
    }
1021
1022
    /**
1023
     * alias: for "Arrayy->contains()"
1024
     *
1025
     * @param float|int|string $value
1026
     *
1027
     * @return bool
1028
     *
1029
     * @see Arrayy::contains()
1030
     */
1031 9
    public function containsValue($value): bool
1032
    {
1033 9
        return $this->contains($value);
1034
    }
1035
1036
    /**
1037
     * alias: for "Arrayy->contains($value, true)"
1038
     *
1039
     * @param float|int|string $value
1040
     *
1041
     * @return bool
1042
     *
1043
     * @see Arrayy::contains()
1044
     */
1045 18
    public function containsValueRecursive($value): bool
1046
    {
1047 18
        return $this->contains($value, true);
1048
    }
1049
1050
    /**
1051
     * Check if all given needles are present in the array.
1052
     *
1053
     * @param array $needles
1054
     *
1055
     * @return bool
1056
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
1057
     */
1058 1
    public function containsValues(array $needles): bool
1059
    {
1060 1
        return \count(\array_intersect($needles, $this->getArray()), \COUNT_NORMAL)
1061
               ===
1062 1
               \count($needles, \COUNT_NORMAL);
1063
    }
1064
1065
    /**
1066
     * Counts all the values of an array
1067
     *
1068
     * @see http://php.net/manual/en/function.array-count-values.php
1069
     *
1070
     * @return static
1071
     *                <p>
1072
     *                (Immutable)
1073
     *                An associative Arrayy-object of values from input as
1074
     *                keys and their count as value.
1075
     *                </p>
1076
     */
1077 1
    public function countValues(): self
1078
    {
1079 1
        return new static(\array_count_values($this->getArray()));
1080
    }
1081
1082
    /**
1083
     * Creates an Arrayy object.
1084
     *
1085
     * @param mixed  $array
1086
     * @param string $iteratorClass
1087
     * @param bool   $checkForMissingPropertiesInConstructor
1088
     *
1089
     * @return static
1090
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1091
     */
1092 553
    public static function create($array = [], string $iteratorClass = ArrayyIterator::class, bool $checkForMissingPropertiesInConstructor = true): self
1093
    {
1094 553
        return new static(
1095 553
            $array,
1096 553
            $iteratorClass,
1097 553
            $checkForMissingPropertiesInConstructor
1098
        );
1099
    }
1100
1101
    /**
1102
     * WARNING: Creates an Arrayy object by reference.
1103
     *
1104
     * @param array $array
1105
     *
1106
     * @return static
1107
     *                <p>(Mutable) Return this Arrayy object.</p>
1108
     */
1109 1
    public function createByReference(array &$array = []): self
1110
    {
1111 1
        $array = $this->fallbackForArray($array);
1112
1113 1
        $this->array = &$array;
1114
1115 1
        return $this;
1116
    }
1117
1118
    /**
1119
     * Create an new instance from a callable function which will return an Generator.
1120
     *
1121
     * @param callable():Generator $generatorFunction
0 ignored issues
show
Documentation introduced by
The doc-type callable():Generator could not be parsed: Expected "|" or "end of type", but got "(" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1122
     *
1123
     * @return static
1124
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1125
     */
1126 5
    public static function createFromGeneratorFunction(callable $generatorFunction): self
1127
    {
1128 5
        $arrayy = new static($generatorFunction);
1129
1130 5
        return $arrayy;
1131
    }
1132
1133
    /**
1134
     * Create an new instance filled with a copy of values from a "Traversable"-object.
1135
     *
1136
     * @param \Traversable $traversable
1137
     *
1138
     * @return static
1139
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1140
     */
1141
    public static function createFromTraversableImmutable(\Traversable $traversable): self
1142
    {
1143
        return new static(\iterator_to_array($traversable, true));
1144
    }
1145
1146
    /**
1147
     * Create an new instance filled with a copy of values from a "Generator"-object.
1148
     *
1149
     * @param \Generator $generator
1150
     *
1151
     * @return static
1152
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1153
     */
1154 4
    public static function createFromGeneratorImmutable(\Generator $generator): self
1155
    {
1156 4
        return new static(\iterator_to_array($generator, true));
1157
    }
1158
1159
    /**
1160
     * Create an new Arrayy object via JSON.
1161
     *
1162
     * @param string $json
1163
     *
1164
     * @return static
1165
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1166
     */
1167 5
    public static function createFromJson(string $json): self
1168
    {
1169
        /** @noinspection PhpComposerExtensionStubsInspection */
1170 5
        return static::create(\json_decode($json, true));
1171
    }
1172
1173
    /**
1174
     * Create an new instance filled with values from an object that is iterable.
1175
     *
1176
     * @param \Traversable $object <p>iterable object</p>
1177
     *
1178
     * @return static
1179
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1180
     */
1181 4
    public static function createFromObject(\Traversable $object): self
1182
    {
1183
        // init
1184 4
        $array = new static();
1185
1186 4
        if ($object instanceof self) {
1187 4
            $objectArray = $object->getGenerator();
1188
        } else {
1189
            $objectArray = $object;
1190
        }
1191
1192 4
        foreach ($objectArray as $key => $value) {
1193 3
            $array[$key] = $value;
1194
        }
1195
1196 4
        return $array;
1197
    }
1198
1199
    /**
1200
     * Create an new instance filled with values from an object.
1201
     *
1202
     * @param object $object
1203
     *
1204
     * @return static
1205
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1206
     */
1207 5
    public static function createFromObjectVars($object): self
1208
    {
1209 5
        return new static(self::objectToArray($object));
1210
    }
1211
1212
    /**
1213
     * Create an new Arrayy object via string.
1214
     *
1215
     * @param string      $str       <p>The input string.</p>
1216
     * @param string|null $delimiter <p>The boundary string.</p>
1217
     * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1218
     *                               used.</p>
1219
     *
1220
     * @return static
1221
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1222
     */
1223 10
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
1224
    {
1225 10
        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...
1226 1
            \preg_match_all($regEx, $str, $array);
1227
1228 1
            if (!empty($array)) {
1229 1
                $array = $array[0];
1230
            }
1231
        } else {
1232
            /** @noinspection NestedPositiveIfStatementsInspection */
1233 9
            if ($delimiter !== null) {
1234 7
                $array = \explode($delimiter, $str);
1235
            } else {
1236 2
                $array = [$str];
1237
            }
1238
        }
1239
1240
        // trim all string in the array
1241 10
        \array_walk(
1242 10
            $array,
1243
            static function (&$val) {
1244 10
                if (\is_string($val)) {
1245 10
                    $val = \trim($val);
1246
                }
1247 10
            }
1248
        );
1249
1250 10
        return static::create($array);
1251
    }
1252
1253
    /**
1254
     * Create an new instance containing a range of elements.
1255
     *
1256
     * @param mixed $low  <p>First value of the sequence.</p>
1257
     * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1258
     * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1259
     *
1260
     * @return static
1261
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1262
     */
1263 2
    public static function createWithRange($low, $high, int $step = 1): self
1264
    {
1265 2
        return static::create(\range($low, $high, $step));
1266
    }
1267
1268
    /**
1269
     * Custom sort by index via "uksort".
1270
     *
1271
     * @see http://php.net/manual/en/function.uksort.php
1272
     *
1273
     * @param callable $function
1274
     *
1275
     * @throws \InvalidArgumentException
1276
     *
1277
     * @return static
1278
     *                <p>(Mutable) Return this Arrayy object.</p>
1279
     */
1280 5 View Code Duplication
    public function customSortKeys($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1281
    {
1282 5
        if (!\is_callable($function)) {
1283
            throw new \InvalidArgumentException(
1284
                'Passed function must be callable'
1285
            );
1286
        }
1287
1288 5
        $this->generatorToArray();
1289
1290 5
        \uksort($this->array, $function);
1291
1292 5
        return $this;
1293
    }
1294
1295
    /**
1296
     * Custom sort by value via "usort".
1297
     *
1298
     * @see http://php.net/manual/en/function.usort.php
1299
     *
1300
     * @param callable $function
1301
     *
1302
     * @throws \InvalidArgumentException
1303
     *
1304
     * @return static
1305
     *                <p>(Mutable) Return this Arrayy object.</p>
1306
     */
1307 5 View Code Duplication
    public function customSortValues($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1308
    {
1309 5
        if (!\is_callable($function)) {
1310
            throw new \InvalidArgumentException(
1311
                'Passed function must be callable'
1312
            );
1313
        }
1314
1315 5
        $this->generatorToArray();
1316
1317 5
        \usort($this->array, $function);
1318
1319 5
        return $this;
1320
    }
1321
1322
    /**
1323
     * Return values that are only in the current array.
1324
     *
1325
     * @param array $array
1326
     *
1327
     * @return static
1328
     *                <p>(Immutable)</p>
1329
     */
1330 12
    public function diff(array $array = []): self
1331
    {
1332 12
        return static::create(
1333 12
            \array_diff($this->getArray(), $array),
1334 12
            $this->iteratorClass,
1335 12
            false
1336
        );
1337
    }
1338
1339
    /**
1340
     * Return values that are only in the current multi-dimensional array.
1341
     *
1342
     * @param array      $array
1343
     * @param array|null $helperVariableForRecursion <p>(only for internal usage)</p>
1344
     *
1345
     * @return static
1346
     *                <p>(Immutable)</p>
1347
     */
1348 1
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
1349
    {
1350
        // init
1351 1
        $result = [];
1352
1353
        if (
1354 1
            $helperVariableForRecursion !== null
1355
            &&
1356 1
            \is_array($helperVariableForRecursion)
1357
        ) {
1358
            $arrayForTheLoop = $helperVariableForRecursion;
1359
        } else {
1360 1
            $arrayForTheLoop = $this->getGenerator();
1361
        }
1362
1363 1
        foreach ($arrayForTheLoop as $key => $value) {
1364 1
            if ($value instanceof self) {
1365
                $value = $value->getArray();
1366
            }
1367
1368 1
            if (\array_key_exists($key, $array)) {
1369 1
                if ($value !== $array[$key]) {
1370 1
                    $result[$key] = $value;
1371
                }
1372
            } else {
1373 1
                $result[$key] = $value;
1374
            }
1375
        }
1376
1377 1
        return static::create(
1378 1
            $result,
1379 1
            $this->iteratorClass,
1380 1
            false
1381
        );
1382
    }
1383
1384
    /**
1385
     * Return values that are only in the new $array.
1386
     *
1387
     * @param array $array
1388
     *
1389
     * @return static
1390
     *                <p>(Immutable)</p>
1391
     */
1392 8
    public function diffReverse(array $array = []): self
1393
    {
1394 8
        return static::create(
1395 8
            \array_diff($array, $this->getArray()),
1396 8
            $this->iteratorClass,
1397 8
            false
1398
        );
1399
    }
1400
1401
    /**
1402
     * Divide an array into two arrays. One with keys and the other with values.
1403
     *
1404
     * @return static
1405
     *                <p>(Immutable)</p>
1406
     */
1407 1
    public function divide(): self
1408
    {
1409 1
        return static::create(
1410
            [
1411 1
                $this->keys(),
1412 1
                $this->values(),
1413
            ],
1414 1
            $this->iteratorClass,
1415 1
            false
1416
        );
1417
    }
1418
1419
    /**
1420
     * Iterate over the current array and modify the array's value.
1421
     *
1422
     * @param \Closure $closure
1423
     *
1424
     * @return static
1425
     *                <p>(Immutable)</p>
1426
     */
1427 4 View Code Duplication
    public function each(\Closure $closure): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1428
    {
1429
        // init
1430 4
        $array = [];
1431
1432 4
        foreach ($this->getGenerator() as $key => $value) {
1433 4
            $array[$key] = $closure($value, $key);
1434
        }
1435
1436 4
        return static::create(
1437 4
            $array,
1438 4
            $this->iteratorClass,
1439 4
            false
1440
        );
1441
    }
1442
1443
    /**
1444
     * Check if a value is in the current array using a closure.
1445
     *
1446
     * @param \Closure $closure
1447
     *
1448
     * @return bool
1449
     *              <p>Returns true if the given value is found, false otherwise.</p>
1450
     */
1451 4
    public function exists(\Closure $closure): bool
1452
    {
1453
        // init
1454 4
        $isExists = false;
1455
1456 4
        foreach ($this->getGenerator() as $key => $value) {
1457 3
            if ($closure($value, $key)) {
1458 1
                $isExists = true;
1459
1460 1
                break;
1461
            }
1462
        }
1463
1464 4
        return $isExists;
1465
    }
1466
1467
    /**
1468
     * Fill the array until "$num" with "$default" values.
1469
     *
1470
     * @param int   $num
1471
     * @param mixed $default
1472
     *
1473
     * @return static
1474
     *                <p>(Immutable)</p>
1475
     */
1476 8
    public function fillWithDefaults(int $num, $default = null): self
1477
    {
1478 8
        if ($num < 0) {
1479 1
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1480
        }
1481
1482 7
        $this->generatorToArray();
1483
1484 7
        $tmpArray = $this->array;
1485
1486 7
        $count = \count($tmpArray);
1487
1488 7
        while ($count < $num) {
1489 4
            $tmpArray[] = $default;
1490 4
            ++$count;
1491
        }
1492
1493 7
        return static::create(
1494 7
            $tmpArray,
1495 7
            $this->iteratorClass,
1496 7
            false
1497
        );
1498
    }
1499
1500
    /**
1501
     * Find all items in an array that pass the truth test.
1502
     *
1503
     * @param \Closure|null $closure [optional] <p>
1504
     *                               The callback function to use
1505
     *                               </p>
1506
     *                               <p>
1507
     *                               If no callback is supplied, all entries of
1508
     *                               input equal to false (see
1509
     *                               converting to
1510
     *                               boolean) will be removed.
1511
     *                               </p>
1512
     *                               * @param int $flag [optional] <p>
1513
     *                               Flag determining what arguments are sent to <i>callback</i>:
1514
     *                               </p><ul>
1515
     *                               <li>
1516
     *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1517
     *                               to <i>callback</i> instead of the value</span>
1518
     *                               </li>
1519
     *                               <li>
1520
     *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1521
     *                               arguments to <i>callback</i> instead of the value</span>
1522
     *                               </li>
1523
     *                               </ul>
1524
     *
1525
     * @return static
1526
     *                <p>(Immutable)</p>
1527
     */
1528 11
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH): self
1529
    {
1530 11
        if (!$closure) {
1531 1
            return $this->clean();
1532
        }
1533
1534 11
        return static::create(
1535 11
            \array_filter($this->getArray(), $closure, $flag),
1536 11
            $this->iteratorClass,
1537 11
            false
1538
        );
1539
    }
1540
1541
    /**
1542
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
1543
     * property within that.
1544
     *
1545
     * @param string          $property
1546
     * @param string|string[] $value
1547
     * @param string          $comparisonOp
1548
     *                                      <p>
1549
     *                                      'eq' (equals),<br />
1550
     *                                      'gt' (greater),<br />
1551
     *                                      'gte' || 'ge' (greater or equals),<br />
1552
     *                                      'lt' (less),<br />
1553
     *                                      'lte' || 'le' (less or equals),<br />
1554
     *                                      'ne' (not equals),<br />
1555
     *                                      'contains',<br />
1556
     *                                      'notContains',<br />
1557
     *                                      'newer' (via strtotime),<br />
1558
     *                                      'older' (via strtotime),<br />
1559
     *                                      </p>
1560
     *
1561
     * @return static
1562
     *                <p>(Immutable)</p>
1563
     */
1564 1
    public function filterBy(string $property, $value, string $comparisonOp = null): self
1565
    {
1566 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...
1567 1
            $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1568
        }
1569
1570
        $ops = [
1571
            'eq' => static function ($item, $prop, $value) {
1572 1
                return $item[$prop] === $value;
1573 1
            },
1574
            'gt' => static function ($item, $prop, $value) {
1575
                return $item[$prop] > $value;
1576 1
            },
1577
            'ge' => static function ($item, $prop, $value) {
1578
                return $item[$prop] >= $value;
1579 1
            },
1580
            'gte' => static function ($item, $prop, $value) {
1581
                return $item[$prop] >= $value;
1582 1
            },
1583
            'lt' => static function ($item, $prop, $value) {
1584 1
                return $item[$prop] < $value;
1585 1
            },
1586
            'le' => static function ($item, $prop, $value) {
1587
                return $item[$prop] <= $value;
1588 1
            },
1589
            'lte' => static function ($item, $prop, $value) {
1590
                return $item[$prop] <= $value;
1591 1
            },
1592
            'ne' => static function ($item, $prop, $value) {
1593
                return $item[$prop] !== $value;
1594 1
            },
1595
            'contains' => static function ($item, $prop, $value) {
1596 1
                return \in_array($item[$prop], (array) $value, true);
1597 1
            },
1598
            'notContains' => static function ($item, $prop, $value) {
1599
                return !\in_array($item[$prop], (array) $value, true);
1600 1
            },
1601
            'newer' => static function ($item, $prop, $value) {
1602
                return \strtotime($item[$prop]) > \strtotime($value);
1603 1
            },
1604
            'older' => static function ($item, $prop, $value) {
1605
                return \strtotime($item[$prop]) < \strtotime($value);
1606 1
            },
1607
        ];
1608
1609 1
        $result = \array_values(
1610 1
            \array_filter(
1611 1
                $this->getArray(),
1612
                static function ($item) use (
1613 1
                    $property,
1614 1
                    $value,
1615 1
                    $ops,
1616 1
                    $comparisonOp
1617
                ) {
1618 1
                    $item = (array) $item;
1619 1
                    $itemArrayy = new static($item);
1620 1
                    $item[$property] = $itemArrayy->get($property, []);
1621
1622 1
                    return $ops[$comparisonOp]($item, $property, $value);
1623 1
                }
1624
            )
1625
        );
1626
1627 1
        return static::create(
1628 1
            $result,
1629 1
            $this->iteratorClass,
1630 1
            false
1631
        );
1632
    }
1633
1634
    /**
1635
     * Find the first item in an array that passes the truth test,
1636
     *  otherwise return false
1637
     *
1638
     * @param \Closure $closure
1639
     *
1640
     * @return false|mixed
1641
     *                     <p>Return false if we did not find the value.</p>
1642
     */
1643 8
    public function find(\Closure $closure)
1644
    {
1645 8
        foreach ($this->getGenerator() as $key => $value) {
1646 6
            if ($closure($value, $key)) {
1647 5
                return $value;
1648
            }
1649
        }
1650
1651 3
        return false;
1652
    }
1653
1654
    /**
1655
     * find by ...
1656
     *
1657
     * @param string          $property
1658
     * @param string|string[] $value
1659
     * @param string          $comparisonOp
1660
     *
1661
     * @return static
1662
     *                <p>(Immutable)</p>
1663
     */
1664
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
1665
    {
1666
        return $this->filterBy($property, $value, $comparisonOp);
1667
    }
1668
1669
    /**
1670
     * Get the first value from the current array.
1671
     *
1672
     * @return mixed
1673
     *               <p>Return null if there wasn't a element.</p>
1674
     */
1675 13
    public function first()
1676
    {
1677 13
        $tmpArray = $this->getArray();
1678
1679 13
        return \array_shift($tmpArray);
1680
    }
1681
1682
    /**
1683
     * Get the first value(s) from the current array.
1684
     * And will return an empty array if there was no first entry.
1685
     *
1686
     * @param int|null $number <p>How many values you will take?</p>
1687
     *
1688
     * @return static
1689
     *                <p>(Immutable)</p>
1690
     */
1691 36
    public function firstsImmutable(int $number = null): self
1692
    {
1693 36
        $arrayTmp = $this->getArray();
1694
1695 36
        if ($number === null) {
1696 14
            $array = (array) \array_shift($arrayTmp);
1697
        } else {
1698 22
            $number = (int) $number;
1699 22
            $array = \array_splice($arrayTmp, 0, $number);
1700
        }
1701
1702 36
        return static::create(
1703 36
            $array,
1704 36
            $this->iteratorClass,
1705 36
            false
1706
        );
1707
    }
1708
1709
    /**
1710
     * Get the first value(s) from the current array.
1711
     * And will return an empty array if there was no first entry.
1712
     *
1713
     * @param int|null $number <p>How many values you will take?</p>
1714
     *
1715
     * @return static
1716
     *                <p>(Mutable)</p>
1717
     */
1718 34
    public function firstsMutable(int $number = null): self
1719
    {
1720 34
        $this->generatorToArray();
1721
1722 34
        if ($number === null) {
1723 19
            $this->array = (array) \array_shift($this->array);
1724
        } else {
1725 15
            $number = (int) $number;
1726 15
            $this->array = \array_splice($this->array, 0, $number);
1727
        }
1728
1729 34
        return $this;
1730
    }
1731
1732
    /**
1733
     * Exchanges all keys with their associated values in an array.
1734
     *
1735
     * @return static
1736
     *                <p>(Immutable)</p>
1737
     */
1738 1
    public function flip(): self
1739
    {
1740 1
        return static::create(
1741 1
            \array_flip($this->getArray()),
1742 1
            $this->iteratorClass,
1743 1
            false
1744
        );
1745
    }
1746
1747
    /**
1748
     * Get a value from an array (optional using dot-notation).
1749
     *
1750
     * @param mixed $key      <p>The key to look for.</p>
1751
     * @param mixed $fallback <p>Value to fallback to.</p>
1752
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
1753
     *                        class.</p>
1754
     *
1755
     * @return mixed|static
1756
     */
1757 72
    public function get($key, $fallback = null, array $array = null)
1758
    {
1759 72
        if ($array !== null) {
1760 4
            $usedArray = $array;
1761
        } else {
1762 68
            $this->generatorToArray();
1763
1764 68
            $usedArray = $this->array;
1765
        }
1766
1767 72
        if ($key === null) {
1768 1
            return static::create(
1769 1
                $usedArray,
1770 1
                $this->iteratorClass,
1771 1
                false
1772
            );
1773
        }
1774
1775
        // php cast "bool"-index into "int"-index
1776 72
        if ((bool) $key === $key) {
1777 3
            $key = (int) $key;
1778
        }
1779
1780 72
        if (\array_key_exists($key, $usedArray) === true) {
1781 61
            if (\is_array($usedArray[$key])) {
1782 9
                return static::create(
1783 9
                    $usedArray[$key],
1784 9
                    $this->iteratorClass,
1785 9
                    false
1786
                );
1787
            }
1788
1789 54
            return $usedArray[$key];
1790
        }
1791
1792
        // crawl through array, get key according to object or not
1793 23
        $usePath = false;
1794
        if (
1795 23
            $this->pathSeparator
1796
            &&
1797 23
            \is_string($key)
1798
            &&
1799 23
            \strpos($key, $this->pathSeparator) !== false
1800
        ) {
1801 7
            $segments = \explode($this->pathSeparator, (string) $key);
1802 7
            if ($segments !== false) {
1803 7
                $usePath = true;
1804
1805 7
                foreach ($segments as $segment) {
1806
                    if (
1807
                        (
1808 7
                            \is_array($usedArray)
1809
                            ||
1810 7
                            $usedArray instanceof \ArrayAccess
1811
                        )
1812
                        &&
1813 7
                        isset($usedArray[$segment])
1814
                    ) {
1815 7
                        $usedArray = $usedArray[$segment];
1816
1817 7
                        continue;
1818
                    }
1819
1820
                    if (
1821 6
                        \is_object($usedArray)
1822
                        &&
1823 6
                        \property_exists($usedArray, $segment)
1824
                    ) {
1825 1
                        $usedArray = $usedArray->{$segment};
1826
1827 1
                        continue;
1828
                    }
1829
1830 5
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
1831
                }
1832
            }
1833
        }
1834
1835 23
        if (!$usePath && !isset($usedArray[$key])) {
1836 16
            return $fallback instanceof \Closure ? $fallback() : $fallback;
1837
        }
1838
1839 7
        if (\is_array($usedArray)) {
1840 1
            return static::create(
1841 1
                $usedArray,
1842 1
                $this->iteratorClass,
1843 1
                false
1844
            );
1845
        }
1846
1847 7
        return $usedArray;
1848
    }
1849
1850
    /**
1851
     * Get the current array from the "Arrayy"-object.
1852
     *
1853
     * @return array
1854
     */
1855 822
    public function getArray(): array
1856
    {
1857
        // init
1858 822
        $array = [];
1859
1860 822
        foreach ($this->getGenerator() as $key => $value) {
1861 712
            $array[$key] = $value;
1862
        }
1863
1864 822
        return $array;
1865
    }
1866
1867
    /**
1868
     * Returns the values from a single column of the input array, identified by
1869
     * the $columnKey, can be used to extract data-columns from multi-arrays.
1870
     *
1871
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
1872
     * array by the values from the $indexKey column in the input array.
1873
     *
1874
     * @param mixed $columnKey
1875
     * @param mixed $indexKey
1876
     *
1877
     * @return static
1878
     *                <p>(Immutable)</p>
1879
     */
1880 1
    public function getColumn($columnKey = null, $indexKey = null): self
1881
    {
1882 1
        return static::create(
1883 1
            \array_column($this->getArray(), $columnKey, $indexKey),
1884 1
            $this->iteratorClass,
1885 1
            false
1886
        );
1887
    }
1888
1889
    /**
1890
     * Get the current array from the "Arrayy"-object as generator.
1891
     *
1892
     * @return \Generator
1893
     */
1894 847
    public function getGenerator(): \Generator
1895
    {
1896 847
        if ($this->generator instanceof ArrayyRewindableGenerator) {
1897 5
            yield from $this->generator;
1898
        }
1899
1900 847
        yield from $this->array;
1901 834
    }
1902
1903
    /**
1904
     * alias: for "Arrayy->keys()"
1905
     *
1906
     * @return static
1907
     *                <p>(Immutable)</p>
1908
     *
1909
     * @see Arrayy::keys()
1910
     */
1911 1
    public function getKeys(): self
1912
    {
1913 1
        return $this->keys();
1914
    }
1915
1916
    /**
1917
     * Get the current array from the "Arrayy"-object as object.
1918
     *
1919
     * @return \stdClass
1920
     */
1921 4
    public function getObject(): \stdClass
1922
    {
1923 4
        return self::arrayToObject($this->getArray());
1924
    }
1925
1926
    /**
1927
     * alias: for "Arrayy->randomImmutable()"
1928
     *
1929
     * @return static
1930
     *                <p>(Immutable)</p>
1931
     *
1932
     * @see Arrayy::randomImmutable()
1933
     */
1934 4
    public function getRandom(): self
1935
    {
1936 4
        return $this->randomImmutable();
1937
    }
1938
1939
    /**
1940
     * alias: for "Arrayy->randomKey()"
1941
     *
1942
     * @return mixed
1943
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
1944
     *
1945
     * @see Arrayy::randomKey()
1946
     */
1947 3
    public function getRandomKey()
1948
    {
1949 3
        return $this->randomKey();
1950
    }
1951
1952
    /**
1953
     * alias: for "Arrayy->randomKeys()"
1954
     *
1955
     * @param int $number
1956
     *
1957
     * @return static
1958
     *                <p>(Immutable)</p>
1959
     *
1960
     * @see Arrayy::randomKeys()
1961
     */
1962 8
    public function getRandomKeys(int $number): self
1963
    {
1964 8
        return $this->randomKeys($number);
1965
    }
1966
1967
    /**
1968
     * alias: for "Arrayy->randomValue()"
1969
     *
1970
     * @return mixed
1971
     *               <p>Get a random value or null if there wasn't a value.</p>
1972
     *
1973
     * @see Arrayy::randomValue()
1974
     */
1975 3
    public function getRandomValue()
1976
    {
1977 3
        return $this->randomValue();
1978
    }
1979
1980
    /**
1981
     * alias: for "Arrayy->randomValues()"
1982
     *
1983
     * @param int $number
1984
     *
1985
     * @return static
1986
     *                <p>(Immutable)</p>
1987
     *
1988
     * @see Arrayy::randomValues()
1989
     */
1990 6
    public function getRandomValues(int $number): self
1991
    {
1992 6
        return $this->randomValues($number);
1993
    }
1994
1995
    /**
1996
     * Group values from a array according to the results of a closure.
1997
     *
1998
     * @param callable $grouper  <p>A callable function name.</p>
1999
     * @param bool     $saveKeys
2000
     *
2001
     * @return static
2002
     *                <p>(Immutable)</p>
2003
     */
2004 4
    public function group($grouper, bool $saveKeys = false): self
2005
    {
2006
        // init
2007 4
        $result = [];
2008
2009
        // Iterate over values, group by property/results from closure.
2010 4
        foreach ($this->getGenerator() as $key => $value) {
2011 4
            $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $this->getArray());
2012 4
            $newValue = $this->get($groupKey, null, $result);
2013
2014 4
            if ($groupKey instanceof self) {
2015
                $groupKey = $groupKey->getArray();
2016
            }
2017
2018 4
            if ($newValue instanceof self) {
2019 4
                $newValue = $newValue->getArray();
2020
            }
2021
2022
            // Add to results.
2023 4
            if ($groupKey !== null) {
2024 3
                if ($saveKeys) {
2025 2
                    $result[$groupKey] = $newValue;
2026 2
                    $result[$groupKey][$key] = $value;
2027
                } else {
2028 1
                    $result[$groupKey] = $newValue;
2029 1
                    $result[$groupKey][] = $value;
2030
                }
2031
            }
2032
        }
2033
2034 4
        return static::create(
2035 4
            $result,
2036 4
            $this->iteratorClass,
2037 4
            false
2038
        );
2039
    }
2040
2041
    /**
2042
     * Check if an array has a given key.
2043
     *
2044
     * @param mixed $key
2045
     *
2046
     * @return bool
2047
     */
2048 23
    public function has($key): bool
2049
    {
2050 23
        static $UN_FOUND = null;
2051
2052 23
        if ($UN_FOUND === null) {
2053
            // Generate unique string to use as marker.
2054 1
            $UN_FOUND = \uniqid('arrayy', true);
2055
        }
2056
2057 23
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2058
    }
2059
2060
    /**
2061
     * Implodes the values of this array.
2062
     *
2063
     * @param string $glue
2064
     *
2065
     * @return string
2066
     */
2067 27
    public function implode(string $glue = ''): string
2068
    {
2069 27
        return $this->implode_recursive($glue, $this->getArray(), false);
2070
    }
2071
2072
    /**
2073
     * Implodes the keys of this array.
2074
     *
2075
     * @param string $glue
2076
     *
2077
     * @return string
2078
     */
2079 8
    public function implodeKeys(string $glue = ''): string
2080
    {
2081 8
        return $this->implode_recursive($glue, $this->getArray(), true);
2082
    }
2083
2084
    /**
2085
     * Given a list and an iterate-function that returns
2086
     * a key for each element in the list (or a property name),
2087
     * returns an object with an index of each item.
2088
     *
2089
     * @param mixed $key
2090
     *
2091
     * @return static
2092
     *                <p>(Immutable)</p>
2093
     */
2094 4
    public function indexBy($key): self
2095
    {
2096
        // init
2097 4
        $results = [];
2098
2099 4
        foreach ($this->getGenerator() as $a) {
2100 4
            if (\array_key_exists($key, $a) === true) {
2101 3
                $results[$a[$key]] = $a;
2102
            }
2103
        }
2104
2105 4
        return static::create(
2106 4
            $results,
2107 4
            $this->iteratorClass,
2108 4
            false
2109
        );
2110
    }
2111
2112
    /**
2113
     * alias: for "Arrayy->searchIndex()"
2114
     *
2115
     * @param mixed $value <p>The value to search for.</p>
2116
     *
2117
     * @return mixed
2118
     *
2119
     * @see Arrayy::searchIndex()
2120
     */
2121 4
    public function indexOf($value)
2122
    {
2123 4
        return $this->searchIndex($value);
2124
    }
2125
2126
    /**
2127
     * Get everything but the last..$to items.
2128
     *
2129
     * @param int $to
2130
     *
2131
     * @return static
2132
     *                <p>(Immutable)</p>
2133
     */
2134 12
    public function initial(int $to = 1): self
2135
    {
2136 12
        return $this->firstsImmutable(\count($this->getArray(), \COUNT_NORMAL) - $to);
2137
    }
2138
2139
    /**
2140
     * Return an array with all elements found in input array.
2141
     *
2142
     * @param array $search
2143
     * @param bool  $keepKeys
2144
     *
2145
     * @return static
2146
     *                <p>(Immutable)</p>
2147
     */
2148 3
    public function intersection(array $search, bool $keepKeys = false): self
2149
    {
2150 3
        if ($keepKeys) {
2151 1
            return static::create(
2152 1
                \array_uintersect(
2153 1
                    $this->array,
2154 1
                    $search,
2155
                    static function ($a, $b) {
2156 1
                        return $a === $b ? 0 : -1;
2157 1
                    }
2158
                ),
2159 1
                $this->iteratorClass,
2160 1
                false
2161
            );
2162
        }
2163
2164 2
        return static::create(
2165 2
            \array_values(\array_intersect($this->getArray(), $search)),
2166 2
            $this->iteratorClass,
2167 2
            false
2168
        );
2169
    }
2170
2171
    /**
2172
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
2173
     *
2174
     * @param array $search
2175
     *
2176
     * @return bool
2177
     */
2178 1
    public function intersects(array $search): bool
2179
    {
2180 1
        return \count($this->intersection($search)->array, \COUNT_NORMAL) > 0;
2181
    }
2182
2183
    /**
2184
     * Invoke a function on all of an array's values.
2185
     *
2186
     * @param mixed $callable
2187
     * @param mixed $arguments
2188
     *
2189
     * @return static
2190
     *                <p>(Immutable)</p>
2191
     */
2192 1
    public function invoke($callable, $arguments = []): self
2193
    {
2194
        // If one argument given for each iteration, create an array for it.
2195 1
        if (!\is_array($arguments)) {
2196 1
            $arguments = StaticArrayy::repeat(
2197 1
                $arguments,
2198 1
                \count($this->getArray(), \COUNT_NORMAL)
2199 1
            )->getArray();
2200
        }
2201
2202
        // If the callable has arguments, pass them.
2203 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...
2204 1
            $array = \array_map($callable, $this->getArray(), $arguments);
2205
        } else {
2206 1
            $array = \array_map($callable, $this->getArray());
2207
        }
2208
2209 1
        return static::create(
2210 1
            $array,
2211 1
            $this->iteratorClass,
2212 1
            false
2213
        );
2214
    }
2215
2216
    /**
2217
     * Check whether array is associative or not.
2218
     *
2219
     * @param bool $recursive
2220
     *
2221
     * @return bool
2222
     *              <p>Returns true if associative, false otherwise.</p>
2223
     */
2224 15
    public function isAssoc(bool $recursive = false): bool
2225
    {
2226 15
        if ($this->isEmpty()) {
2227 3
            return false;
2228
        }
2229
2230 13
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2231 13
            if (!\is_string($key)) {
2232 11
                return false;
2233
            }
2234
        }
2235
2236 3
        return true;
2237
    }
2238
2239
    /**
2240
     * Check whether the array is empty or not.
2241
     *
2242
     * @return bool
2243
     *              <p>Returns true if empty, false otherwise.</p>
2244
     */
2245 38
    public function isEmpty(): bool
2246
    {
2247 38
        if ($this->generator) {
2248
            return $this->getArray() === [];
2249
        }
2250
2251 38
        return $this->array === [];
2252
    }
2253
2254
    /**
2255
     * Check if the current array is equal to the given "$array" or not.
2256
     *
2257
     * @param array $array
2258
     *
2259
     * @return bool
2260
     */
2261
    public function isEqual(array $array): bool
2262
    {
2263
        return $this->getArray() === $array;
2264
    }
2265
2266
    /**
2267
     * Check if the current array is a multi-array.
2268
     *
2269
     * @return bool
2270
     */
2271 14
    public function isMultiArray(): bool
2272
    {
2273
        return !(
2274 14
            \count($this->getArray(), \COUNT_NORMAL)
2275
            ===
2276 14
            \count($this->getArray(), \COUNT_RECURSIVE)
2277
        );
2278
    }
2279
2280
    /**
2281
     * Check whether array is numeric or not.
2282
     *
2283
     * @return bool
2284
     *              <p>Returns true if numeric, false otherwise.</p>
2285
     */
2286 5
    public function isNumeric(): bool
2287
    {
2288 5
        if ($this->isEmpty()) {
2289 2
            return false;
2290
        }
2291
2292 4
        foreach ($this->keys()->getGenerator() as $key) {
2293 4
            if (!\is_int($key)) {
2294 2
                return false;
2295
            }
2296
        }
2297
2298 2
        return true;
2299
    }
2300
2301
    /**
2302
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2303
     *
2304
     * @param bool $recursive
2305
     *
2306
     * @return bool
2307
     */
2308 1
    public function isSequential(bool $recursive = false): bool
2309
    {
2310
2311
        // recursive
2312
2313 1
        if ($recursive === true) {
2314
            return $this->array_keys_recursive($this->getArray())
2315
                   ===
2316
                   \range(0, \count($this->getArray(), \COUNT_RECURSIVE) - 1);
2317
        }
2318
2319
        // non recursive
2320
2321 1
        return \array_keys($this->getArray())
2322
               ===
2323 1
               \range(0, \count($this->getArray(), \COUNT_NORMAL) - 1);
2324
    }
2325
2326
    /**
2327
     * @return array
2328
     */
2329
    public function jsonSerialize(): array
2330
    {
2331
        return $this->getArray();
2332
    }
2333
2334
    /**
2335
     * Get all keys from the current array.
2336
     *
2337
     * @param bool  $recursive    [optional] <p>
2338
     *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2339
     *                            </p>
2340
     * @param mixed $search_value [optional] <p>
2341
     *                            If specified, then only keys containing these values are returned.
2342
     *                            </p>
2343
     * @param bool  $strict       [optional] <p>
2344
     *                            Determines if strict comparison (===) should be used during the search.
2345
     *                            </p>
2346
     *
2347
     * @return static
2348
     *                <p>(Immutable) An array of all the keys in input.</p>
2349
     */
2350 26
    public function keys(bool $recursive = false, $search_value = null, bool $strict = true): self
2351
    {
2352
2353
        // recursive
2354
2355 26
        if ($recursive === true) {
2356 3
            if ($search_value === null) {
2357 3
                $array = $this->array_keys_recursive($this->getArray());
2358
            } else {
2359
                $array = $this->array_keys_recursive($this->getArray(), $search_value, $strict);
2360
            }
2361
2362 3
            return static::create(
2363 3
                $array,
2364 3
                $this->iteratorClass,
2365 3
                false
2366
            );
2367
        }
2368
2369
        // non recursive
2370
2371 25
        if ($search_value === null) {
2372 25
            $array = \array_keys($this->getArray());
2373
        } else {
2374
            $array = \array_keys($this->getArray(), $search_value, $strict);
2375
        }
2376
2377 25
        return static::create(
2378 25
            $array,
2379 25
            $this->iteratorClass,
2380 25
            false
2381
        );
2382
    }
2383
2384
    /**
2385
     * Sort an array by key in reverse order.
2386
     *
2387
     * @param int $sort_flags [optional] <p>
2388
     *                        You may modify the behavior of the sort using the optional
2389
     *                        parameter sort_flags, for details
2390
     *                        see sort.
2391
     *                        </p>
2392
     *
2393
     * @return static
2394
     *                <p>(Mutable) Return this Arrayy object.</p>
2395
     */
2396 4
    public function krsort(int $sort_flags = 0): self
2397
    {
2398 4
        $this->generatorToArray();
2399
2400 4
        \krsort($this->array, $sort_flags);
2401
2402 4
        return $this;
2403
    }
2404
2405
    /**
2406
     * Get the last value from the current array.
2407
     *
2408
     * @return mixed
2409
     *               <p>Return null if there wasn't a element.</p>
2410
     */
2411 4
    public function last()
2412
    {
2413 4
        return $this->pop();
2414
    }
2415
2416
    /**
2417
     * Get the last value(s) from the current array.
2418
     *
2419
     * @param int|null $number
2420
     *
2421
     * @return static
2422
     *                <p>(Immutable)</p>
2423
     */
2424 13
    public function lastsImmutable(int $number = null): self
2425
    {
2426 13
        if ($this->isEmpty()) {
2427 1
            return static::create(
2428 1
                [],
2429 1
                $this->iteratorClass,
2430 1
                false
2431
            );
2432
        }
2433
2434 12
        if ($number === null) {
2435 8
            $poppedValue = $this->pop();
2436
2437 8
            if ($poppedValue === null) {
2438 1
                $poppedValue = [$poppedValue];
2439
            } else {
2440 7
                $poppedValue = (array) $poppedValue;
2441
            }
2442
2443 8
            $arrayy = static::create(
2444 8
                $poppedValue,
2445 8
                $this->iteratorClass,
2446 8
                false
2447
            );
2448
        } else {
2449 4
            $number = (int) $number;
2450 4
            $arrayy = $this->rest(-$number);
2451
        }
2452
2453 12
        return $arrayy;
2454
    }
2455
2456
    /**
2457
     * Get the last value(s) from the current array.
2458
     *
2459
     * @param int|null $number
2460
     *
2461
     * @return static
2462
     *                <p>(Mutable)</p>
2463
     */
2464 13
    public function lastsMutable(int $number = null): self
2465
    {
2466 13
        if ($this->isEmpty()) {
2467 1
            return $this;
2468
        }
2469
2470 12
        if ($number === null) {
2471 8
            $poppedValue = $this->pop();
2472
2473 8
            if ($poppedValue === null) {
2474 1
                $poppedValue = [$poppedValue];
2475
            } else {
2476 7
                $poppedValue = (array) $poppedValue;
2477
            }
2478
2479 8
            $this->array = static::create(
2480 8
                $poppedValue,
2481 8
                $this->iteratorClass,
2482 8
                false
2483 8
            )->getArray();
2484
        } else {
2485 4
            $number = (int) $number;
2486 4
            $this->array = $this->rest(-$number)->getArray();
2487
        }
2488
2489 12
        $this->generator = null;
2490
2491 12
        return $this;
2492
    }
2493
2494
    /**
2495
     * Count the values from the current array.
2496
     *
2497
     * alias: for "Arrayy->count()"
2498
     *
2499
     * @param int $mode
2500
     *
2501
     * @return int
2502
     *
2503
     * @see Arrayy::count()
2504
     */
2505 20
    public function length(int $mode = \COUNT_NORMAL): int
2506
    {
2507 20
        return $this->count($mode);
2508
    }
2509
2510
    /**
2511
     * Apply the given function to the every element of the array,
2512
     * collecting the results.
2513
     *
2514
     * @param callable $callable
2515
     *
2516
     * @return static
2517
     *                <p>(Immutable) Arrayy object with modified elements.</p>
2518
     */
2519 4
    public function map(callable $callable): self
2520
    {
2521 4
        return static::create(
2522 4
            \array_map($callable, $this->getArray()),
2523 4
            $this->iteratorClass,
2524 4
            false
2525
        );
2526
    }
2527
2528
    /**
2529
     * Check if all items in current array match a truth test.
2530
     *
2531
     * @param \Closure $closure
2532
     *
2533
     * @return bool
2534
     */
2535 15 View Code Duplication
    public function matches(\Closure $closure): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2536
    {
2537 15
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2538 2
            return false;
2539
        }
2540
2541 13
        foreach ($this->getGenerator() as $key => $value) {
2542 13
            $value = $closure($value, $key);
2543
2544 13
            if ($value === false) {
2545 7
                return false;
2546
            }
2547
        }
2548
2549 7
        return true;
2550
    }
2551
2552
    /**
2553
     * Check if any item in the current array matches a truth test.
2554
     *
2555
     * @param \Closure $closure
2556
     *
2557
     * @return bool
2558
     */
2559 14 View Code Duplication
    public function matchesAny(\Closure $closure): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2560
    {
2561 14
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2562 2
            return false;
2563
        }
2564
2565 12
        foreach ($this->getGenerator() as $key => $value) {
2566 12
            $value = $closure($value, $key);
2567
2568 12
            if ($value === true) {
2569 9
                return true;
2570
            }
2571
        }
2572
2573 4
        return false;
2574
    }
2575
2576
    /**
2577
     * Get the max value from an array.
2578
     *
2579
     * @return mixed
2580
     */
2581 10 View Code Duplication
    public function max()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2582
    {
2583 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2584 1
            return false;
2585
        }
2586
2587 9
        return \max($this->getArray());
2588
    }
2589
2590
    /**
2591
     * Merge the new $array into the current array.
2592
     *
2593
     * - keep key,value from the current array, also if the index is in the new $array
2594
     *
2595
     * @param array $array
2596
     * @param bool  $recursive
2597
     *
2598
     * @return static
2599
     *                <p>(Immutable)</p>
2600
     */
2601 25 View Code Duplication
    public function mergeAppendKeepIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2602
    {
2603 25
        if ($recursive === true) {
2604 4
            $result = \array_replace_recursive($this->getArray(), $array);
2605
        } else {
2606 21
            $result = \array_replace($this->getArray(), $array);
2607
        }
2608
2609 25
        return static::create(
2610 25
            $result,
2611 25
            $this->iteratorClass,
2612 25
            false
2613
        );
2614
    }
2615
2616
    /**
2617
     * Merge the new $array into the current array.
2618
     *
2619
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2620
     * - create new indexes
2621
     *
2622
     * @param array $array
2623
     * @param bool  $recursive
2624
     *
2625
     * @return static
2626
     *                <p>(Immutable)</p>
2627
     */
2628 16 View Code Duplication
    public function mergeAppendNewIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2629
    {
2630 16
        if ($recursive === true) {
2631 4
            $result = \array_merge_recursive($this->getArray(), $array);
2632
        } else {
2633 12
            $result = \array_merge($this->getArray(), $array);
2634
        }
2635
2636 16
        return static::create(
2637 16
            $result,
2638 16
            $this->iteratorClass,
2639 16
            false
2640
        );
2641
    }
2642
2643
    /**
2644
     * Merge the the current array into the $array.
2645
     *
2646
     * - use key,value from the new $array, also if the index is in the current array
2647
     *
2648
     * @param array $array
2649
     * @param bool  $recursive
2650
     *
2651
     * @return static
2652
     *                <p>(Immutable)</p>
2653
     */
2654 16 View Code Duplication
    public function mergePrependKeepIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2655
    {
2656 16
        if ($recursive === true) {
2657 4
            $result = \array_replace_recursive($array, $this->getArray());
2658
        } else {
2659 12
            $result = \array_replace($array, $this->getArray());
2660
        }
2661
2662 16
        return static::create(
2663 16
            $result,
2664 16
            $this->iteratorClass,
2665 16
            false
2666
        );
2667
    }
2668
2669
    /**
2670
     * Merge the current array into the new $array.
2671
     *
2672
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
2673
     * - create new indexes
2674
     *
2675
     * @param array $array
2676
     * @param bool  $recursive
2677
     *
2678
     * @return static
2679
     *                <p>(Immutable)</p>
2680
     */
2681 17 View Code Duplication
    public function mergePrependNewIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2682
    {
2683 17
        if ($recursive === true) {
2684 4
            $result = \array_merge_recursive($array, $this->getArray());
2685
        } else {
2686 13
            $result = \array_merge($array, $this->getArray());
2687
        }
2688
2689 17
        return static::create(
2690 17
            $result,
2691 17
            $this->iteratorClass,
2692 17
            false
2693
        );
2694
    }
2695
2696
    /**
2697
     * @return ArrayyMeta|static
2698
     */
2699 14
    public static function meta()
2700
    {
2701 14
        return (new ArrayyMeta())->getMetaObject(static::class);
2702
    }
2703
2704
    /**
2705
     * Get the min value from an array.
2706
     *
2707
     * @return mixed
2708
     */
2709 10 View Code Duplication
    public function min()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2710
    {
2711 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2712 1
            return false;
2713
        }
2714
2715 9
        return \min($this->getArray());
2716
    }
2717
2718
    /**
2719
     * Move an array element to a new index.
2720
     *
2721
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2722
     *
2723
     * @param int|string $from
2724
     * @param int        $to
2725
     *
2726
     * @return static
2727
     *                <p>(Immutable)</p>
2728
     */
2729 1
    public function moveElement($from, $to): self
2730
    {
2731 1
        $array = $this->getArray();
2732
2733 1
        if (\is_int($from)) {
2734 1
            $tmp = \array_splice($array, $from, 1);
2735 1
            \array_splice($array, (int) $to, 0, $tmp);
2736 1
            $output = $array;
2737 1
        } elseif (\is_string($from)) {
2738 1
            $indexToMove = \array_search($from, \array_keys($array), true);
2739 1
            $itemToMove = $array[$from];
2740 1
            if ($indexToMove !== false) {
2741 1
                \array_splice($array, $indexToMove, 1);
2742
            }
2743 1
            $i = 0;
2744 1
            $output = [];
2745 1
            foreach ($array as $key => $item) {
2746 1
                if ($i === $to) {
2747 1
                    $output[$from] = $itemToMove;
2748
                }
2749 1
                $output[$key] = $item;
2750 1
                ++$i;
2751
            }
2752
        } else {
2753
            $output = [];
2754
        }
2755
2756 1
        return static::create(
2757 1
            $output,
2758 1
            $this->iteratorClass,
2759 1
            false
2760
        );
2761
    }
2762
2763
    /**
2764
     * Get a subset of the items from the given array.
2765
     *
2766
     * @param mixed[] $keys
2767
     *
2768
     * @return static
2769
     *                <p>(Immutable)</p>
2770
     */
2771
    public function only(array $keys): self
2772
    {
2773
        $array = $this->getArray();
2774
2775
        return static::create(
2776
            \array_intersect_key($array, \array_flip($keys)),
2777
            $this->iteratorClass,
2778
            false
2779
        );
2780
    }
2781
2782
    /**
2783
     * Pad array to the specified size with a given value.
2784
     *
2785
     * @param int   $size  <p>Size of the result array.</p>
2786
     * @param mixed $value <p>Empty value by default.</p>
2787
     *
2788
     * @return static
2789
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
2790
     */
2791 4
    public function pad(int $size, $value): self
2792
    {
2793 4
        return static::create(
2794 4
            \array_pad($this->getArray(), $size, $value),
2795 4
            $this->iteratorClass,
2796 4
            false
2797
        );
2798
    }
2799
2800
    /**
2801
     * Pop a specified value off the end of the current array.
2802
     *
2803
     * @return mixed
2804
     *               <p>(Mutable) The popped element from the current array.</p>
2805
     */
2806 16
    public function pop()
2807
    {
2808 16
        $this->generatorToArray();
2809
2810 16
        return \array_pop($this->array);
2811
    }
2812
2813
    /**
2814
     * Prepend a (key) + value to the current array.
2815
     *
2816
     * @param mixed $value
2817
     * @param mixed $key
2818
     *
2819
     * @return static
2820
     *                <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2821
     */
2822 8
    public function prepend($value, $key = null): self
2823
    {
2824 8
        $this->generatorToArray();
2825
2826 8
        if ($key === null) {
2827 8
            \array_unshift($this->array, $value);
2828
        } else {
2829
            /** @noinspection AdditionOperationOnArraysInspection */
2830 1
            $this->array = [$key => $value] + $this->array;
2831
        }
2832
2833 8
        return $this;
2834
    }
2835
2836
    /**
2837
     * Add a suffix to each key.
2838
     *
2839
     * @param mixed $suffix
2840
     *
2841
     * @return static
2842
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2843
     */
2844 10 View Code Duplication
    public function prependToEachKey($suffix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2845
    {
2846
        // init
2847 10
        $result = [];
2848
2849 10
        foreach ($this->getGenerator() as $key => $item) {
2850 9
            if ($item instanceof self) {
2851
                $result[$key] = $item->prependToEachKey($suffix);
2852 9
            } elseif (\is_array($item)) {
2853
                $result[$key] = self::create(
2854
                    $item,
2855
                    $this->iteratorClass,
2856
                    false
2857
                )->prependToEachKey($suffix)
2858
                    ->toArray();
2859
            } else {
2860 9
                $result[$key . $suffix] = $item;
2861
            }
2862
        }
2863
2864 10
        return self::create(
2865 10
            $result,
2866 10
            $this->iteratorClass,
2867 10
            false
2868
        );
2869
    }
2870
2871
    /**
2872
     * Add a suffix to each value.
2873
     *
2874
     * @param mixed $suffix
2875
     *
2876
     * @return static
2877
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2878
     */
2879 10 View Code Duplication
    public function prependToEachValue($suffix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2880
    {
2881
        // init
2882 10
        $result = [];
2883
2884 10
        foreach ($this->getGenerator() as $key => $item) {
2885 9
            if ($item instanceof self) {
2886
                $result[$key] = $item->prependToEachValue($suffix);
2887 9
            } elseif (\is_array($item)) {
2888
                $result[$key] = self::create(
2889
                    $item,
2890
                    $this->iteratorClass,
2891
                    false
2892
                )->prependToEachValue($suffix)
2893
                    ->toArray();
2894 9
            } elseif (\is_object($item)) {
2895 1
                $result[$key] = $item;
2896
            } else {
2897 8
                $result[$key] = $item . $suffix;
2898
            }
2899
        }
2900
2901 10
        return self::create(
2902 10
            $result,
2903 10
            $this->iteratorClass,
2904 10
            false
2905
        );
2906
    }
2907
2908
    /**
2909
     * Push one or more values onto the end of array at once.
2910
     *
2911
     * @return static
2912
     *                <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2913
     */
2914 4 View Code Duplication
    public function push(/* variadic arguments allowed */): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2915
    {
2916 4
        $this->generatorToArray();
2917
2918 4
        if (\func_num_args()) {
2919 4
            $args = \func_get_args();
2920 4
            \array_push(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_push() as the parameter $array expects a reference.
Loading history...
2921
        }
2922
2923 4
        return $this;
2924
    }
2925
2926
    /**
2927
     * Get a random value from the current array.
2928
     *
2929
     * @param int|null $number <p>How many values you will take?</p>
2930
     *
2931
     * @return static
2932
     *                <p>(Immutable)</p>
2933
     */
2934 18
    public function randomImmutable(int $number = null): self
2935
    {
2936 18
        $this->generatorToArray();
2937
2938 18 View Code Duplication
        if (\count($this->array, \COUNT_NORMAL) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2939 1
            return static::create(
2940 1
                [],
2941 1
                $this->iteratorClass,
2942 1
                false
2943
            );
2944
        }
2945
2946 17 View Code Duplication
        if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2947
            /** @noinspection NonSecureArrayRandUsageInspection */
2948 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
2949
2950 13
            return static::create(
2951 13
                $arrayRandValue,
2952 13
                $this->iteratorClass,
2953 13
                false
2954
            );
2955
        }
2956
2957 5
        $arrayTmp = $this->array;
2958
        /** @noinspection NonSecureShuffleUsageInspection */
2959 5
        \shuffle($arrayTmp);
2960
2961 5
        return static::create(
2962 5
            $arrayTmp,
2963 5
            $this->iteratorClass,
2964 5
            false
2965 5
        )->firstsImmutable($number);
2966
    }
2967
2968
    /**
2969
     * Pick a random key/index from the keys of this array.
2970
     *
2971
     * @throws \RangeException If array is empty
2972
     *
2973
     * @return mixed
2974
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2975
     */
2976 4
    public function randomKey()
2977
    {
2978 4
        $result = $this->randomKeys(1);
2979
2980 4
        if (!isset($result[0])) {
2981
            $result[0] = null;
2982
        }
2983
2984 4
        return $result[0];
2985
    }
2986
2987
    /**
2988
     * Pick a given number of random keys/indexes out of this array.
2989
     *
2990
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2991
     *
2992
     * @throws \RangeException If array is empty
2993
     *
2994
     * @return static
2995
     *                <p>(Immutable)</p>
2996
     */
2997 13
    public function randomKeys(int $number): self
2998
    {
2999 13
        $this->generatorToArray();
3000
3001 13
        $count = \count($this->array, \COUNT_NORMAL);
3002
3003 13
        if ($number === 0 || $number > $count) {
3004 2
            throw new \RangeException(
3005 2
                \sprintf(
3006 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
3007 2
                    $number,
3008 2
                    $count
3009
                )
3010
            );
3011
        }
3012
3013 11
        $result = (array) \array_rand($this->array, $number);
3014
3015 11
        return static::create(
3016 11
            $result,
3017 11
            $this->iteratorClass,
3018 11
            false
3019
        );
3020
    }
3021
3022
    /**
3023
     * Get a random value from the current array.
3024
     *
3025
     * @param int|null $number <p>How many values you will take?</p>
3026
     *
3027
     * @return static
3028
     *                <p>(Mutable)</p>
3029
     */
3030 17
    public function randomMutable(int $number = null): self
3031
    {
3032 17
        $this->generatorToArray();
3033
3034 17 View Code Duplication
        if (\count($this->array, \COUNT_NORMAL) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3035
            return static::create(
3036
                [],
3037
                $this->iteratorClass,
3038
                false
3039
            );
3040
        }
3041
3042 17 View Code Duplication
        if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3043
            /** @noinspection NonSecureArrayRandUsageInspection */
3044 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3045 7
            $this->array = $arrayRandValue;
3046
3047 7
            return $this;
3048
        }
3049
3050
        /** @noinspection NonSecureShuffleUsageInspection */
3051 11
        \shuffle($this->array);
3052
3053 11
        return $this->firstsMutable($number);
3054
    }
3055
3056
    /**
3057
     * Pick a random value from the values of this array.
3058
     *
3059
     * @return mixed
3060
     *               <p>Get a random value or null if there wasn't a value.</p>
3061
     */
3062 4
    public function randomValue()
3063
    {
3064 4
        $result = $this->randomImmutable();
3065
3066 4
        if (!isset($result[0])) {
3067
            $result[0] = null;
3068
        }
3069
3070 4
        return $result[0];
3071
    }
3072
3073
    /**
3074
     * Pick a given number of random values out of this array.
3075
     *
3076
     * @param int $number
3077
     *
3078
     * @return static
3079
     *                <p>(Mutable)</p>
3080
     */
3081 7
    public function randomValues(int $number): self
3082
    {
3083 7
        return $this->randomMutable($number);
3084
    }
3085
3086
    /**
3087
     * Get a random value from an array, with the ability to skew the results.
3088
     *
3089
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3090
     *
3091
     * @param array    $array
3092
     * @param int|null $number <p>How many values you will take?</p>
3093
     *
3094
     * @return static
3095
     *                <p>(Immutable)</p>
3096
     */
3097 9
    public function randomWeighted(array $array, int $number = null): self
3098
    {
3099
        // init
3100 9
        $options = [];
3101
3102 9
        foreach ($array as $option => $weight) {
3103 9
            if ($this->searchIndex($option) !== false) {
3104 2
                for ($i = 0; $i < $weight; ++$i) {
3105 1
                    $options[] = $option;
3106
                }
3107
            }
3108
        }
3109
3110 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3111
    }
3112
3113
    /**
3114
     * Reduce the current array via callable e.g. anonymous-function.
3115
     *
3116
     * @param callable $callable
3117
     * @param array    $init
3118
     *
3119
     * @return static
3120
     *                <p>(Immutable)</p>
3121
     */
3122 16
    public function reduce($callable, array $init = []): self
3123
    {
3124 16
        if ($this->generator) {
3125 1
            $result = $init;
3126
3127 1
            foreach ($this->getGenerator() as $value) {
3128 1
                $result = $callable($result, $value);
3129
            }
3130
3131 1
            return static::create(
3132 1
                $result,
3133 1
                $this->iteratorClass,
3134 1
                false
3135
            );
3136
        }
3137
3138 16
        $result = \array_reduce($this->array, $callable, $init);
3139
3140 16
        if ($result === null) {
3141
            $this->array = [];
3142
        } else {
3143 16
            $this->array = (array) $result;
3144
        }
3145
3146 16
        return static::create(
3147 16
            $this->array,
3148 16
            $this->iteratorClass,
3149 16
            false
3150
        );
3151
    }
3152
3153
    /**
3154
     * Create a numerically re-indexed Arrayy object.
3155
     *
3156
     * @return static
3157
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
3158
     */
3159 9
    public function reindex(): self
3160
    {
3161 9
        $this->generatorToArray();
3162
3163 9
        $this->array = \array_values($this->array);
3164
3165 9
        return $this;
3166
    }
3167
3168
    /**
3169
     * Return all items that fail the truth test.
3170
     *
3171
     * @param \Closure $closure
3172
     *
3173
     * @return static
3174
     *                <p>(Immutable)</p>
3175
     */
3176 1 View Code Duplication
    public function reject(\Closure $closure): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3177
    {
3178
        // init
3179 1
        $filtered = [];
3180
3181 1
        foreach ($this->getGenerator() as $key => $value) {
3182 1
            if (!$closure($value, $key)) {
3183 1
                $filtered[$key] = $value;
3184
            }
3185
        }
3186
3187 1
        return static::create(
3188 1
            $filtered,
3189 1
            $this->iteratorClass,
3190 1
            false
3191
        );
3192
    }
3193
3194
    /**
3195
     * Remove a value from the current array (optional using dot-notation).
3196
     *
3197
     * @param mixed $key
3198
     *
3199
     * @return static
3200
     *                <p>(Immutable)</p>
3201
     */
3202 18
    public function remove($key): self
3203
    {
3204
        // recursive call
3205 18
        if (\is_array($key)) {
3206
            foreach ($key as $k) {
3207
                $this->internalRemove($k);
3208
            }
3209
3210
            return static::create(
3211
                $this->getArray(),
3212
                $this->iteratorClass,
3213
                false
3214
            );
3215
        }
3216
3217 18
        $this->internalRemove($key);
3218
3219 18
        return static::create(
3220 18
            $this->getArray(),
3221 18
            $this->iteratorClass,
3222 18
            false
3223
        );
3224
    }
3225
3226
    /**
3227
     * Remove the first value from the current array.
3228
     *
3229
     * @return static
3230
     *                <p>(Immutable)</p>
3231
     */
3232 7 View Code Duplication
    public function removeFirst(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3233
    {
3234 7
        $tmpArray = $this->getArray();
3235
3236 7
        \array_shift($tmpArray);
3237
3238 7
        return static::create(
3239 7
            $tmpArray,
3240 7
            $this->iteratorClass,
3241 7
            false
3242
        );
3243
    }
3244
3245
    /**
3246
     * Remove the last value from the current array.
3247
     *
3248
     * @return static
3249
     *                <p>(Immutable)</p>
3250
     */
3251 7 View Code Duplication
    public function removeLast(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3252
    {
3253 7
        $tmpArray = $this->getArray();
3254
3255 7
        \array_pop($tmpArray);
3256
3257 7
        return static::create(
3258 7
            $tmpArray,
3259 7
            $this->iteratorClass,
3260 7
            false
3261
        );
3262
    }
3263
3264
    /**
3265
     * Removes a particular value from an array (numeric or associative).
3266
     *
3267
     * @param mixed $value
3268
     *
3269
     * @return static
3270
     *                <p>(Immutable)</p>
3271
     */
3272 7
    public function removeValue($value): self
3273
    {
3274 7
        $this->generatorToArray();
3275
3276
        // init
3277 7
        $isNumericArray = true;
3278
3279 7
        foreach ($this->getGenerator() as $key => $item) {
3280 6
            if ($item === $value) {
3281 6
                if (!\is_int($key)) {
3282
                    $isNumericArray = false;
3283
                }
3284 6
                unset($this->array[$key]);
3285
            }
3286
        }
3287
3288 7
        if ($isNumericArray) {
3289 7
            $this->array = \array_values($this->array);
3290
        }
3291
3292 7
        return static::create(
3293 7
            $this->array,
3294 7
            $this->iteratorClass,
3295 7
            false
3296
        );
3297
    }
3298
3299
    /**
3300
     * Generate array of repeated arrays.
3301
     *
3302
     * @param int $times <p>How many times has to be repeated.</p>
3303
     *
3304
     * @return static
3305
     *                <p>(Immutable)</p>
3306
     */
3307 1
    public function repeat($times): self
3308
    {
3309 1
        if ($times === 0) {
3310 1
            return new static();
3311
        }
3312
3313 1
        return static::create(
3314 1
            \array_fill(0, (int) $times, $this->getArray()),
3315 1
            $this->iteratorClass,
3316 1
            false
3317
        );
3318
    }
3319
3320
    /**
3321
     * Replace a key with a new key/value pair.
3322
     *
3323
     * @param mixed $replace
3324
     * @param mixed $key
3325
     * @param mixed $value
3326
     *
3327
     * @return static
3328
     *                <p>(Immutable)</p>
3329
     */
3330 2
    public function replace($replace, $key, $value): self
3331
    {
3332 2
        $that = $this->remove($replace);
3333
3334 2
        return $that->set($key, $value);
3335
    }
3336
3337
    /**
3338
     * Create an array using the current array as values and the other array as keys.
3339
     *
3340
     * @param array $keys <p>An array of keys.</p>
3341
     *
3342
     * @return static
3343
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
3344
     */
3345 2
    public function replaceAllKeys(array $keys): self
3346
    {
3347 2
        return static::create(
3348 2
            \array_combine($keys, $this->getArray()),
3349 2
            $this->iteratorClass,
3350 2
            false
3351
        );
3352
    }
3353
3354
    /**
3355
     * Create an array using the current array as keys and the other array as values.
3356
     *
3357
     * @param array $array <p>An array o values.</p>
3358
     *
3359
     * @return static
3360
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3361
     */
3362 2
    public function replaceAllValues(array $array): self
3363
    {
3364 2
        return static::create(
3365 2
            \array_combine($this->array, $array),
3366 2
            $this->iteratorClass,
3367 2
            false
3368
        );
3369
    }
3370
3371
    /**
3372
     * Replace the keys in an array with another set.
3373
     *
3374
     * @param array $keys <p>An array of keys matching the array's size</p>
3375
     *
3376
     * @return static
3377
     *                <p>(Immutable)</p>
3378
     */
3379 1
    public function replaceKeys(array $keys): self
3380
    {
3381 1
        $values = \array_values($this->getArray());
3382 1
        $result = \array_combine($keys, $values);
3383
3384 1
        return static::create(
3385 1
            $result,
3386 1
            $this->iteratorClass,
3387 1
            false
3388
        );
3389
    }
3390
3391
    /**
3392
     * Replace the first matched value in an array.
3393
     *
3394
     * @param mixed $search      <p>The value to replace.</p>
3395
     * @param mixed $replacement <p>The value to replace.</p>
3396
     *
3397
     * @return static
3398
     *                <p>(Immutable)</p>
3399
     */
3400 3
    public function replaceOneValue($search, $replacement = ''): self
3401
    {
3402 3
        $array = $this->getArray();
3403 3
        $key = \array_search($search, $array, true);
3404
3405 3
        if ($key !== false) {
3406 3
            $array[$key] = $replacement;
3407
        }
3408
3409 3
        return static::create(
3410 3
            $array,
3411 3
            $this->iteratorClass,
3412 3
            false
3413
        );
3414
    }
3415
3416
    /**
3417
     * Replace values in the current array.
3418
     *
3419
     * @param mixed $search      <p>The value to replace.</p>
3420
     * @param mixed $replacement <p>What to replace it with.</p>
3421
     *
3422
     * @return static
3423
     *                <p>(Immutable)</p>
3424
     */
3425 1
    public function replaceValues($search, $replacement = ''): self
3426
    {
3427 1
        $array = $this->each(
3428
            static function ($value) use ($search, $replacement) {
3429 1
                return \str_replace($search, $replacement, $value);
3430 1
            }
3431
        );
3432
3433 1
        return $array;
3434
    }
3435
3436
    /**
3437
     * Get the last elements from index $from until the end of this array.
3438
     *
3439
     * @param int $from
3440
     *
3441
     * @return static
3442
     *                <p>(Immutable)</p>
3443
     */
3444 15 View Code Duplication
    public function rest(int $from = 1): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3445
    {
3446 15
        $tmpArray = $this->getArray();
3447
3448 15
        return static::create(
3449 15
            \array_splice($tmpArray, $from),
3450 15
            $this->iteratorClass,
3451 15
            false
3452
        );
3453
    }
3454
3455
    /**
3456
     * Return the array in the reverse order.
3457
     *
3458
     * @return static
3459
     *                <p>(Mutable) Return this Arrayy object.</p>
3460
     */
3461 8
    public function reverse(): self
3462
    {
3463 8
        $this->generatorToArray();
3464
3465 8
        $this->array = \array_reverse($this->array);
3466
3467 8
        return $this;
3468
    }
3469
3470
    /**
3471
     * Sort an array in reverse order.
3472
     *
3473
     * @param int $sort_flags [optional] <p>
3474
     *                        You may modify the behavior of the sort using the optional
3475
     *                        parameter sort_flags, for details
3476
     *                        see sort.
3477
     *                        </p>
3478
     *
3479
     * @return static
3480
     *                <p>(Mutable) Return this Arrayy object.</p>
3481
     */
3482 4
    public function rsort(int $sort_flags = 0): self
3483
    {
3484 4
        $this->generatorToArray();
3485
3486 4
        \rsort($this->array, $sort_flags);
3487
3488 4
        return $this;
3489
    }
3490
3491
    /**
3492
     * Search for the first index of the current array via $value.
3493
     *
3494
     * @param mixed $value
3495
     *
3496
     * @return false|float|int|string
3497
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
3498
     */
3499 20
    public function searchIndex($value)
3500
    {
3501 20
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
3502 19
            if ($value === $valueFromArray) {
3503 9
                return $keyFromArray;
3504
            }
3505
        }
3506
3507 11
        return false;
3508
    }
3509
3510
    /**
3511
     * Search for the value of the current array via $index.
3512
     *
3513
     * @param mixed $index
3514
     *
3515
     * @return static
3516
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3517
     */
3518 9
    public function searchValue($index): self
3519
    {
3520 9
        $this->generatorToArray();
3521
3522
        // init
3523 9
        $return = [];
3524
3525 9
        if ($this->array === []) {
3526
            return static::create(
3527
                [],
3528
                $this->iteratorClass,
3529
                false
3530
            );
3531
        }
3532
3533
        // php cast "bool"-index into "int"-index
3534 9
        if ((bool) $index === $index) {
3535 1
            $index = (int) $index;
3536
        }
3537
3538 9
        if (\array_key_exists($index, $this->array) === true) {
3539 7
            $return = [$this->array[$index]];
3540
        }
3541
3542 9
        return static::create(
3543 9
            $return,
3544 9
            $this->iteratorClass,
3545 9
            false
3546
        );
3547
    }
3548
3549
    /**
3550
     * Set a value for the current array (optional using dot-notation).
3551
     *
3552
     * @param string $key   <p>The key to set.</p>
3553
     * @param mixed  $value <p>Its value.</p>
3554
     *
3555
     * @return static
3556
     *                <p>(Mutable)</p>
3557
     */
3558 18
    public function set($key, $value): self
3559
    {
3560 18
        $this->generatorToArray();
3561
3562 18
        $this->internalSet($key, $value);
3563
3564 18
        return $this;
3565
    }
3566
3567
    /**
3568
     * Get a value from a array and set it if it was not.
3569
     *
3570
     * WARNING: this method only set the value, if the $key is not already set
3571
     *
3572
     * @param mixed $key      <p>The key</p>
3573
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
3574
     *
3575
     * @return mixed
3576
     *               <p>(Mutable)</p>
3577
     */
3578 11
    public function setAndGet($key, $fallback = null)
3579
    {
3580 11
        $this->generatorToArray();
3581
3582
        // If the key doesn't exist, set it.
3583 11
        if (!$this->has($key)) {
3584 4
            $this->array = $this->set($key, $fallback)->getArray();
3585
        }
3586
3587 11
        return $this->get($key);
3588
    }
3589
3590
    /**
3591
     * Shifts a specified value off the beginning of array.
3592
     *
3593
     * @return mixed
3594
     *               <p>(Mutable) A shifted element from the current array.</p>
3595
     */
3596 4
    public function shift()
3597
    {
3598 4
        $this->generatorToArray();
3599
3600 4
        return \array_shift($this->array);
3601
    }
3602
3603
    /**
3604
     * Shuffle the current array.
3605
     *
3606
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3607
     * @param array $array  [optional]
3608
     *
3609
     * @return static
3610
     *                <p>(Immutable)</p>
3611
     */
3612 1
    public function shuffle(bool $secure = false, array $array = null): self
3613
    {
3614 1
        if ($array === null) {
3615 1
            $array = $this->getArray();
3616
        }
3617
3618 1
        if ($secure !== true) {
3619
            /** @noinspection NonSecureShuffleUsageInspection */
3620 1
            \shuffle($array);
3621
        } else {
3622 1
            $size = \count($array, \COUNT_NORMAL);
3623 1
            $keys = \array_keys($array);
3624 1
            for ($i = $size - 1; $i > 0; --$i) {
3625
                try {
3626 1
                    $r = \random_int(0, $i);
3627
                } catch (\Exception $e) {
3628
                    /** @noinspection RandomApiMigrationInspection */
3629
                    $r = \mt_rand(0, $i);
3630
                }
3631 1
                if ($r !== $i) {
3632
                    $temp = $array[$keys[$r]];
3633
                    $array[$keys[$r]] = $array[$keys[$i]];
3634
                    $array[$keys[$i]] = $temp;
3635
                }
3636
            }
3637
3638
            // reset indices
3639 1
            $array = \array_values($array);
3640
        }
3641
3642 1
        foreach ($array as $key => $value) {
3643
            // check if recursive is needed
3644 1
            if (\is_array($value) === true) {
3645
                $array[$key] = $this->shuffle($secure, $value);
3646
            }
3647
        }
3648
3649 1
        return static::create(
3650 1
            $array,
3651 1
            $this->iteratorClass,
3652 1
            false
3653
        );
3654
    }
3655
3656
    /**
3657
     * Count the values from the current array.
3658
     *
3659
     * alias: for "Arrayy->count()"
3660
     *
3661
     * @param int $mode
3662
     *
3663
     * @return int
3664
     */
3665 20
    public function size(int $mode = \COUNT_NORMAL): int
3666
    {
3667 20
        return $this->count($mode);
3668
    }
3669
3670
    /**
3671
     * Counts all elements in an array, or something in an object.
3672
     *
3673
     * <p>
3674
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3675
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3676
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3677
     * implemented and used in PHP.
3678
     * </p>
3679
     *
3680
     * @return int
3681
     *             <p>
3682
     *             The number of elements in var, which is
3683
     *             typically an array, since anything else will have one
3684
     *             element.
3685
     *             </p>
3686
     *             <p>
3687
     *             If var is not an array or an object with
3688
     *             implemented Countable interface,
3689
     *             1 will be returned.
3690
     *             There is one exception, if var is &null;,
3691
     *             0 will be returned.
3692
     *             </p>
3693
     *             <p>
3694
     *             Caution: count may return 0 for a variable that isn't set,
3695
     *             but it may also return 0 for a variable that has been initialized with an
3696
     *             empty array. Use isset to test if a variable is set.
3697
     *             </p>
3698
     */
3699 10
    public function sizeRecursive(): int
3700
    {
3701 10
        return \count($this->getArray(), \COUNT_RECURSIVE);
3702
    }
3703
3704
    /**
3705
     * Extract a slice of the array.
3706
     *
3707
     * @param int      $offset       <p>Slice begin index.</p>
3708
     * @param int|null $length       <p>Length of the slice.</p>
3709
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3710
     *
3711
     * @return static
3712
     *                <p>A slice of the original array with length $length.</p>
3713
     */
3714 4
    public function slice(int $offset, int $length = null, bool $preserveKeys = false): self
3715
    {
3716 4
        return static::create(
3717 4
            \array_slice(
3718 4
                $this->getArray(),
3719 4
                $offset,
3720 4
                $length,
3721 4
                $preserveKeys
3722
            ),
3723 4
            $this->iteratorClass,
3724 4
            false
3725
        );
3726
    }
3727
3728
    /**
3729
     * Sort the current array and optional you can keep the keys.
3730
     *
3731
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3732
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3733
     *                              <strong>SORT_NATURAL</strong></p>
3734
     * @param bool       $keepKeys
3735
     *
3736
     * @return static
3737
     *                <p>(Mutable) Return this Arrayy object.</p>
3738
     */
3739 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
3740
    {
3741 20
        $this->generatorToArray();
3742
3743 20
        return $this->sorting(
3744 20
            $this->array,
3745 20
            $direction,
3746 20
            $strategy,
3747 20
            $keepKeys
3748
        );
3749
    }
3750
3751
    /**
3752
     * Sort the current array by key.
3753
     *
3754
     * @see http://php.net/manual/en/function.ksort.php
3755
     * @see http://php.net/manual/en/function.krsort.php
3756
     *
3757
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3758
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3759
     *                              <strong>SORT_NATURAL</strong></p>
3760
     *
3761
     * @return static
3762
     *                <p>(Mutable) Return this Arrayy object.</p>
3763
     */
3764 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3765
    {
3766 18
        $this->generatorToArray();
3767
3768 18
        $this->sorterKeys($this->array, $direction, $strategy);
3769
3770 18
        return $this;
3771
    }
3772
3773
    /**
3774
     * Sort the current array by value.
3775
     *
3776
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3777
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3778
     *                              <strong>SORT_NATURAL</strong></p>
3779
     *
3780
     * @return static
3781
     *                <p>(Mutable)</p>
3782
     */
3783 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3784
    {
3785 1
        return $this->sort($direction, $strategy, true);
3786
    }
3787
3788
    /**
3789
     * Sort the current array by value.
3790
     *
3791
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3792
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3793
     *                              <strong>SORT_NATURAL</strong></p>
3794
     *
3795
     * @return static
3796
     *                <p>(Mutable)</p>
3797
     */
3798 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3799
    {
3800 1
        return $this->sort($direction, $strategy, false);
3801
    }
3802
3803
    /**
3804
     * Sort a array by value, by a closure or by a property.
3805
     *
3806
     * - If the sorter is null, the array is sorted naturally.
3807
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3808
     *
3809
     * @param callable|null $sorter
3810
     * @param int|string    $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3811
     * @param int           $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3812
     *                                 <strong>SORT_NATURAL</strong></p>
3813
     *
3814
     * @return static
3815
     *                <p>(Immutable)</p>
3816
     */
3817 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3818
    {
3819 1
        $array = $this->getArray();
3820 1
        $direction = $this->getDirection($direction);
3821
3822
        // Transform all values into their results.
3823 1
        if ($sorter) {
3824 1
            $arrayy = static::create(
3825 1
                $array,
3826 1
                $this->iteratorClass,
3827 1
                false
3828
            );
3829
3830 1
            $that = $this;
3831 1
            $results = $arrayy->each(
3832
                static function ($value) use ($sorter, $that) {
3833 1
                    return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3834 1
                }
3835
            );
3836
3837 1
            $results = $results->getArray();
3838
        } else {
3839 1
            $results = $array;
3840
        }
3841
3842
        // Sort by the results and replace by original values
3843 1
        \array_multisort($results, $direction, $strategy, $array);
3844
3845 1
        return static::create(
3846 1
            $array,
3847 1
            $this->iteratorClass,
3848 1
            false
3849
        );
3850
    }
3851
3852
    /**
3853
     * Split an array in the given amount of pieces.
3854
     *
3855
     * @param int  $numberOfPieces
3856
     * @param bool $keepKeys
3857
     *
3858
     * @return static
3859
     *                <p>(Immutable)</p>
3860
     */
3861 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
3862
    {
3863 1
        $this->generatorToArray();
3864
3865 1
        $arrayCount = \count($this->array, \COUNT_NORMAL);
3866
3867 1
        if ($arrayCount === 0) {
3868 1
            $result = [];
3869
        } else {
3870 1
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
3871 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
3872
        }
3873
3874 1
        return static::create(
3875 1
            $result,
3876 1
            $this->iteratorClass,
3877 1
            false
3878
        );
3879
    }
3880
3881
    /**
3882
     * Stripe all empty items.
3883
     *
3884
     * @return static
3885
     *                <p>(Immutable)</p>
3886
     */
3887 1
    public function stripEmpty(): self
3888
    {
3889 1
        return $this->filter(
3890
            static function ($item) {
3891 1
                if ($item === null) {
3892 1
                    return false;
3893
                }
3894
3895 1
                return (bool) \trim((string) $item);
3896 1
            }
3897
        );
3898
    }
3899
3900
    /**
3901
     * Swap two values between positions by key.
3902
     *
3903
     * @param int|string $swapA <p>a key in the array</p>
3904
     * @param int|string $swapB <p>a key in the array</p>
3905
     *
3906
     * @return static
3907
     *                <p>(Immutable)</p>
3908
     */
3909 1
    public function swap($swapA, $swapB): self
3910
    {
3911 1
        $array = $this->getArray();
3912
3913 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3914
3915 1
        return static::create(
3916 1
            $array,
3917 1
            $this->iteratorClass,
3918 1
            false
3919
        );
3920
    }
3921
3922
    /**
3923
     * alias: for "Arrayy->getArray()"
3924
     *
3925
     * @see Arrayy::getArray()
3926
     */
3927 198
    public function toArray()
3928
    {
3929 198
        return $this->getArray();
3930
    }
3931
3932
    /**
3933
     * Convert the current array to JSON.
3934
     *
3935
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3936
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3937
     *
3938
     * @return string
3939
     */
3940 6
    public function toJson(int $options = 0, int $depth = 512): string
3941
    {
3942
        /** @noinspection PhpComposerExtensionStubsInspection */
3943 6
        $return = \json_encode($this->getArray(), $options, $depth);
3944 6
        if ($return === false) {
3945
            return '';
3946
        }
3947
3948 6
        return $return;
3949
    }
3950
3951
    /**
3952
     * Implodes array to a string with specified separator.
3953
     *
3954
     * @param string $separator [optional] <p>The element's separator.</p>
3955
     *
3956
     * @return string
3957
     *                <p>The string representation of array, separated by ",".</p>
3958
     */
3959 19
    public function toString(string $separator = ','): string
3960
    {
3961 19
        return $this->implode($separator);
3962
    }
3963
3964
    /**
3965
     * Return a duplicate free copy of the current array.
3966
     *
3967
     * @return static
3968
     *                <p>(Mutable)</p>
3969
     */
3970 12
    public function unique(): self
3971
    {
3972
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3973
3974 12
        $this->array = $this->reduce(
3975
            static function ($resultArray, $value) {
3976 11
                if (!\in_array($value, $resultArray, true)) {
3977 11
                    $resultArray[] = $value;
3978
                }
3979
3980 11
                return $resultArray;
3981 12
            },
3982 12
            []
3983 12
        )->getArray();
3984 12
        $this->generator = null;
3985
3986 12
        return $this;
3987
    }
3988
3989
    /**
3990
     * Return a duplicate free copy of the current array. (with the old keys)
3991
     *
3992
     * @return static
3993
     *                <p>(Mutable)</p>
3994
     */
3995 11
    public function uniqueKeepIndex(): self
3996
    {
3997
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3998
3999
        // init
4000 11
        $array = $this->getArray();
4001
4002 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...
4003 11
            \array_keys($array),
4004
            static function ($resultArray, $key) use ($array) {
4005 10
                if (!\in_array($array[$key], $resultArray, true)) {
4006 10
                    $resultArray[$key] = $array[$key];
4007
                }
4008
4009 10
                return $resultArray;
4010 11
            },
4011 11
            []
4012
        );
4013 11
        $this->generator = null;
4014
4015 11
        if ($this->array === null) {
4016
            $this->array = [];
4017
        } else {
4018 11
            $this->array = (array) $this->array;
4019
        }
4020
4021 11
        return $this;
4022
    }
4023
4024
    /**
4025
     * @param bool $unique
4026
     *
4027
     * @return static
4028
     *                <p>(Immutable)</p>
4029
     */
4030 14
    public function reduce_dimension(bool $unique = true): self
4031
    {
4032
        // init
4033 14
        $result = [[]];
4034
4035 14
        foreach ($this->array as $val) {
4036 12
            if (\is_array($val)) {
4037 5
                $result[] = (new self($val))->reduce_dimension($unique)->getArray();
4038
            } else {
4039 12
                $result[] = [$val];
4040
            }
4041
        }
4042 14
        $result = array_merge(...$result);
4043
4044 14
        $resultArrayy = new self($result);
4045
4046 14
        return $unique ? $resultArrayy->unique() : $resultArrayy;
4047
    }
4048
4049
    /**
4050
     * alias: for "Arrayy->unique()"
4051
     *
4052
     * @return static
4053
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
4054
     *
4055
     * @see Arrayy::unique()
4056
     */
4057 10
    public function uniqueNewIndex(): self
4058
    {
4059 10
        return $this->unique();
4060
    }
4061
4062
    /**
4063
     * Prepends one or more values to the beginning of array at once.
4064
     *
4065
     * @return static
4066
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
4067
     */
4068 4 View Code Duplication
    public function unshift(/* variadic arguments allowed */): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4069
    {
4070 4
        $this->generatorToArray();
4071
4072 4
        if (\func_num_args()) {
4073 4
            $args = \func_get_args();
4074 4
            \array_unshift(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_unshift() as the parameter $array expects a reference.
Loading history...
4075
        }
4076
4077 4
        return $this;
4078
    }
4079
4080
    /**
4081
     * Get all values from a array.
4082
     *
4083
     * @return static
4084
     *                <p>(Immutable)</p>
4085
     */
4086 2
    public function values(): self
4087
    {
4088 2
        return static::create(
4089 2
            \array_values($this->getArray()),
4090 2
            $this->iteratorClass,
4091 2
            false
4092
        );
4093
    }
4094
4095
    /**
4096
     * Apply the given function to every element in the array, discarding the results.
4097
     *
4098
     * @param callable $callable
4099
     * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
4100
     *
4101
     * @return static
4102
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
4103
     */
4104 37
    public function walk($callable, bool $recursive = false): self
4105
    {
4106 37
        $this->generatorToArray();
4107
4108 37
        if ($recursive === true) {
4109 32
            \array_walk_recursive($this->array, $callable);
4110
        } else {
4111 18
            \array_walk($this->array, $callable);
4112
        }
4113
4114 37
        return $this;
4115
    }
4116
4117
    /**
4118
     * Convert an array into a object.
4119
     *
4120
     * @param array $array PHP array
4121
     *
4122
     * @return \stdClass
4123
     */
4124 4
    protected static function arrayToObject(array $array = []): \stdClass
4125
    {
4126
        // init
4127 4
        $object = new \stdClass();
4128
4129 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
4130 1
            return $object;
4131
        }
4132
4133 3
        foreach ($array as $name => $value) {
4134 3
            if (\is_array($value)) {
4135 1
                $object->{$name} = self::arrayToObject($value);
4136
            } else {
4137 3
                $object->{$name} = $value;
4138
            }
4139
        }
4140
4141 3
        return $object;
4142
    }
4143
4144
    /**
4145
     * @param array|\Generator|null $input        <p>
4146
     *                                            An array containing keys to return.
4147
     *                                            </p>
4148
     * @param mixed                 $search_value [optional] <p>
4149
     *                                            If specified, then only keys containing these values are returned.
4150
     *                                            </p>
4151
     * @param bool                  $strict       [optional] <p>
4152
     *                                            Determines if strict comparison (===) should be used during the
4153
     *                                            search.
4154
     *                                            </p>
4155
     *
4156
     * @return array
4157
     *               <p>an array of all the keys in input</p>
4158
     */
4159 10
    protected function array_keys_recursive(
4160
        $input = null,
4161
        $search_value = null,
4162
        bool $strict = true
4163
    ): array {
4164
        // init
4165 10
        $keys = [];
4166 10
        $keysTmp = [[]]; // the inner empty array covers cases when no loops were made
4167
4168 10
        if ($input === null) {
4169
            $input = $this->getGenerator();
4170
        }
4171
4172 10
        foreach ($input as $key => $value) {
4173
            if (
4174 10
                $search_value === null
4175
                ||
4176
                (
4177
                    \is_array($search_value) === true
4178
                    &&
4179 10
                    \in_array($key, $search_value, $strict)
4180
                )
4181
            ) {
4182 10
                $keys[] = $key;
4183
            }
4184
4185
            // check if recursive is needed
4186 10
            if (\is_array($value) === true) {
4187 4
                $keysTmp[] = $this->array_keys_recursive($value);
4188
            }
4189
        }
4190
4191 10
        return \array_merge($keys, ...$keysTmp);
4192
    }
4193
4194
    /**
4195
     * @param mixed      $path
4196
     * @param callable   $callable
4197
     * @param array|null $currentOffset
4198
     */
4199 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
4200
    {
4201 4
        $this->generatorToArray();
4202
4203 4
        if ($currentOffset === null) {
4204 4
            $currentOffset = &$this->array;
4205
        }
4206
4207 4
        $explodedPath = \explode($this->pathSeparator, $path);
4208 4
        if ($explodedPath === false) {
4209
            return;
4210
        }
4211
4212 4
        $nextPath = \array_shift($explodedPath);
4213
4214 4
        if (!isset($currentOffset[$nextPath])) {
4215
            return;
4216
        }
4217
4218 4
        if (!empty($explodedPath)) {
4219 1
            $this->callAtPath(
4220 1
                \implode($this->pathSeparator, $explodedPath),
4221 1
                $callable,
4222 1
                $currentOffset[$nextPath]
4223
            );
4224
        } else {
4225 4
            $callable($currentOffset[$nextPath]);
4226
        }
4227 4
    }
4228
4229
    /**
4230
     * create a fallback for array
4231
     *
4232
     * 1. use the current array, if it's a array
4233
     * 2. fallback to empty array, if there is nothing
4234
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
4235
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
4236
     * 5. call "__toArray()" on object, if the method exists
4237
     * 6. cast a string or object with "__toString()" into an array
4238
     * 7. throw a "InvalidArgumentException"-Exception
4239
     *
4240
     * @param mixed $data
4241
     *
4242
     * @throws \InvalidArgumentException
4243
     *
4244
     * @return array
4245
     */
4246 936
    protected function fallbackForArray(&$data): array
4247
    {
4248 936
        if (\is_array($data)) {
4249 933
            return $data;
4250
        }
4251
4252 17
        if (!$data) {
4253 6
            return [];
4254
        }
4255
4256 16
        $isObject = \is_object($data);
4257
4258 16
        if ($isObject && $data instanceof self) {
4259 1
            return $data->getArray();
4260
        }
4261
4262 15
        if ($isObject && $data instanceof \ArrayObject) {
4263
            return $data->getArrayCopy();
4264
        }
4265
4266 15
        if ($isObject && $data instanceof \Generator) {
4267
            return static::createFromGeneratorImmutable($data)->getArray();
4268
        }
4269
4270 15
        if ($isObject && $data instanceof \Traversable) {
4271
            return static::createFromObject($data)->getArray();
4272
        }
4273
4274 15
        if (\is_callable($data)) {
4275 6
            $this->generator = new ArrayyRewindableGenerator($data);
4276
4277 6
            return [];
4278
        }
4279
4280 9
        if ($isObject && \method_exists($data, '__toArray')) {
4281
            return (array) $data->__toArray();
4282
        }
4283
4284
        if (
4285 9
            \is_string($data)
4286
            ||
4287 9
            ($isObject && \method_exists($data, '__toString'))
4288
        ) {
4289 7
            return [(string) $data];
4290
        }
4291
4292 2
        throw new \InvalidArgumentException(
4293 2
            'Passed value should be a array'
4294
        );
4295
    }
4296
4297
    /**
4298
     * Get correct PHP constant for direction.
4299
     *
4300
     * @param int|string $direction
4301
     *
4302
     * @return int
4303
     */
4304 39
    protected function getDirection($direction): int
4305
    {
4306 39
        if (\is_string($direction)) {
4307 10
            $direction = \strtolower($direction);
4308
4309 10
            if ($direction === 'desc') {
4310 2
                $direction = \SORT_DESC;
4311
            } else {
4312 8
                $direction = \SORT_ASC;
4313
            }
4314
        }
4315
4316
        if (
4317 39
            $direction !== \SORT_DESC
4318
            &&
4319 39
            $direction !== \SORT_ASC
4320
        ) {
4321
            $direction = \SORT_ASC;
4322
        }
4323
4324 39
        return $direction;
4325
    }
4326
4327
    /**
4328
     * @param mixed               $glue
4329
     * @param array|static|string $pieces
4330
     * @param bool                $useKeys
4331
     *
4332
     * @return string
4333
     */
4334 35
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
4335
    {
4336 35
        if ($pieces instanceof self) {
4337 1
            $pieces = $pieces->getArray();
4338
        }
4339
4340 35
        if (\is_array($pieces)) {
4341 35
            $pieces_count = \count($pieces, \COUNT_NORMAL);
4342 35
            $pieces_count_not_zero = $pieces_count > 0;
4343
4344 35
            return \implode(
4345 35
                $glue,
4346 35
                \array_map(
4347 35
                    [$this, 'implode_recursive'],
4348 35
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
4349 35
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
4350
                )
4351
            );
4352
        }
4353
4354 35
        return (string) $pieces;
4355
    }
4356
4357
    /**
4358
     * @param mixed                 $needle   <p>
4359
     *                                        The searched value.
4360
     *                                        </p>
4361
     *                                        <p>
4362
     *                                        If needle is a string, the comparison is done
4363
     *                                        in a case-sensitive manner.
4364
     *                                        </p>
4365
     * @param array|\Generator|null $haystack <p>
4366
     *                                        The array.
4367
     *                                        </p>
4368
     * @param bool                  $strict   [optional] <p>
4369
     *                                        If the third parameter strict is set to true
4370
     *                                        then the in_array function will also check the
4371
     *                                        types of the
4372
     *                                        needle in the haystack.
4373
     *                                        </p>
4374
     *
4375
     * @return bool
4376
     *              <p>true if needle is found in the array, false otherwise</p>
4377
     */
4378 44
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
4379
    {
4380 44
        if ($haystack === null) {
4381
            $haystack = $this->getGenerator();
4382
        }
4383
4384 44
        foreach ($haystack as $item) {
4385 36
            if (\is_array($item) === true) {
4386 8
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
4387
            } else {
4388 36
                $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
4389
            }
4390
4391 36
            if ($returnTmp === true) {
4392 26
                return true;
4393
            }
4394
        }
4395
4396 18
        return false;
4397
    }
4398
4399
    /**
4400
     * @param mixed $value
4401
     */
4402
    protected function internalGetArray(&$value)
4403
    {
4404
        if ($value instanceof self) {
4405
            $valueTmp = $value->getArray();
4406
            if (\count($valueTmp, \COUNT_NORMAL) === 0) {
4407
                $value = [];
4408
            } else {
4409
                /** @noinspection PhpUnusedLocalVariableInspection */
4410
                $value = &$valueTmp;
4411
            }
4412
        }
4413
4414
        /** @noinspection PhpComposerExtensionStubsInspection */
4415
        /** @noinspection NotOptimalIfConditionsInspection */
4416
        if (
4417
            \class_exists('JsonSerializable')
4418
            &&
4419
            $value instanceof \JsonSerializable
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

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

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

2. Missing use statement

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

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

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

Loading history...
4420
        ) {
4421
4422
            /** @noinspection PhpUnusedLocalVariableInspection */
4423
            $value = &$value->jsonSerialize();
4424
        }
4425
    }
4426
4427
    /**
4428
     * Internal mechanics of remove method.
4429
     *
4430
     * @param mixed $key
4431
     *
4432
     * @return bool
4433
     */
4434 18
    protected function internalRemove($key): bool
4435
    {
4436 18
        $this->generatorToArray();
4437
4438
        if (
4439 18
            $this->pathSeparator
4440
            &&
4441 18
            \is_string($key)
4442
            &&
4443 18
            \strpos($key, $this->pathSeparator) !== false
4444
        ) {
4445
            $path = \explode($this->pathSeparator, (string) $key);
4446
4447
            if ($path !== false) {
4448
                // crawl though the keys
4449
                while (\count($path, \COUNT_NORMAL) > 1) {
4450
                    $key = \array_shift($path);
4451
4452
                    if (!$this->has($key)) {
4453
                        return false;
4454
                    }
4455
4456
                    $this->array = &$this->array[$key];
4457
                }
4458
4459
                $key = \array_shift($path);
4460
            }
4461
        }
4462
4463 18
        unset($this->array[$key]);
4464
4465 18
        return true;
4466
    }
4467
4468
    /**
4469
     * Internal mechanic of set method.
4470
     *
4471
     * @param int|string|null $key
4472
     * @param mixed           $value
4473
     * @param bool            $checkProperties
4474
     *
4475
     * @return bool
4476
     */
4477 819
    protected function internalSet($key, $value, $checkProperties = true): bool
4478
    {
4479
        if (
4480 819
            $checkProperties === true
4481
            &&
4482 819
            $this->properties !== []
4483
        ) {
4484 13
            if (isset($this->properties[$key]) === false) {
4485
                throw new \InvalidArgumentException('The key ' . $key . ' does not exists as @property in the class (' . \get_class($this) . ').');
4486
            }
4487
4488 13
            $this->properties[$key]->checkType($value);
4489
        }
4490
4491 818
        if ($key === null) {
4492
            return false;
4493
        }
4494
4495 818
        $this->generatorToArray();
4496
4497 818
        $array = &$this->array;
4498
4499
        if (
4500 818
            $this->pathSeparator
4501
            &&
4502 818
            \is_string($key)
4503
            &&
4504 818
            \strpos($key, $this->pathSeparator) !== false
4505
        ) {
4506 3
            $path = \explode($this->pathSeparator, (string) $key);
4507
4508 3
            if ($path !== false) {
4509
                // crawl through the keys
4510 3
                while (\count($path, \COUNT_NORMAL) > 1) {
4511 3
                    $key = \array_shift($path);
4512
4513 3
                    $array = &$array[$key];
4514
                }
4515
4516 3
                $key = \array_shift($path);
4517
            }
4518
        }
4519
4520 818
        $array[$key] = $value;
4521
4522 818
        return true;
4523
    }
4524
4525
    /**
4526
     * Convert a object into an array.
4527
     *
4528
     * @param object $object
4529
     *
4530
     * @return mixed
4531
     */
4532 5
    protected static function objectToArray($object)
4533
    {
4534 5
        if (!\is_object($object)) {
4535 4
            return $object;
4536
        }
4537
4538 5
        if (\is_object($object)) {
4539 5
            $object = \get_object_vars($object);
4540
        }
4541
4542 5
        return \array_map(['static', 'objectToArray'], $object);
4543
    }
4544
4545
    /**
4546
     * sorting keys
4547
     *
4548
     * @param array      $elements
4549
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4550
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4551
     *                              <strong>SORT_NATURAL</strong></p>
4552
     *
4553
     * @return static
4554
     *                <p>(Mutable) Return this Arrayy object.</p>
4555
     */
4556 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4557
    {
4558 18
        $direction = $this->getDirection($direction);
4559
4560 18
        switch ($direction) {
4561 18
            case 'desc':
4562
            case \SORT_DESC:
4563 6
                \krsort($elements, $strategy);
4564
4565 6
                break;
4566 13
            case 'asc':
4567 13
            case \SORT_ASC:
4568
            default:
4569 13
                \ksort($elements, $strategy);
4570
        }
4571
4572 18
        return $this;
4573
    }
4574
4575
    /**
4576
     * @param array      $elements  <p>Warning: used as reference</p>
4577
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4578
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4579
     *                              <strong>SORT_NATURAL</strong></p>
4580
     * @param bool       $keepKeys
4581
     *
4582
     * @return static
4583
     *                <p>(Mutable) Return this Arrayy object.</p>
4584
     */
4585 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4586
    {
4587 20
        $direction = $this->getDirection($direction);
4588
4589 20
        if (!$strategy) {
4590 20
            $strategy = \SORT_REGULAR;
4591
        }
4592
4593 20
        switch ($direction) {
4594 20
            case 'desc':
4595
            case \SORT_DESC:
4596 9
                if ($keepKeys) {
4597 5
                    \arsort($elements, $strategy);
4598
                } else {
4599 4
                    \rsort($elements, $strategy);
4600
                }
4601
4602 9
                break;
4603 11
            case 'asc':
4604 11
            case \SORT_ASC:
4605
            default:
4606 11
                if ($keepKeys) {
4607 4
                    \asort($elements, $strategy);
4608
                } else {
4609 7
                    \sort($elements, $strategy);
4610
                }
4611
        }
4612
4613 20
        return $this;
4614
    }
4615
4616
    /**
4617
     * @return bool
4618
     */
4619 858
    private function generatorToArray(): bool
4620
    {
4621 858
        if ($this->generator) {
4622 1
            $this->array = $this->getArray();
4623 1
            $this->generator = null;
4624
4625 1
            return true;
4626
        }
4627
4628 858
        return false;
4629
    }
4630
4631
    /**
4632
     * @return Property[]
4633
     */
4634 15
    private function getPropertiesFromPhpDoc(): array
4635
    {
4636 15
        static $PROPERTY_CACHE = [];
4637 15
        $cacheKey = 'Class::' . static::class;
4638
4639 15
        if (isset($PROPERTY_CACHE[$cacheKey])) {
4640 14
            return $PROPERTY_CACHE[$cacheKey];
4641
        }
4642
4643
        // init
4644 2
        $properties = [];
4645
4646 2
        $reflector = new \ReflectionClass($this);
4647 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
4648 2
        $docComment = $reflector->getDocComment();
4649 2
        if ($docComment) {
4650 2
            $docblock = $factory->create($docComment);
4651 2
            foreach ($docblock->getTagsByName('property') as $tag) {
4652
                /* @var $tag \phpDocumentor\Reflection\DocBlock\Tags\Property */
4653 2
                $properties[$tag->getVariableName()] = Property::fromPhpDocumentorProperty($tag);
4654
            }
4655
        }
4656
4657 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
4658
    }
4659
}
4660