Completed
Push — master ( d91a6c...c4c656 )
by Lars
01:35
created

Arrayy::extractValue()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 7.3471

Importance

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

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
434
435 122
        $tmpReturn = $this->keyExists($offset);
436
437
        if (
438 122
            $tmpReturn === true
439
            ||
440
            (
441 89
                $tmpReturn === false
442
                &&
443 122
                \strpos((string) $offset, $this->pathSeparator) === false
444
            )
445
        ) {
446 120
            return $tmpReturn;
447
        }
448
449 3
        $offsetExists = false;
450
451
        if (
452 3
            $this->pathSeparator
453
            &&
454 3
            (string) $offset === $offset
455
            &&
456 3
            \strpos($offset, $this->pathSeparator) !== false
457
        ) {
458 3
            $explodedPath = \explode($this->pathSeparator, (string) $offset);
459 3
            if ($explodedPath !== false) {
460 3
                $lastOffset = \array_pop($explodedPath);
461 3
                if ($lastOffset !== null) {
462 3
                    $containerPath = \implode($this->pathSeparator, $explodedPath);
463
464 3
                    $this->callAtPath(
465 3
                        $containerPath,
466
                        static function ($container) use ($lastOffset, &$offsetExists) {
467 3
                            $offsetExists = \array_key_exists($lastOffset, $container);
468 3
                        }
469
                    );
470
                }
471
            }
472
        }
473
474 3
        return $offsetExists;
475
    }
476
477
    /**
478
     * Returns the value at specified offset.
479
     *
480
     * @param int|string $offset
481
     *
482
     * @return mixed
483
     *               <p>Will return null if the offset did not exists.</p>
484
     */
485 98
    public function offsetGet($offset)
486
    {
487 98
        return $this->offsetExists($offset) ? $this->get($offset) : null;
488
    }
489
490
    /**
491
     * Assigns a value to the specified offset + check the type.
492
     *
493
     * @param int|string|null $offset
494
     * @param mixed           $value
495
     *
496
     * @return void
497
     */
498 21
    public function offsetSet($offset, $value)
499
    {
500 21
        $this->generatorToArray();
501
502 21
        if ($offset === null) {
503 5
            if ($this->properties !== []) {
504 1
                $this->checkType(null, $value);
505
            }
506
507 4
            $this->array[] = $value;
508
        } else {
509 16
            $this->internalSet(
510 16
                $offset,
511 16
                $value,
512 16
                true
513
            );
514
        }
515 20
    }
516
517
    /**
518
     * Unset an offset.
519
     *
520
     * @param int|string $offset
521
     *
522
     * @return void
523
     */
524 12
    public function offsetUnset($offset)
525
    {
526 12
        $this->generatorToArray();
527
528 12
        if ($this->array === []) {
529 3
            return;
530
        }
531
532 10
        if ($this->keyExists($offset)) {
533 7
            unset($this->array[$offset]);
534
535 7
            return;
536
        }
537
538
        if (
539 5
            $this->pathSeparator
540
            &&
541 5
            (string) $offset === $offset
542
            &&
543 5
            \strpos($offset, $this->pathSeparator) !== false
544
        ) {
545 2
            $path = \explode($this->pathSeparator, (string) $offset);
546
547 2
            if ($path !== false) {
548 2
                $pathToUnset = \array_pop($path);
549
550 2
                $this->callAtPath(
551 2
                    \implode($this->pathSeparator, $path),
552
                    static function (&$offset) use ($pathToUnset) {
553 2
                        unset($offset[$pathToUnset]);
554 2
                    }
555
                );
556
            }
557
        }
558
559 5
        unset($this->array[$offset]);
560 5
    }
561
562
    /**
563
     * Serialize the current "Arrayy"-object.
564
     *
565
     * @return string
566
     */
567 2
    public function serialize(): string
568
    {
569 2
        $this->generatorToArray();
570
571 2
        if (\PHP_VERSION_ID < 70400) {
572 2
            return parent::serialize();
573
        }
574
575
        return \serialize($this);
576
    }
577
578
    /**
579
     * Sets the iterator classname for the current "Arrayy"-object.
580
     *
581
     * @param string $iteratorClass
582
     *
583
     * @throws \InvalidArgumentException
584
     *
585
     * @return void
586
     *
587
     * @psalm-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
588
     */
589 1044
    public function setIteratorClass($iteratorClass)
590
    {
591 1044
        if (\class_exists($iteratorClass)) {
592 1044
            $this->iteratorClass = $iteratorClass;
593
594 1044
            return;
595
        }
596
597
        if (\strpos($iteratorClass, '\\') === 0) {
598
            $iteratorClass = '\\' . $iteratorClass;
599
            if (\class_exists($iteratorClass)) {
600
                $this->iteratorClass = $iteratorClass;
601
602
                return;
603
            }
604
        }
605
606
        throw new \InvalidArgumentException('The iterator class does not exist: ' . $iteratorClass);
607
    }
608
609
    /**
610
     * Sort the entries with a user-defined comparison function and maintain key association.
611
     *
612
     * @param callable $function
613
     *
614
     * @throws \InvalidArgumentException
615
     *
616
     * @return static
617
     *                <p>(Mutable) Return this Arrayy object.</p>
618
     */
619 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...
620
    {
621
        if (!\is_callable($function)) {
622
            throw new \InvalidArgumentException('Passed function must be callable');
623
        }
624
625
        $this->generatorToArray();
626
627
        \uasort($this->array, $function);
628
629
        return $this;
630
    }
631
632
    /**
633
     * Sort the entries by keys using a user-defined comparison function.
634
     *
635
     * @param callable $function
636
     *
637
     * @throws \InvalidArgumentException
638
     *
639
     * @return static
640
     *                <p>(Mutable) Return this Arrayy object.</p>
641
     */
642 5
    public function uksort($function): self
643
    {
644 5
        return $this->customSortKeys($function);
645
    }
646
647
    /**
648
     * Unserialize an string and return the instance of the "Arrayy"-class.
649
     *
650
     * @param string $string
651
     *
652
     * @return static
653
     */
654 2
    public function unserialize($string): self
655
    {
656 2
        if (\PHP_VERSION_ID < 70400) {
657 2
            parent::unserialize($string);
658
659 2
            return $this;
660
        }
661
662
        return \unserialize($string, ['allowed_classes' => [__CLASS__, TypeCheckPhpDoc::class]]);
663
    }
664
665
    /**
666
     * Append a (key) + values to the current array.
667
     *
668
     * @param array $values
669
     * @param mixed $key
670
     *
671
     * @return static
672
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
673
     */
674 1
    public function appendArrayValues(array $values, $key = null)
675
    {
676 1
        $this->generatorToArray();
677
678 1
        if ($key !== null) {
679
            if (
680 1
                isset($this->array[$key])
681
                &&
682 1
                \is_array($this->array[$key]) === true
683
            ) {
684 1
                foreach ($values as $value) {
685 1
                    $this->array[$key][] = $value;
686
                }
687
            } else {
688 1
                foreach ($values as $value) {
689
                    $this->array[$key] = $value;
690
                }
691
            }
692
        } else {
693
            foreach ($values as $value) {
694
                $this->array[] = $value;
695
            }
696
        }
697
698 1
        return $this;
699
    }
700
701
    /**
702
     * Add a suffix to each key.
703
     *
704
     * @param mixed $prefix
705
     *
706
     * @return static
707
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
708
     */
709 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...
710
    {
711
        // init
712 10
        $result = [];
713
714 10
        foreach ($this->getGenerator() as $key => $item) {
715 9
            if ($item instanceof self) {
716
                $result[$prefix . $key] = $item->appendToEachKey($prefix);
717 9
            } elseif (\is_array($item) === true) {
718
                $result[$prefix . $key] = self::create($item, $this->iteratorClass, false)
719
                    ->appendToEachKey($prefix)
720
                    ->toArray();
721
            } else {
722 9
                $result[$prefix . $key] = $item;
723
            }
724
        }
725
726 10
        return self::create($result, $this->iteratorClass, false);
727
    }
728
729
    /**
730
     * Add a prefix to each value.
731
     *
732
     * @param mixed $prefix
733
     *
734
     * @return static
735
     *                <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
736
     */
737 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...
738
    {
739
        // init
740 10
        $result = [];
741
742 10
        foreach ($this->getGenerator() as $key => $item) {
743 9
            if ($item instanceof self) {
744
                $result[$key] = $item->appendToEachValue($prefix);
745 9
            } elseif (\is_array($item) === true) {
746
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
747 9
            } elseif (\is_object($item) === true) {
748 1
                $result[$key] = $item;
749
            } else {
750 8
                $result[$key] = $prefix . $item;
751
            }
752
        }
753
754 10
        return self::create($result, $this->iteratorClass, false);
755
    }
756
757
    /**
758
     * Sort an array in reverse order and maintain index association.
759
     *
760
     * @return static
761
     *                <p>(Mutable) Return this Arrayy object.</p>
762
     */
763 10
    public function arsort(): self
764
    {
765 10
        $this->generatorToArray();
766
767 10
        \arsort($this->array);
768
769 10
        return $this;
770
    }
771
772
    /**
773
     * Iterate over the current array and execute a callback for each loop.
774
     *
775
     * @param \Closure $closure
776
     *
777
     * @return static
778
     *                <p>(Immutable)</p>
779
     */
780 2
    public function at(\Closure $closure): self
781
    {
782 2
        $arrayy = clone $this;
783
784 2
        foreach ($arrayy->getGenerator() as $key => $value) {
785 2
            $closure($value, $key);
786
        }
787
788 2
        return static::create(
789 2
            $arrayy->toArray(),
790 2
            $this->iteratorClass,
791 2
            false
792
        );
793
    }
794
795
    /**
796
     * Returns the average value of the current array.
797
     *
798
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
799
     *
800
     * @return float|int
801
     *                   <p>The average value.</p>
802
     */
803 10
    public function average($decimals = 0)
804
    {
805 10
        $count = \count($this->getArray(), \COUNT_NORMAL);
806
807 10
        if (!$count) {
808 2
            return 0;
809
        }
810
811 8
        if ((int) $decimals !== $decimals) {
812 3
            $decimals = 0;
813
        }
814
815 8
        return \round(\array_sum($this->getArray()) / $count, $decimals);
816
    }
817
818
    /**
819
     * Changes all keys in an array.
820
     *
821
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
822
     *                  or <strong>CASE_LOWER</strong> (default)</p>
823
     *
824
     * @return static
825
     *                <p>(Immutable)</p>
826
     */
827 1
    public function changeKeyCase(int $case = \CASE_LOWER): self
828
    {
829
        if (
830 1
            $case !== \CASE_LOWER
831
            &&
832 1
            $case !== \CASE_UPPER
833
        ) {
834
            $case = \CASE_LOWER;
835
        }
836
837 1
        $return = [];
838 1
        foreach ($this->getGenerator() as $key => $value) {
839 1
            if ($case === \CASE_LOWER) {
840 1
                $key = \mb_strtolower((string) $key);
841
            } else {
842 1
                $key = \mb_strtoupper((string) $key);
843
            }
844
845 1
            $return[$key] = $value;
846
        }
847
848 1
        return static::create(
849 1
            $return,
850 1
            $this->iteratorClass,
851 1
            false
852
        );
853
    }
854
855
    /**
856
     * Change the path separator of the array wrapper.
857
     *
858
     * By default, the separator is: "."
859
     *
860
     * @param string $separator <p>Separator to set.</p>
861
     *
862
     * @return static
863
     *                <p>Mutable</p>
864
     */
865 11
    public function changeSeparator($separator): self
866
    {
867 11
        $this->pathSeparator = $separator;
868
869 11
        return $this;
870
    }
871
872
    /**
873
     * Create a chunked version of the current array.
874
     *
875
     * @param int  $size         <p>Size of each chunk.</p>
876
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
877
     *
878
     * @return static
879
     *                <p>(Immutable) A new array of chunks from the original array.</p>
880
     */
881 5
    public function chunk($size, $preserveKeys = false): self
882
    {
883 5
        return static::create(
884 5
            \array_chunk($this->getArray(), $size, $preserveKeys),
885 5
            $this->iteratorClass,
886 5
            false
887
        );
888
    }
889
890
    /**
891
     * Clean all falsy values from the current array.
892
     *
893
     * @return static
894
     *                <p>(Immutable)</p>
895
     */
896 8
    public function clean(): self
897
    {
898 8
        return $this->filter(
899
            static function ($value) {
900 7
                return (bool) $value;
901 8
            }
902
        );
903
    }
904
905
    /**
906
     * WARNING!!! -> Clear the current array.
907
     *
908
     * @return static
909
     *                <p>(Mutable) Return this Arrayy object, with an empty array.</p>
910
     */
911 5
    public function clear(): self
912
    {
913 5
        $this->array = [];
914 5
        $this->generator = null;
915
916 5
        return $this;
917
    }
918
919
    /**
920
     * Check if an item is in the current array.
921
     *
922
     * @param float|int|string $value
923
     * @param bool             $recursive
924
     * @param bool             $strict
925
     *
926
     * @return bool
927
     */
928 23
    public function contains($value, bool $recursive = false, bool $strict = true): bool
929
    {
930 23
        if ($recursive === true) {
931 18
            return $this->in_array_recursive($value, $this->getArray(), $strict);
932
        }
933
934 14
        foreach ($this->getGenerator() as $valueFromArray) {
935 11
            if ($strict) {
936 11
                if ($value === $valueFromArray) {
937 11
                    return true;
938
                }
939
            } else {
940
                /** @noinspection NestedPositiveIfStatementsInspection */
941
                if ($value == $valueFromArray) {
942
                    return true;
943
                }
944
            }
945
        }
946
947 7
        return false;
948
    }
949
950
    /**
951
     * Check if an (case-insensitive) string is in the current array.
952
     *
953
     * @param string $value
954
     * @param bool   $recursive
955
     *
956
     * @return bool
957
     */
958 26
    public function containsCaseInsensitive($value, $recursive = false): bool
959
    {
960 26
        if ($recursive === true) {
961 26
            foreach ($this->getGenerator() as $key => $valueTmp) {
962 22
                if (\is_array($valueTmp) === true) {
963 5
                    $return = (new self($valueTmp))->containsCaseInsensitive($value, $recursive);
964 5
                    if ($return === true) {
965 5
                        return $return;
966
                    }
967 22
                } elseif (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
968 16
                    return true;
969
                }
970
            }
971
972 10
            return false;
973
        }
974
975 13
        foreach ($this->getGenerator() as $key => $valueTmp) {
976 11
            if (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
977 8
                return true;
978
            }
979
        }
980
981 5
        return false;
982
    }
983
984
    /**
985
     * Check if the given key/index exists in the array.
986
     *
987
     * @param int|string $key <p>key/index to search for</p>
988
     *
989
     * @return bool
990
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
991
     */
992 4
    public function containsKey($key): bool
993
    {
994 4
        return $this->offsetExists($key);
995
    }
996
997
    /**
998
     * Check if all given needles are present in the array as key/index.
999
     *
1000
     * @param array $needles   <p>The keys you are searching for.</p>
1001
     * @param bool  $recursive
1002
     *
1003
     * @return bool
1004
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1005
     */
1006 2
    public function containsKeys(array $needles, $recursive = false): bool
1007
    {
1008 2
        if ($recursive === true) {
1009
            return
1010 2
                \count(
1011 2
                    \array_intersect(
1012 2
                        $needles,
1013 2
                        $this->keys(true)->getArray()
1014
                    ),
1015 2
                    \COUNT_RECURSIVE
1016
                )
1017
                ===
1018 2
                \count(
1019 2
                    $needles,
1020 2
                    \COUNT_RECURSIVE
1021
                );
1022
        }
1023
1024 1
        return \count(
1025 1
            \array_intersect($needles, $this->keys()->getArray()),
1026 1
            \COUNT_NORMAL
1027
        )
1028
               ===
1029 1
               \count(
1030 1
                   $needles,
1031 1
                   \COUNT_NORMAL
1032
               );
1033
    }
1034
1035
    /**
1036
     * Check if all given needles are present in the array as key/index.
1037
     *
1038
     * @param array $needles <p>The keys you are searching for.</p>
1039
     *
1040
     * @return bool
1041
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1042
     */
1043 1
    public function containsKeysRecursive(array $needles): bool
1044
    {
1045 1
        return $this->containsKeys($needles, true);
1046
    }
1047
1048
    /**
1049
     * alias: for "Arrayy->contains()"
1050
     *
1051
     * @param float|int|string $value
1052
     *
1053
     * @return bool
1054
     *
1055
     * @see Arrayy::contains()
1056
     */
1057 9
    public function containsValue($value): bool
1058
    {
1059 9
        return $this->contains($value);
1060
    }
1061
1062
    /**
1063
     * alias: for "Arrayy->contains($value, true)"
1064
     *
1065
     * @param float|int|string $value
1066
     *
1067
     * @return bool
1068
     *
1069
     * @see Arrayy::contains()
1070
     */
1071 18
    public function containsValueRecursive($value): bool
1072
    {
1073 18
        return $this->contains($value, true);
1074
    }
1075
1076
    /**
1077
     * Check if all given needles are present in the array.
1078
     *
1079
     * @param array $needles
1080
     *
1081
     * @return bool
1082
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
1083
     */
1084 1
    public function containsValues(array $needles): bool
1085
    {
1086 1
        return \count(\array_intersect($needles, $this->getArray()), \COUNT_NORMAL)
1087
               ===
1088 1
               \count($needles, \COUNT_NORMAL);
1089
    }
1090
1091
    /**
1092
     * Counts all the values of an array
1093
     *
1094
     * @see http://php.net/manual/en/function.array-count-values.php
1095
     *
1096
     * @return static
1097
     *                <p>
1098
     *                (Immutable)
1099
     *                An associative Arrayy-object of values from input as
1100
     *                keys and their count as value.
1101
     *                </p>
1102
     */
1103 7
    public function countValues(): self
1104
    {
1105 7
        return self::create(\array_count_values($this->getArray()), $this->iteratorClass);
1106
    }
1107
1108
    /**
1109
     * Creates an Arrayy object.
1110
     *
1111
     * @param mixed  $data
1112
     * @param string $iteratorClass
1113
     * @param bool   $checkPropertiesInConstructor
1114
     *
1115
     * @return static
1116
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1117
     *
1118
     * @psalm-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
1119
     */
1120 660
    public static function create(
1121
        $data = [],
1122
        string $iteratorClass = ArrayyIterator::class,
1123
        bool $checkPropertiesInConstructor = true
1124
    ) {
1125 660
        return new static(
1126 660
            $data,
1127 660
            $iteratorClass,
1128 660
            $checkPropertiesInConstructor
1129
        );
1130
    }
1131
1132
    /**
1133
     * WARNING: Creates an Arrayy object by reference.
1134
     *
1135
     * @param array $array
1136
     *
1137
     * @return static
1138
     *                <p>(Mutable) Return this Arrayy object.</p>
1139
     */
1140 1
    public function createByReference(array &$array = []): self
1141
    {
1142 1
        $array = $this->fallbackForArray($array);
1143
1144 1
        $this->array = &$array;
1145
1146 1
        return $this;
1147
    }
1148
1149
    /**
1150
     * Create an new instance from a callable function which will return an Generator.
1151
     *
1152
     * @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...
1153
     *
1154
     * @return static
1155
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1156
     */
1157 5
    public static function createFromGeneratorFunction(callable $generatorFunction): self
1158
    {
1159 5
        return self::create($generatorFunction);
1160
    }
1161
1162
    /**
1163
     * Create an new instance filled with a copy of values from a "Generator"-object.
1164
     *
1165
     * @param \Generator $generator
1166
     *
1167
     * @return static
1168
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1169
     */
1170 4
    public static function createFromGeneratorImmutable(\Generator $generator): self
1171
    {
1172 4
        return self::create(\iterator_to_array($generator, true));
1173
    }
1174
1175
    /**
1176
     * Create an new Arrayy object via JSON.
1177
     *
1178
     * @param string $json
1179
     *
1180
     * @return static
1181
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1182
     */
1183 5
    public static function createFromJson(string $json): self
1184
    {
1185 5
        return static::create(\json_decode($json, true));
1186
    }
1187
1188
    /**
1189
     * Create an new instance filled with values from an object that is iterable.
1190
     *
1191
     * @param \Traversable $object <p>iterable object</p>
1192
     *
1193
     * @return static
1194
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1195
     */
1196 4
    public static function createFromObject(\Traversable $object): self
1197
    {
1198
        // init
1199 4
        $array = self::create();
1200
1201 4
        if ($object instanceof self) {
1202 4
            $objectArray = $object->getGenerator();
1203
        } else {
1204
            $objectArray = $object;
1205
        }
1206
1207 4
        foreach ($objectArray as $key => $value) {
1208 3
            $array[$key] = $value;
1209
        }
1210
1211 4
        return $array;
1212
    }
1213
1214
    /**
1215
     * Create an new instance filled with values from an object.
1216
     *
1217
     * @param object $object
1218
     *
1219
     * @return static
1220
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1221
     */
1222 5
    public static function createFromObjectVars($object): self
1223
    {
1224 5
        return self::create(self::objectToArray($object));
1225
    }
1226
1227
    /**
1228
     * Create an new Arrayy object via string.
1229
     *
1230
     * @param string      $str       <p>The input string.</p>
1231
     * @param string|null $delimiter <p>The boundary string.</p>
1232
     * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1233
     *                               used.</p>
1234
     *
1235
     * @return static
1236
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1237
     */
1238 10
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
1239
    {
1240 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...
1241 1
            \preg_match_all($regEx, $str, $array);
1242
1243 1
            if (!empty($array)) {
1244 1
                $array = $array[0];
1245
            }
1246
        } else {
1247
            /** @noinspection NestedPositiveIfStatementsInspection */
1248 9
            if ($delimiter !== null) {
1249 7
                $array = \explode($delimiter, $str);
1250
            } else {
1251 2
                $array = [$str];
1252
            }
1253
        }
1254
1255
        // trim all string in the array
1256 10
        \array_walk(
1257 10
            $array,
1258
            static function (&$val) {
1259 10
                if ((string) $val === $val) {
1260 10
                    $val = \trim($val);
1261
                }
1262 10
            }
1263
        );
1264
1265 10
        return static::create($array);
1266
    }
1267
1268
    /**
1269
     * Create an new instance filled with a copy of values from a "Traversable"-object.
1270
     *
1271
     * @param \Traversable $traversable
1272
     *
1273
     * @return static
1274
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1275
     */
1276 1
    public static function createFromTraversableImmutable(\Traversable $traversable): self
1277
    {
1278 1
        return self::create(\iterator_to_array($traversable, true));
1279
    }
1280
1281
    /**
1282
     * Create an new instance containing a range of elements.
1283
     *
1284
     * @param mixed $low  <p>First value of the sequence.</p>
1285
     * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1286
     * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1287
     *
1288
     * @return static
1289
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1290
     */
1291 2
    public static function createWithRange($low, $high, int $step = 1): self
1292
    {
1293 2
        return static::create(\range($low, $high, $step));
1294
    }
1295
1296
    /**
1297
     * Gets the element of the array at the current internal iterator position.
1298
     *
1299
     * @return false|mixed
1300
     */
1301
    public function current()
1302
    {
1303
        return \current($this->array);
1304
    }
1305
1306
    /**
1307
     * Custom sort by index via "uksort".
1308
     *
1309
     * @see http://php.net/manual/en/function.uksort.php
1310
     *
1311
     * @param callable $function
1312
     *
1313
     * @throws \InvalidArgumentException
1314
     *
1315
     * @return static
1316
     *                <p>(Mutable) Return this Arrayy object.</p>
1317
     */
1318 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...
1319
    {
1320 5
        if (\is_callable($function) === false) {
1321
            throw new \InvalidArgumentException('Passed function must be callable');
1322
        }
1323
1324 5
        $this->generatorToArray();
1325
1326 5
        \uksort($this->array, $function);
1327
1328 5
        return $this;
1329
    }
1330
1331
    /**
1332
     * Custom sort by value via "usort".
1333
     *
1334
     * @see http://php.net/manual/en/function.usort.php
1335
     *
1336
     * @param callable $function
1337
     *
1338
     * @throws \InvalidArgumentException
1339
     *
1340
     * @return static
1341
     *                <p>(Mutable) Return this Arrayy object.</p>
1342
     */
1343 6 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...
1344
    {
1345 6
        if (\is_callable($function) === false) {
1346
            throw new \InvalidArgumentException('Passed function must be callable');
1347
        }
1348
1349 6
        $this->generatorToArray();
1350
1351 6
        \usort($this->array, $function);
1352
1353 6
        return $this;
1354
    }
1355
1356
    /**
1357
     * Delete the given key or keys.
1358
     *
1359
     * @param int|int[]|string|string[] $keyOrKeys
1360
     *
1361
     * @return void
1362
     */
1363 4
    public function delete($keyOrKeys)
1364
    {
1365 4
        $keyOrKeys = (array) $keyOrKeys;
1366
1367 4
        foreach ($keyOrKeys as $key) {
1368 4
            $this->offsetUnset($key);
1369
        }
1370 4
    }
1371
1372
    /**
1373
     * Return values that are only in the current array.
1374
     *
1375
     * @param array ...$array
1376
     *
1377
     * @return static
1378
     *                <p>(Immutable)</p>
1379
     */
1380 13
    public function diff(...$array): self
1381
    {
1382 13
        return static::create(
1383 13
            \array_diff($this->getArray(), ...$array),
1384 13
            $this->iteratorClass,
1385 13
            false
1386
        );
1387
    }
1388
1389
    /**
1390
     * Return values that are only in the current array.
1391
     *
1392
     * @param array ...$array
1393
     *
1394
     * @return static
1395
     *                <p>(Immutable)</p>
1396
     */
1397 8
    public function diffKey(...$array): self
1398
    {
1399 8
        return static::create(
1400 8
            \array_diff_key($this->getArray(), ...$array),
1401 8
            $this->iteratorClass,
1402 8
            false
1403
        );
1404
    }
1405
1406
    /**
1407
     * Return values and Keys that are only in the current array.
1408
     *
1409
     * @param array $array
1410
     *
1411
     * @return static
1412
     *                <p>(Immutable)</p>
1413
     */
1414 8
    public function diffKeyAndValue(array $array = []): self
1415
    {
1416 8
        return static::create(
1417 8
            \array_diff_assoc($this->getArray(), $array),
1418 8
            $this->iteratorClass,
1419 8
            false
1420
        );
1421
    }
1422
1423
    /**
1424
     * Return values that are only in the current multi-dimensional array.
1425
     *
1426
     * @param array      $array
1427
     * @param array|null $helperVariableForRecursion <p>(only for internal usage)</p>
1428
     *
1429
     * @return static
1430
     *                <p>(Immutable)</p>
1431
     */
1432 1
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
1433
    {
1434
        // init
1435 1
        $result = [];
1436
1437
        if (
1438 1
            $helperVariableForRecursion !== null
1439
            &&
1440 1
            \is_array($helperVariableForRecursion) === true
1441
        ) {
1442
            $arrayForTheLoop = $helperVariableForRecursion;
1443
        } else {
1444 1
            $arrayForTheLoop = $this->getGenerator();
1445
        }
1446
1447 1
        foreach ($arrayForTheLoop as $key => $value) {
1448 1
            if ($value instanceof self) {
1449
                $value = $value->getArray();
1450
            }
1451
1452 1
            if (\array_key_exists($key, $array)) {
1453 1
                if ($value !== $array[$key]) {
1454 1
                    $result[$key] = $value;
1455
                }
1456
            } else {
1457 1
                $result[$key] = $value;
1458
            }
1459
        }
1460
1461 1
        return static::create(
1462 1
            $result,
1463 1
            $this->iteratorClass,
1464 1
            false
1465
        );
1466
    }
1467
1468
    /**
1469
     * Return values that are only in the new $array.
1470
     *
1471
     * @param array $array
1472
     *
1473
     * @return static
1474
     *                <p>(Immutable)</p>
1475
     */
1476 8
    public function diffReverse(array $array = []): self
1477
    {
1478 8
        return static::create(
1479 8
            \array_diff($array, $this->getArray()),
1480 8
            $this->iteratorClass,
1481 8
            false
1482
        );
1483
    }
1484
1485
    /**
1486
     * Divide an array into two arrays. One with keys and the other with values.
1487
     *
1488
     * @return static
1489
     *                <p>(Immutable)</p>
1490
     */
1491 1
    public function divide(): self
1492
    {
1493 1
        return static::create(
1494
            [
1495 1
                $this->keys(),
1496 1
                $this->values(),
1497
            ],
1498 1
            $this->iteratorClass,
1499 1
            false
1500
        );
1501
    }
1502
1503
    /**
1504
     * Iterate over the current array and modify the array's value.
1505
     *
1506
     * @param \Closure $closure
1507
     *
1508
     * @return static
1509
     *                <p>(Immutable)</p>
1510
     */
1511 5 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...
1512
    {
1513
        // init
1514 5
        $array = [];
1515
1516 5
        foreach ($this->getGenerator() as $key => $value) {
1517 5
            $array[$key] = $closure($value, $key);
1518
        }
1519
1520 5
        return static::create(
1521 5
            $array,
1522 5
            $this->iteratorClass,
1523 5
            false
1524
        );
1525
    }
1526
1527
    /**
1528
     * Sets the internal iterator to the last element in the array and returns this element.
1529
     *
1530
     * @return mixed
1531
     */
1532
    public function end()
1533
    {
1534
        return \end($this->array);
1535
    }
1536
1537
    /**
1538
     * Check if a value is in the current array using a closure.
1539
     *
1540
     * @param \Closure $closure
1541
     *
1542
     * @return bool
1543
     *              <p>Returns true if the given value is found, false otherwise.</p>
1544
     */
1545 4
    public function exists(\Closure $closure): bool
1546
    {
1547
        // init
1548 4
        $isExists = false;
1549
1550 4
        foreach ($this->getGenerator() as $key => $value) {
1551 3
            if ($closure($value, $key)) {
1552 1
                $isExists = true;
1553
1554 1
                break;
1555
            }
1556
        }
1557
1558 4
        return $isExists;
1559
    }
1560
1561
    /**
1562
     * Fill the array until "$num" with "$default" values.
1563
     *
1564
     * @param int   $num
1565
     * @param mixed $default
1566
     *
1567
     * @return static
1568
     *                <p>(Immutable)</p>
1569
     */
1570 8
    public function fillWithDefaults(int $num, $default = null): self
1571
    {
1572 8
        if ($num < 0) {
1573 1
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1574
        }
1575
1576 7
        $this->generatorToArray();
1577
1578 7
        $tmpArray = $this->array;
1579
1580 7
        $count = \count($tmpArray);
1581
1582 7
        while ($count < $num) {
1583 4
            $tmpArray[] = $default;
1584 4
            ++$count;
1585
        }
1586
1587 7
        return static::create(
1588 7
            $tmpArray,
1589 7
            $this->iteratorClass,
1590 7
            false
1591
        );
1592
    }
1593
1594
    /**
1595
     * Find all items in an array that pass the truth test.
1596
     *
1597
     * @param \Closure|null $closure [optional] <p>
1598
     *                               The callback function to use
1599
     *                               </p>
1600
     *                               <p>
1601
     *                               If no callback is supplied, all entries of
1602
     *                               input equal to false (see
1603
     *                               converting to
1604
     *                               boolean) will be removed.
1605
     *                               </p>
1606
     * @param int           $flag    [optional] <p>
1607
     *                               Flag determining what arguments are sent to <i>callback</i>:
1608
     *                               </p><ul>
1609
     *                               <li>
1610
     *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1611
     *                               to <i>callback</i> instead of the value</span>
1612
     *                               </li>
1613
     *                               <li>
1614
     *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1615
     *                               arguments to <i>callback</i> instead of the value</span>
1616
     *                               </li>
1617
     *                               </ul>
1618
     *
1619
     * @return static
1620
     *                <p>(Immutable)</p>
1621
     */
1622 12
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH)
1623
    {
1624 12
        if (!$closure) {
1625 1
            return $this->clean();
1626
        }
1627
1628 12
        return static::create(
1629 12
            \array_filter($this->getArray(), $closure, $flag),
1630 12
            $this->iteratorClass,
1631 12
            false
1632
        );
1633
    }
1634
1635
    /**
1636
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
1637
     * property within that.
1638
     *
1639
     * @param string          $property
1640
     * @param string|string[] $value
1641
     * @param string          $comparisonOp
1642
     *                                      <p>
1643
     *                                      'eq' (equals),<br />
1644
     *                                      'gt' (greater),<br />
1645
     *                                      'gte' || 'ge' (greater or equals),<br />
1646
     *                                      'lt' (less),<br />
1647
     *                                      'lte' || 'le' (less or equals),<br />
1648
     *                                      'ne' (not equals),<br />
1649
     *                                      'contains',<br />
1650
     *                                      'notContains',<br />
1651
     *                                      'newer' (via strtotime),<br />
1652
     *                                      'older' (via strtotime),<br />
1653
     *                                      </p>
1654
     *
1655
     * @return static
1656
     *                <p>(Immutable)</p>
1657
     */
1658 1
    public function filterBy(string $property, $value, string $comparisonOp = null): self
1659
    {
1660 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...
1661 1
            $comparisonOp = \is_array($value) === true ? 'contains' : 'eq';
1662
        }
1663
1664
        $ops = [
1665
            'eq' => static function ($item, $prop, $value): bool {
1666 1
                return $item[$prop] === $value;
1667 1
            },
1668
            'gt' => static function ($item, $prop, $value): bool {
1669
                return $item[$prop] > $value;
1670 1
            },
1671
            'ge' => static function ($item, $prop, $value): bool {
1672
                return $item[$prop] >= $value;
1673 1
            },
1674
            'gte' => static function ($item, $prop, $value): bool {
1675
                return $item[$prop] >= $value;
1676 1
            },
1677
            'lt' => static function ($item, $prop, $value): bool {
1678 1
                return $item[$prop] < $value;
1679 1
            },
1680
            'le' => static function ($item, $prop, $value): bool {
1681
                return $item[$prop] <= $value;
1682 1
            },
1683
            'lte' => static function ($item, $prop, $value): bool {
1684
                return $item[$prop] <= $value;
1685 1
            },
1686
            'ne' => static function ($item, $prop, $value): bool {
1687
                return $item[$prop] !== $value;
1688 1
            },
1689
            'contains' => static function ($item, $prop, $value): bool {
1690 1
                return \in_array($item[$prop], (array) $value, true);
1691 1
            },
1692
            'notContains' => static function ($item, $prop, $value): bool {
1693
                return !\in_array($item[$prop], (array) $value, true);
1694 1
            },
1695
            'newer' => static function ($item, $prop, $value): bool {
1696
                return \strtotime($item[$prop]) > \strtotime($value);
1697 1
            },
1698
            'older' => static function ($item, $prop, $value): bool {
1699
                return \strtotime($item[$prop]) < \strtotime($value);
1700 1
            },
1701
        ];
1702
1703 1
        $result = \array_values(
1704 1
            \array_filter(
1705 1
                $this->getArray(),
1706
                static function ($item) use (
1707 1
                    $property,
1708 1
                    $value,
1709 1
                    $ops,
1710 1
                    $comparisonOp
1711
                ) {
1712 1
                    $item = (array) $item;
1713 1
                    $itemArrayy = static::create($item);
1714 1
                    $item[$property] = $itemArrayy->get($property, []);
1715
1716 1
                    return $ops[$comparisonOp]($item, $property, $value);
1717 1
                }
1718
            )
1719
        );
1720
1721 1
        return static::create(
1722 1
            $result,
1723 1
            $this->iteratorClass,
1724 1
            false
1725
        );
1726
    }
1727
1728
    /**
1729
     * Find the first item in an array that passes the truth test,
1730
     *  otherwise return false
1731
     *
1732
     * @param \Closure $closure
1733
     *
1734
     * @return false|mixed
1735
     *                     <p>Return false if we did not find the value.</p>
1736
     */
1737 8
    public function find(\Closure $closure)
1738
    {
1739 8
        foreach ($this->getGenerator() as $key => $value) {
1740 6
            if ($closure($value, $key)) {
1741 5
                return $value;
1742
            }
1743
        }
1744
1745 3
        return false;
1746
    }
1747
1748
    /**
1749
     * find by ...
1750
     *
1751
     * @param string          $property
1752
     * @param string|string[] $value
1753
     * @param string          $comparisonOp
1754
     *
1755
     * @return static
1756
     *                <p>(Immutable)</p>
1757
     */
1758 1
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
1759
    {
1760 1
        return $this->filterBy($property, $value, $comparisonOp);
1761
    }
1762
1763
    /**
1764
     * Get the first value from the current array.
1765
     *
1766
     * @return mixed
1767
     *               <p>Return null if there wasn't a element.</p>
1768
     */
1769 21
    public function first()
1770
    {
1771 21
        $key_first = $this->firstKey();
1772 21
        if ($key_first === null) {
1773 3
            return null;
1774
        }
1775
1776 18
        return $this->get($key_first);
1777
    }
1778
1779
    /**
1780
     * Get the first key from the current array.
1781
     *
1782
     * @return mixed
1783
     *               <p>Return null if there wasn't a element.</p>
1784
     */
1785 28
    public function firstKey()
1786
    {
1787 28
        $this->generatorToArray();
1788
1789 28
        return \array_key_first($this->array);
1790
    }
1791
1792
    /**
1793
     * Get the first value(s) from the current array.
1794
     * And will return an empty array if there was no first entry.
1795
     *
1796
     * @param int|null $number <p>How many values you will take?</p>
1797
     *
1798
     * @return static
1799
     *                <p>(Immutable)</p>
1800
     */
1801 37 View Code Duplication
    public function firstsImmutable(int $number = null): 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...
1802
    {
1803 37
        $arrayTmp = $this->getArray();
1804
1805 37
        if ($number === null) {
1806 14
            $array = (array) \array_shift($arrayTmp);
1807
        } else {
1808 23
            $number = (int) $number;
1809 23
            $array = \array_splice($arrayTmp, 0, $number);
1810
        }
1811
1812 37
        return static::create(
1813 37
            $array,
1814 37
            $this->iteratorClass,
1815 37
            false
1816
        );
1817
    }
1818
1819
    /**
1820
     * Get the first value(s) from the current array.
1821
     * And will return an empty array if there was no first entry.
1822
     *
1823
     * @param int|null $number <p>How many values you will take?</p>
1824
     *
1825
     * @return static
1826
     *                <p>(Immutable)</p>
1827
     */
1828 3 View Code Duplication
    public function firstsKeys(int $number = null): 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...
1829
    {
1830 3
        $arrayTmp = $this->keys()->getArray();
1831
1832 3
        if ($number === null) {
1833
            $array = (array) \array_shift($arrayTmp);
1834
        } else {
1835 3
            $number = (int) $number;
1836 3
            $array = \array_splice($arrayTmp, 0, $number);
1837
        }
1838
1839 3
        return static::create(
1840 3
            $array,
1841 3
            $this->iteratorClass,
1842 3
            false
1843
        );
1844
    }
1845
1846
    /**
1847
     * Get and rmove the first value(s) from the current array.
1848
     * And will return an empty array if there was no first entry.
1849
     *
1850
     * @param int|null $number <p>How many values you will take?</p>
1851
     *
1852
     * @return static
1853
     *                <p>(Mutable)</p>
1854
     */
1855 34
    public function firstsMutable(int $number = null): self
1856
    {
1857 34
        $this->generatorToArray();
1858
1859 34
        if ($number === null) {
1860 19
            $this->array = (array) \array_shift($this->array);
1861
        } else {
1862 15
            $number = (int) $number;
1863 15
            $this->array = \array_splice($this->array, 0, $number);
1864
        }
1865
1866 34
        return $this;
1867
    }
1868
1869
    /**
1870
     * Exchanges all keys with their associated values in an array.
1871
     *
1872
     * @return static
1873
     *                <p>(Immutable)</p>
1874
     */
1875 1
    public function flip(): self
1876
    {
1877 1
        return static::create(
1878 1
            \array_flip($this->getArray()),
1879 1
            $this->iteratorClass,
1880 1
            false
1881
        );
1882
    }
1883
1884
    /**
1885
     * Tests whether the given predicate p holds for all elements of this array.
1886
     *
1887
     * @param \Closure $closure the predicate
1888
     *
1889
     * @return bool
1890
     *              <p>TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.</p>
1891
     */
1892
    public function forAll(\Closure $closure): bool
1893
    {
1894
        foreach ($this->getGenerator() as $key => $element) {
1895
            if (!$closure($key, $element)) {
1896
                return false;
1897
            }
1898
        }
1899
1900
        return true;
1901
    }
1902
1903
    /**
1904
     * Get a value from an array (optional using dot-notation).
1905
     *
1906
     * @param mixed $key      <p>The key to look for.</p>
1907
     * @param mixed $fallback <p>Value to fallback to.</p>
1908
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
1909
     *                        class.</p>
1910
     *
1911
     * @return mixed|static
1912
     */
1913 169
    public function get($key, $fallback = null, array $array = null)
1914
    {
1915 169
        if ($array !== null) {
1916 4
            $usedArray = $array;
1917
        } else {
1918 166
            $this->generatorToArray();
1919
1920 166
            $usedArray = $this->array;
1921
        }
1922
1923 169
        if ($key === null) {
1924 1
            return static::create(
1925 1
                $usedArray,
1926 1
                $this->iteratorClass,
1927 1
                false
1928
            );
1929
        }
1930
1931
        // php cast "bool"-index into "int"-index
1932 169
        if ((bool) $key === $key) {
1933 3
            $key = (int) $key;
1934
        }
1935
1936 169
        if (\array_key_exists($key, $usedArray) === true) {
1937 159
            if (\is_array($usedArray[$key]) === true) {
1938 11
                return static::create(
1939 11
                    $usedArray[$key],
1940 11
                    $this->iteratorClass,
1941 11
                    false
1942
                );
1943
            }
1944
1945 151
            return $usedArray[$key];
1946
        }
1947
1948
        // crawl through array, get key according to object or not
1949 24
        $usePath = false;
1950
        if (
1951 24
            $this->pathSeparator
1952
            &&
1953 24
            (string) $key === $key
1954
            &&
1955 24
            \strpos($key, $this->pathSeparator) !== false
1956
        ) {
1957 7
            $segments = \explode($this->pathSeparator, (string) $key);
1958 7
            if ($segments !== false) {
1959 7
                $usePath = true;
1960
1961 7
                foreach ($segments as $segment) {
1962
                    if (
1963
                        (
1964 7
                            \is_array($usedArray) === true
1965
                            ||
1966 7
                            $usedArray instanceof \ArrayAccess
1967
                        )
1968
                        &&
1969 7
                        isset($usedArray[$segment])
1970
                    ) {
1971 7
                        $usedArray = $usedArray[$segment];
1972
1973 7
                        continue;
1974
                    }
1975
1976
                    if (
1977 6
                        \is_object($usedArray) === true
1978
                        &&
1979 6
                        \property_exists($usedArray, $segment)
1980
                    ) {
1981 1
                        $usedArray = $usedArray->{$segment};
1982
1983 1
                        continue;
1984
                    }
1985
1986 5
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
1987
                }
1988
            }
1989
        }
1990
1991 24
        if (!$usePath && !isset($usedArray[$key])) {
1992 17
            return $fallback instanceof \Closure ? $fallback() : $fallback;
1993
        }
1994
1995 7
        if (\is_array($usedArray) === true) {
1996 1
            return static::create(
1997 1
                $usedArray,
1998 1
                $this->iteratorClass,
1999 1
                false
2000
            );
2001
        }
2002
2003 7
        return $usedArray;
2004
    }
2005
2006
    /**
2007
     * alias: for "Arrayy->getArray()"
2008
     *
2009
     * @return array
2010
     *
2011
     * @see Arrayy::getArray()
2012
     */
2013 1
    public function getAll(): array
2014
    {
2015 1
        return $this->getArray();
2016
    }
2017
2018
    /**
2019
     * Get the current array from the "Arrayy"-object.
2020
     *
2021
     * @param bool $convertAllArrayyElements
2022
     *
2023
     * @return array
2024
     */
2025 842
    public function getArray($convertAllArrayyElements = false): array
2026
    {
2027
        // init
2028 842
        $array = [];
2029
2030 842
        if ($convertAllArrayyElements) {
2031 1
            foreach ($this->getGenerator() as $key => $value) {
2032 1
                if ($value instanceof self) {
2033 1
                    $value = $value->getArray(true);
2034
                }
2035
2036 1
                $array[$key] = $value;
2037
            }
2038
        } else {
2039 842
            foreach ($this->getGenerator() as $key => $value) {
2040 736
                $array[$key] = $value;
2041
            }
2042
        }
2043
2044 842
        return $array;
2045
    }
2046
2047
    /**
2048
     * Returns the values from a single column of the input array, identified by
2049
     * the $columnKey, can be used to extract data-columns from multi-arrays.
2050
     *
2051
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
2052
     * array by the values from the $indexKey column in the input array.
2053
     *
2054
     * @param mixed $columnKey
2055
     * @param mixed $indexKey
2056
     *
2057
     * @return static
2058
     *                <p>(Immutable)</p>
2059
     */
2060 1
    public function getColumn($columnKey = null, $indexKey = null): self
2061
    {
2062 1
        return static::create(
2063 1
            \array_column($this->getArray(), $columnKey, $indexKey),
2064 1
            $this->iteratorClass,
2065 1
            false
2066
        );
2067
    }
2068
2069
    /**
2070
     * Get the current array from the "Arrayy"-object as generator.
2071
     *
2072
     * @return \Generator
2073
     */
2074 920
    public function getGenerator(): \Generator
2075
    {
2076 920
        if ($this->generator instanceof ArrayyRewindableGenerator) {
2077 39
            yield from $this->generator;
2078
        }
2079
2080 920
        yield from $this->array;
2081 876
    }
2082
2083
    /**
2084
     * alias: for "Arrayy->keys()"
2085
     *
2086
     * @return static
2087
     *                <p>(Immutable)</p>
2088
     *
2089
     * @see Arrayy::keys()
2090
     */
2091 2
    public function getKeys()
2092
    {
2093 2
        return $this->keys();
2094
    }
2095
2096
    /**
2097
     * Get the current array from the "Arrayy"-object as object.
2098
     *
2099
     * @return \stdClass
2100
     */
2101 4
    public function getObject(): \stdClass
2102
    {
2103 4
        return self::arrayToObject($this->getArray());
2104
    }
2105
2106
    /**
2107
     * alias: for "Arrayy->randomImmutable()"
2108
     *
2109
     * @return static
2110
     *                <p>(Immutable)</p>
2111
     *
2112
     * @see Arrayy::randomImmutable()
2113
     */
2114 4
    public function getRandom(): self
2115
    {
2116 4
        return $this->randomImmutable();
2117
    }
2118
2119
    /**
2120
     * alias: for "Arrayy->randomKey()"
2121
     *
2122
     * @return mixed
2123
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2124
     *
2125
     * @see Arrayy::randomKey()
2126
     */
2127 3
    public function getRandomKey()
2128
    {
2129 3
        return $this->randomKey();
2130
    }
2131
2132
    /**
2133
     * alias: for "Arrayy->randomKeys()"
2134
     *
2135
     * @param int $number
2136
     *
2137
     * @return static
2138
     *                <p>(Immutable)</p>
2139
     *
2140
     * @see Arrayy::randomKeys()
2141
     */
2142 8
    public function getRandomKeys(int $number): self
2143
    {
2144 8
        return $this->randomKeys($number);
2145
    }
2146
2147
    /**
2148
     * alias: for "Arrayy->randomValue()"
2149
     *
2150
     * @return mixed
2151
     *               <p>Get a random value or null if there wasn't a value.</p>
2152
     *
2153
     * @see Arrayy::randomValue()
2154
     */
2155 3
    public function getRandomValue()
2156
    {
2157 3
        return $this->randomValue();
2158
    }
2159
2160
    /**
2161
     * alias: for "Arrayy->randomValues()"
2162
     *
2163
     * @param int $number
2164
     *
2165
     * @return static
2166
     *                <p>(Immutable)</p>
2167
     *
2168
     * @see Arrayy::randomValues()
2169
     */
2170 6
    public function getRandomValues(int $number): self
2171
    {
2172 6
        return $this->randomValues($number);
2173
    }
2174
2175
    /**
2176
     * Gets all values.
2177
     *
2178
     * @return static
2179
     *                <p>The values of all elements in this array, in the order they
2180
     *                appear in the array.</p>
2181
     */
2182
    public function getValues()
2183
    {
2184
        $this->generatorToArray();
2185
2186
        return static::create(
2187
            \array_values($this->array),
2188
            $this->iteratorClass,
2189
            false
2190
        );
2191
    }
2192
2193
    /**
2194
     * Gets all values via Generator.
2195
     *
2196
     * @return \Generator
2197
     *                    <p>The values of all elements in this array, in the order they
2198
     *                    appear in the array as Generator.</p>
2199
     */
2200
    public function getValuesYield(): \Generator
2201
    {
2202
        yield from $this->getGenerator();
2203
    }
2204
2205
    /**
2206
     * Group values from a array according to the results of a closure.
2207
     *
2208
     * @param callable|string $grouper  <p>A callable function name.</p>
2209
     * @param bool            $saveKeys
2210
     *
2211
     * @return static
2212
     *                <p>(Immutable)</p>
2213
     */
2214 4
    public function group($grouper, bool $saveKeys = false): self
2215
    {
2216
        // init
2217 4
        $result = [];
2218
2219
        // Iterate over values, group by property/results from closure.
2220 4
        foreach ($this->getGenerator() as $key => $value) {
2221 4
            if (\is_callable($grouper) === true) {
2222 3
                $groupKey = $grouper($value, $key);
2223
            } else {
2224 1
                $groupKey = $this->get($grouper);
2225
            }
2226
2227 4
            $newValue = $this->get($groupKey, null, $result);
2228
2229 4
            if ($groupKey instanceof self) {
2230
                $groupKey = $groupKey->getArray();
2231
            }
2232
2233 4
            if ($newValue instanceof self) {
2234 4
                $newValue = $newValue->getArray();
2235
            }
2236
2237
            // Add to results.
2238 4
            if ($groupKey !== null) {
2239 3
                if ($saveKeys) {
2240 2
                    $result[$groupKey] = $newValue;
2241 2
                    $result[$groupKey][$key] = $value;
2242
                } else {
2243 1
                    $result[$groupKey] = $newValue;
2244 1
                    $result[$groupKey][] = $value;
2245
                }
2246
            }
2247
        }
2248
2249 4
        return static::create(
2250 4
            $result,
2251 4
            $this->iteratorClass,
2252 4
            false
2253
        );
2254
    }
2255
2256
    /**
2257
     * Check if an array has a given key.
2258
     *
2259
     * @param mixed $key
2260
     *
2261
     * @return bool
2262
     */
2263 23
    public function has($key): bool
2264
    {
2265 23
        static $UN_FOUND = null;
2266
2267 23
        if ($UN_FOUND === null) {
2268
            // Generate unique string to use as marker.
2269 1
            $UN_FOUND = \uniqid('arrayy', true);
2270
        }
2271
2272 23
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2273
    }
2274
2275
    /**
2276
     * Check if an array has a given value.
2277
     *
2278
     * INFO: if you need to search recursive please use ```contains()```
2279
     *
2280
     * @param mixed $value
2281
     *
2282
     * @return bool
2283
     */
2284 1
    public function hasValue($value): bool
2285
    {
2286 1
        return $this->contains($value);
2287
    }
2288
2289
    /**
2290
     * Implodes the values of this array.
2291
     *
2292
     * @param string $glue
2293
     *
2294
     * @return string
2295
     */
2296 28
    public function implode(string $glue = ''): string
2297
    {
2298 28
        return $this->implode_recursive($glue, $this->getArray(), false);
2299
    }
2300
2301
    /**
2302
     * Implodes the keys of this array.
2303
     *
2304
     * @param string $glue
2305
     *
2306
     * @return string
2307
     */
2308 8
    public function implodeKeys(string $glue = ''): string
2309
    {
2310 8
        return $this->implode_recursive($glue, $this->getArray(), true);
2311
    }
2312
2313
    /**
2314
     * Given a list and an iterate-function that returns
2315
     * a key for each element in the list (or a property name),
2316
     * returns an object with an index of each item.
2317
     *
2318
     * @param mixed $key
2319
     *
2320
     * @return static
2321
     *                <p>(Immutable)</p>
2322
     */
2323 4
    public function indexBy($key): self
2324
    {
2325
        // init
2326 4
        $results = [];
2327
2328 4
        foreach ($this->getGenerator() as $a) {
2329 4
            if (\array_key_exists($key, $a) === true) {
2330 3
                $results[$a[$key]] = $a;
2331
            }
2332
        }
2333
2334 4
        return static::create(
2335 4
            $results,
2336 4
            $this->iteratorClass,
2337 4
            false
2338
        );
2339
    }
2340
2341
    /**
2342
     * alias: for "Arrayy->searchIndex()"
2343
     *
2344
     * @param mixed $value <p>The value to search for.</p>
2345
     *
2346
     * @return false|mixed
2347
     *
2348
     * @see Arrayy::searchIndex()
2349
     */
2350 4
    public function indexOf($value)
2351
    {
2352 4
        return $this->searchIndex($value);
2353
    }
2354
2355
    /**
2356
     * Get everything but the last..$to items.
2357
     *
2358
     * @param int $to
2359
     *
2360
     * @return static
2361
     *                <p>(Immutable)</p>
2362
     */
2363 12
    public function initial(int $to = 1): self
2364
    {
2365 12
        return $this->firstsImmutable(\count($this->getArray(), \COUNT_NORMAL) - $to);
2366
    }
2367
2368
    /**
2369
     * Return an array with all elements found in input array.
2370
     *
2371
     * @param array $search
2372
     * @param bool  $keepKeys
2373
     *
2374
     * @return static
2375
     *                <p>(Immutable)</p>
2376
     */
2377 4
    public function intersection(array $search, bool $keepKeys = false): self
2378
    {
2379 4
        if ($keepKeys) {
2380 1
            return static::create(
2381 1
                \array_uintersect(
2382 1
                    $this->array,
2383 1
                    $search,
2384
                    static function ($a, $b) {
2385 1
                        return $a === $b ? 0 : -1;
2386 1
                    }
2387
                ),
2388 1
                $this->iteratorClass,
2389 1
                false
2390
            );
2391
        }
2392
2393 3
        return static::create(
2394 3
            \array_values(\array_intersect($this->getArray(), $search)),
2395 3
            $this->iteratorClass,
2396 3
            false
2397
        );
2398
    }
2399
2400
    /**
2401
     * Return an array with all elements found in input array.
2402
     *
2403
     * @param array ...$array
2404
     *
2405
     * @return static
2406
     *                <p>(Immutable)</p>
2407
     */
2408 1
    public function intersectionMulti(...$array): self
2409
    {
2410 1
        return static::create(
2411 1
            \array_values(\array_intersect($this->getArray(), ...$array)),
2412 1
            $this->iteratorClass,
2413 1
            false
2414
        );
2415
    }
2416
2417
    /**
2418
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
2419
     *
2420
     * @param array $search
2421
     *
2422
     * @return bool
2423
     */
2424 1
    public function intersects(array $search): bool
2425
    {
2426 1
        return \count($this->intersection($search)->array, \COUNT_NORMAL) > 0;
2427
    }
2428
2429
    /**
2430
     * Invoke a function on all of an array's values.
2431
     *
2432
     * @param callable $callable
2433
     * @param mixed    $arguments
2434
     *
2435
     * @return static
2436
     *                <p>(Immutable)</p>
2437
     */
2438 1
    public function invoke($callable, $arguments = []): self
2439
    {
2440
        // If one argument given for each iteration, create an array for it.
2441 1
        if (\is_array($arguments) === false) {
2442 1
            $arguments = \array_fill(
2443 1
                0,
2444 1
                \count($this->getArray(), \COUNT_NORMAL),
2445 1
                $arguments
2446
            );
2447
        }
2448
2449
        // If the callable has arguments, pass them.
2450 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...
2451 1
            $array = \array_map($callable, $this->getArray(), $arguments);
2452
        } else {
2453 1
            $array = $this->map($callable);
2454
        }
2455
2456 1
        return static::create(
2457 1
            $array,
2458 1
            $this->iteratorClass,
2459 1
            false
2460
        );
2461
    }
2462
2463
    /**
2464
     * Check whether array is associative or not.
2465
     *
2466
     * @param bool $recursive
2467
     *
2468
     * @return bool
2469
     *              <p>Returns true if associative, false otherwise.</p>
2470
     */
2471 15 View Code Duplication
    public function isAssoc(bool $recursive = false): 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...
2472
    {
2473 15
        if ($this->isEmpty()) {
2474 3
            return false;
2475
        }
2476
2477 13
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2478 13
            if ((string) $key !== $key) {
2479 11
                return false;
2480
            }
2481
        }
2482
2483 3
        return true;
2484
    }
2485
2486
    /**
2487
     * Check if a given key or keys are empty.
2488
     *
2489
     * @param int|int[]|string|string[]|null $keys
2490
     *
2491
     * @return bool
2492
     *              <p>Returns true if empty, false otherwise.</p>
2493
     */
2494 38
    public function isEmpty($keys = null): bool
2495
    {
2496 38
        if ($this->generator) {
2497
            return $this->getArray() === [];
2498
        }
2499
2500 38
        if ($keys === null) {
2501 38
            return $this->array === [];
2502
        }
2503
2504
        foreach ((array) $keys as $key) {
2505
            if (!empty($this->get($key))) {
2506
                return false;
2507
            }
2508
        }
2509
2510
        return true;
2511
    }
2512
2513
    /**
2514
     * Check if the current array is equal to the given "$array" or not.
2515
     *
2516
     * @param array $array
2517
     *
2518
     * @return bool
2519
     */
2520 1
    public function isEqual(array $array): bool
2521
    {
2522 1
        return $this->getArray() === $array;
2523
    }
2524
2525
    /**
2526
     * Check if the current array is a multi-array.
2527
     *
2528
     * @return bool
2529
     */
2530 22
    public function isMultiArray(): bool
2531
    {
2532
        return !(
2533 22
            \count($this->getArray(), \COUNT_NORMAL)
2534
            ===
2535 22
            \count($this->getArray(), \COUNT_RECURSIVE)
2536
        );
2537
    }
2538
2539
    /**
2540
     * Check whether array is numeric or not.
2541
     *
2542
     * @return bool
2543
     *              <p>Returns true if numeric, false otherwise.</p>
2544
     */
2545 5 View Code Duplication
    public function isNumeric(): 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...
2546
    {
2547 5
        if ($this->isEmpty()) {
2548 2
            return false;
2549
        }
2550
2551 4
        foreach ($this->keys()->getGenerator() as $key) {
2552 4
            if ((int) $key !== $key) {
2553 2
                return false;
2554
            }
2555
        }
2556
2557 2
        return true;
2558
    }
2559
2560
    /**
2561
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2562
     *
2563
     * @param bool $recursive
2564
     *
2565
     * @return bool
2566
     */
2567 9
    public function isSequential(bool $recursive = false): bool
2568
    {
2569
2570
        // recursive
2571
2572 9
        if ($recursive === true) {
2573
            return $this->array_keys_recursive($this->getArray())
2574
                   ===
2575
                   \range(0, \count($this->getArray(), \COUNT_RECURSIVE) - 1);
2576
        }
2577
2578
        // non recursive
2579
2580 9
        return \array_keys($this->getArray())
2581
               ===
2582 9
               \range(0, \count($this->getArray(), \COUNT_NORMAL) - 1);
2583
    }
2584
2585
    /**
2586
     * @return array
2587
     */
2588
    public function jsonSerialize(): array
2589
    {
2590
        return $this->getArray();
2591
    }
2592
2593
    /**
2594
     * Gets the key/index of the element at the current internal iterator position.
2595
     *
2596
     * @return int|string|null
2597
     */
2598
    public function key()
2599
    {
2600
        return \key($this->array);
2601
    }
2602
2603
    /**
2604
     * Checks if the given key exists in the provided array.
2605
     *
2606
     * INFO: This method only use "array_key_exists()" if you want to use "dot"-notation,
2607
     *       then you need to use "Arrayy->offsetExists()".
2608
     *
2609
     * @param int|string $key the key to look for
2610
     *
2611
     * @return bool
2612
     */
2613 124
    public function keyExists($key): bool
2614
    {
2615 124
        return \array_key_exists($key, $this->array);
2616
    }
2617
2618
    /**
2619
     * Get all keys from the current array.
2620
     *
2621
     * @param bool       $recursive     [optional] <p>
2622
     *                                  Get all keys, also from all sub-arrays from an multi-dimensional array.
2623
     *                                  </p>
2624
     * @param mixed|null $search_values [optional] <p>
2625
     *                                  If specified, then only keys containing these values are returned.
2626
     *                                  </p>
2627
     * @param bool       $strict        [optional] <p>
2628
     *                                  Determines if strict comparison (===) should be used during the search.
2629
     *                                  </p>
2630
     *
2631
     * @return static
2632
     *                <p>(Immutable) An array of all the keys in input.</p>
2633
     */
2634 29
    public function keys(
2635
        bool $recursive = false,
2636
        $search_values = null,
2637
        bool $strict = true
2638
    ): self {
2639
2640
        // recursive
2641
2642 29
        if ($recursive === true) {
2643 4
            $array = $this->array_keys_recursive(
2644 4
                null,
2645 4
                $search_values,
2646 4
                $strict
2647
            );
2648
2649 4
            return static::create(
2650 4
                $array,
2651 4
                $this->iteratorClass,
2652 4
                false
2653
            );
2654
        }
2655
2656
        // non recursive
2657
2658 28
        if ($search_values === null) {
2659
            $arrayFunction = function (): \Generator {
2660 28
                foreach ($this->getGenerator() as $key => $value) {
2661 26
                    yield $key;
2662
                }
2663 28
            };
2664
        } else {
2665
            $arrayFunction = function () use ($search_values, $strict): \Generator {
2666 1
                $is_array_tmp = \is_array($search_values);
2667
2668 1
                foreach ($this->getGenerator() as $key => $value) {
2669 View Code Duplication
                    if (
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...
2670
                        (
2671 1
                            $is_array_tmp === false
2672
                            &&
2673 1
                            $strict === true
2674
                            &&
2675 1
                            $search_values === $value
2676
                        )
2677
                        ||
2678
                        (
2679 1
                            $is_array_tmp === false
2680
                            &&
2681 1
                            $strict === false
2682
                            &&
2683 1
                            $search_values == $value
2684
                        )
2685
                        ||
2686
                        (
2687 1
                            $is_array_tmp === true
2688
                            &&
2689 1
                            \in_array($value, $search_values, $strict)
2690
                        )
2691
                    ) {
2692 1
                        yield $key;
2693
                    }
2694
                }
2695 1
            };
2696
        }
2697
2698 28
        return static::create(
2699 28
            $arrayFunction,
2700 28
            $this->iteratorClass,
2701 28
            false
2702
        );
2703
    }
2704
2705
    /**
2706
     * Sort an array by key in reverse order.
2707
     *
2708
     * @param int $sort_flags [optional] <p>
2709
     *                        You may modify the behavior of the sort using the optional
2710
     *                        parameter sort_flags, for details
2711
     *                        see sort.
2712
     *                        </p>
2713
     *
2714
     * @return static
2715
     *                <p>(Mutable) Return this Arrayy object.</p>
2716
     */
2717 4
    public function krsort(int $sort_flags = 0): self
2718
    {
2719 4
        $this->generatorToArray();
2720
2721 4
        \krsort($this->array, $sort_flags);
2722
2723 4
        return $this;
2724
    }
2725
2726
    /**
2727
     * Get the last value from the current array.
2728
     *
2729
     * @return mixed
2730
     *               <p>Return null if there wasn't a element.</p>
2731
     */
2732 17
    public function last()
2733
    {
2734 17
        $key_last = $this->lastKey();
2735 17
        if ($key_last === null) {
2736 2
            return null;
2737
        }
2738
2739 15
        return $this->get($key_last);
2740
    }
2741
2742
    /**
2743
     * Get the last key from the current array.
2744
     *
2745
     * @return mixed
2746
     *               <p>Return null if there wasn't a element.</p>
2747
     */
2748 21
    public function lastKey()
2749
    {
2750 21
        $this->generatorToArray();
2751
2752 21
        return \array_key_last($this->array);
2753
    }
2754
2755
    /**
2756
     * Get the last value(s) from the current array.
2757
     *
2758
     * @param int|null $number
2759
     *
2760
     * @return static
2761
     *                <p>(Immutable)</p>
2762
     */
2763 13
    public function lastsImmutable(int $number = null): self
2764
    {
2765 13
        if ($this->isEmpty()) {
2766 1
            return static::create(
2767 1
                [],
2768 1
                $this->iteratorClass,
2769 1
                false
2770
            );
2771
        }
2772
2773 12
        if ($number === null) {
2774 8
            $poppedValue = $this->last();
2775
2776 8
            if ($poppedValue === null) {
2777 1
                $poppedValue = [$poppedValue];
2778
            } else {
2779 7
                $poppedValue = (array) $poppedValue;
2780
            }
2781
2782 8
            $arrayy = static::create(
2783 8
                $poppedValue,
2784 8
                $this->iteratorClass,
2785 8
                false
2786
            );
2787
        } else {
2788 4
            $number = (int) $number;
2789 4
            $arrayy = $this->rest(-$number);
2790
        }
2791
2792 12
        return $arrayy;
2793
    }
2794
2795
    /**
2796
     * Get the last value(s) from the current array.
2797
     *
2798
     * @param int|null $number
2799
     *
2800
     * @return static
2801
     *                <p>(Mutable)</p>
2802
     */
2803 13
    public function lastsMutable(int $number = null): self
2804
    {
2805 13
        if ($this->isEmpty()) {
2806 1
            return $this;
2807
        }
2808
2809 12
        if ($number === null) {
2810 8
            $poppedValue = $this->last();
2811
2812 8
            if ($poppedValue === null) {
2813 1
                $poppedValue = [$poppedValue];
2814
            } else {
2815 7
                $poppedValue = (array) $poppedValue;
2816
            }
2817
2818 8
            $this->array = static::create(
2819 8
                $poppedValue,
2820 8
                $this->iteratorClass,
2821 8
                false
2822 8
            )->getArray();
2823
        } else {
2824 4
            $number = (int) $number;
2825 4
            $this->array = $this->rest(-$number)->getArray();
2826
        }
2827
2828 12
        $this->generator = null;
2829
2830 12
        return $this;
2831
    }
2832
2833
    /**
2834
     * Count the values from the current array.
2835
     *
2836
     * alias: for "Arrayy->count()"
2837
     *
2838
     * @param int $mode
2839
     *
2840
     * @return int
2841
     *
2842
     * @see Arrayy::count()
2843
     */
2844 20
    public function length(int $mode = \COUNT_NORMAL): int
2845
    {
2846 20
        return $this->count($mode);
2847
    }
2848
2849
    /**
2850
     * Apply the given function to the every element of the array,
2851
     * collecting the results.
2852
     *
2853
     * @param callable $callable
2854
     * @param bool     $useKeyAsSecondParameter
2855
     * @param mixed    ...$arguments
2856
     *
2857
     * @return static
2858
     *                <p>(Immutable) Arrayy object with modified elements.</p>
2859
     */
2860 5
    public function map(callable $callable, bool $useKeyAsSecondParameter = false, ...$arguments)
2861
    {
2862 5
        $useArguments = \func_num_args() > 2;
2863
2864 5
        return static::create(
2865
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
2866 5
                foreach ($this->getGenerator() as $key => $value) {
2867 4
                    if ($useArguments) {
2868 3
                        if ($useKeyAsSecondParameter) {
2869
                            yield $key => $callable($value, $key, ...$arguments);
2870
                        } else {
2871 3
                            yield $key => $callable($value, ...$arguments);
2872
                        }
2873
                    } else {
2874
                        /** @noinspection NestedPositiveIfStatementsInspection */
2875 4
                        if ($useKeyAsSecondParameter) {
2876
                            yield $key => $callable($value, $key);
2877
                        } else {
2878 4
                            yield $key => $callable($value);
2879
                        }
2880
                    }
2881
                }
2882 5
            },
2883 5
            $this->iteratorClass,
2884 5
            false
2885
        );
2886
    }
2887
2888
    /**
2889
     * Check if all items in current array match a truth test.
2890
     *
2891
     * @param \Closure $closure
2892
     *
2893
     * @return bool
2894
     */
2895 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...
2896
    {
2897 15
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2898 2
            return false;
2899
        }
2900
2901 13
        foreach ($this->getGenerator() as $key => $value) {
2902 13
            $value = $closure($value, $key);
2903
2904 13
            if ($value === false) {
2905 7
                return false;
2906
            }
2907
        }
2908
2909 7
        return true;
2910
    }
2911
2912
    /**
2913
     * Check if any item in the current array matches a truth test.
2914
     *
2915
     * @param \Closure $closure
2916
     *
2917
     * @return bool
2918
     */
2919 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...
2920
    {
2921 14
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2922 2
            return false;
2923
        }
2924
2925 12
        foreach ($this->getGenerator() as $key => $value) {
2926 12
            $value = $closure($value, $key);
2927
2928 12
            if ($value === true) {
2929 9
                return true;
2930
            }
2931
        }
2932
2933 4
        return false;
2934
    }
2935
2936
    /**
2937
     * Get the max value from an array.
2938
     *
2939
     * @return mixed
2940
     */
2941 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...
2942
    {
2943 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2944 1
            return false;
2945
        }
2946
2947 9
        return \max($this->getArray());
2948
    }
2949
2950
    /**
2951
     * Merge the new $array into the current array.
2952
     *
2953
     * - keep key,value from the current array, also if the index is in the new $array
2954
     *
2955
     * @param array $array
2956
     * @param bool  $recursive
2957
     *
2958
     * @return static
2959
     *                <p>(Immutable)</p>
2960
     */
2961 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...
2962
    {
2963 25
        if ($recursive === true) {
2964 4
            $result = \array_replace_recursive($this->getArray(), $array);
2965
        } else {
2966 21
            $result = \array_replace($this->getArray(), $array);
2967
        }
2968
2969 25
        return static::create(
2970 25
            $result,
2971 25
            $this->iteratorClass,
2972 25
            false
2973
        );
2974
    }
2975
2976
    /**
2977
     * Merge the new $array into the current array.
2978
     *
2979
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2980
     * - create new indexes
2981
     *
2982
     * @param array $array
2983
     * @param bool  $recursive
2984
     *
2985
     * @return static
2986
     *                <p>(Immutable)</p>
2987
     */
2988 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...
2989
    {
2990 16
        if ($recursive === true) {
2991 4
            $result = \array_merge_recursive($this->getArray(), $array);
2992
        } else {
2993 12
            $result = \array_merge($this->getArray(), $array);
2994
        }
2995
2996 16
        return static::create(
2997 16
            $result,
2998 16
            $this->iteratorClass,
2999 16
            false
3000
        );
3001
    }
3002
3003
    /**
3004
     * Merge the the current array into the $array.
3005
     *
3006
     * - use key,value from the new $array, also if the index is in the current array
3007
     *
3008
     * @param array $array
3009
     * @param bool  $recursive
3010
     *
3011
     * @return static
3012
     *                <p>(Immutable)</p>
3013
     */
3014 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...
3015
    {
3016 16
        if ($recursive === true) {
3017 4
            $result = \array_replace_recursive($array, $this->getArray());
3018
        } else {
3019 12
            $result = \array_replace($array, $this->getArray());
3020
        }
3021
3022 16
        return static::create(
3023 16
            $result,
3024 16
            $this->iteratorClass,
3025 16
            false
3026
        );
3027
    }
3028
3029
    /**
3030
     * Merge the current array into the new $array.
3031
     *
3032
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
3033
     * - create new indexes
3034
     *
3035
     * @param array $array
3036
     * @param bool  $recursive
3037
     *
3038
     * @return static
3039
     *                <p>(Immutable)</p>
3040
     */
3041 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...
3042
    {
3043 17
        if ($recursive === true) {
3044 4
            $result = \array_merge_recursive($array, $this->getArray());
3045
        } else {
3046 13
            $result = \array_merge($array, $this->getArray());
3047
        }
3048
3049 17
        return static::create(
3050 17
            $result,
3051 17
            $this->iteratorClass,
3052 17
            false
3053
        );
3054
    }
3055
3056
    /**
3057
     * @return ArrayyMeta|static
3058
     */
3059 15
    public static function meta()
3060
    {
3061 15
        return (new ArrayyMeta())->getMetaObject(static::class);
3062
    }
3063
3064
    /**
3065
     * Get the min value from an array.
3066
     *
3067
     * @return mixed
3068
     */
3069 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...
3070
    {
3071 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
3072 1
            return false;
3073
        }
3074
3075 9
        return \min($this->getArray());
3076
    }
3077
3078
    /**
3079
     * Get the most used value from the array.
3080
     *
3081
     * @return mixed
3082
     *               <p>Return null if there wasn't a element.</p>
3083
     */
3084 3
    public function mostUsedValue()
3085
    {
3086 3
        return $this->countValues()->arsort()->firstKey();
3087
    }
3088
3089
    /**
3090
     * Get the most used value from the array.
3091
     *
3092
     * @param int|null $number <p>How many values you will take?</p>
3093
     *
3094
     * @return static
3095
     *                <p>(Immutable)</p>
3096
     */
3097 3
    public function mostUsedValues(int $number = null): self
3098
    {
3099 3
        return $this->countValues()->arsort()->firstsKeys($number);
3100
    }
3101
3102
    /**
3103
     * Move an array element to a new index.
3104
     *
3105
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
3106
     *
3107
     * @param int|string $from
3108
     * @param int        $to
3109
     *
3110
     * @return static
3111
     *                <p>(Immutable)</p>
3112
     */
3113 1
    public function moveElement($from, $to): self
3114
    {
3115 1
        $array = $this->getArray();
3116
3117 1
        if ((int) $from === $from) {
3118 1
            $tmp = \array_splice($array, $from, 1);
3119 1
            \array_splice($array, (int) $to, 0, $tmp);
3120 1
            $output = $array;
3121 1
        } elseif ((string) $from === $from) {
3122 1
            $indexToMove = \array_search($from, \array_keys($array), true);
3123 1
            $itemToMove = $array[$from];
3124 1
            if ($indexToMove !== false) {
3125 1
                \array_splice($array, $indexToMove, 1);
3126
            }
3127 1
            $i = 0;
3128 1
            $output = [];
3129 1
            foreach ($array as $key => $item) {
3130 1
                if ($i === $to) {
3131 1
                    $output[$from] = $itemToMove;
3132
                }
3133 1
                $output[$key] = $item;
3134 1
                ++$i;
3135
            }
3136
        } else {
3137
            $output = [];
3138
        }
3139
3140 1
        return static::create(
3141 1
            $output,
3142 1
            $this->iteratorClass,
3143 1
            false
3144
        );
3145
    }
3146
3147
    /**
3148
     * Move an array element to the first place.
3149
     *
3150
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3151
     *       loss the keys of an indexed array.
3152
     *
3153
     * @param int|string $key
3154
     *
3155
     * @return static
3156
     *                <p>(Immutable)</p>
3157
     */
3158 1 View Code Duplication
    public function moveElementToFirstPlace($key): 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...
3159
    {
3160 1
        $array = $this->getArray();
3161
3162 1
        if ($this->offsetExists($key)) {
3163 1
            $tmpValue = $this->get($key);
3164 1
            unset($array[$key]);
3165 1
            $array = [$key => $tmpValue] + $array;
3166
        }
3167
3168 1
        return static::create(
3169 1
            $array,
3170 1
            $this->iteratorClass,
3171 1
            false
3172
        );
3173
    }
3174
3175
    /**
3176
     * Move an array element to the last place.
3177
     *
3178
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3179
     *       loss the keys of an indexed array.
3180
     *
3181
     * @param int|string $key
3182
     *
3183
     * @return static
3184
     *                <p>(Immutable)</p>
3185
     */
3186 1 View Code Duplication
    public function moveElementToLastPlace($key): 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...
3187
    {
3188 1
        $array = $this->getArray();
3189
3190 1
        if ($this->offsetExists($key)) {
3191 1
            $tmpValue = $this->get($key);
3192 1
            unset($array[$key]);
3193 1
            $array += [$key => $tmpValue];
3194
        }
3195
3196 1
        return static::create(
3197 1
            $array,
3198 1
            $this->iteratorClass,
3199 1
            false
3200
        );
3201
    }
3202
3203
    /**
3204
     * Moves the internal iterator position to the next element and returns this element.
3205
     *
3206
     * @return mixed
3207
     */
3208
    public function next()
3209
    {
3210
        return \next($this->array);
3211
    }
3212
3213
    /**
3214
     * Get a subset of the items from the given array.
3215
     *
3216
     * @param mixed[] $keys
3217
     *
3218
     * @return static
3219
     *                <p>(Immutable)</p>
3220
     */
3221
    public function only(array $keys): self
3222
    {
3223
        $array = $this->getArray();
3224
3225
        return static::create(
3226
            \array_intersect_key($array, \array_flip($keys)),
3227
            $this->iteratorClass,
3228
            false
3229
        );
3230
    }
3231
3232
    /**
3233
     * Pad array to the specified size with a given value.
3234
     *
3235
     * @param int   $size  <p>Size of the result array.</p>
3236
     * @param mixed $value <p>Empty value by default.</p>
3237
     *
3238
     * @return static
3239
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
3240
     */
3241 5
    public function pad(int $size, $value): self
3242
    {
3243 5
        return static::create(
3244 5
            \array_pad($this->getArray(), $size, $value),
3245 5
            $this->iteratorClass,
3246 5
            false
3247
        );
3248
    }
3249
3250
    /**
3251
     * Partitions this array in two array according to a predicate.
3252
     * Keys are preserved in the resulting array.
3253
     *
3254
     * @param \Closure $closure
3255
     *                          <p>The predicate on which to partition.</p>
3256
     *
3257
     * @return array<int, static>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (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...
3258
     *                    <p>An array with two elements. The first element contains the array
3259
     *                    of elements where the predicate returned TRUE, the second element
3260
     *                    contains the array of elements where the predicate returned FALSE.</p>
3261
     */
3262
    public function partition(\Closure $closure): array
3263
    {
3264
        // init
3265
        $matches = [];
3266
        $noMatches = [];
3267
3268
        foreach ($this->array as $key => $element) {
3269
            if ($closure($key, $element)) {
3270
                $matches[$key] = $element;
3271
            } else {
3272
                $noMatches[$key] = $element;
3273
            }
3274
        }
3275
3276
        return [self::create($matches), self::create($noMatches)];
3277
    }
3278
3279
    /**
3280
     * Pop a specified value off the end of the current array.
3281
     *
3282
     * @return mixed
3283
     *               <p>(Mutable) The popped element from the current array.</p>
3284
     */
3285 5
    public function pop()
3286
    {
3287 5
        $this->generatorToArray();
3288
3289 5
        return \array_pop($this->array);
3290
    }
3291
3292
    /**
3293
     * Prepend a (key) + value to the current array.
3294
     *
3295
     * @param mixed $value
3296
     * @param mixed $key
3297
     *
3298
     * @return static
3299
     *                <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
3300
     */
3301 11
    public function prepend($value, $key = null)
3302
    {
3303 11
        $this->generatorToArray();
3304
3305 11
        if ($this->properties !== []) {
3306 3
            $this->checkType($key, $value);
3307
        }
3308
3309 9
        if ($key === null) {
3310 8
            \array_unshift($this->array, $value);
3311
        } else {
3312 2
            $this->array = [$key => $value] + $this->array;
3313
        }
3314
3315 9
        return $this;
3316
    }
3317
3318
    /**
3319
     * Add a suffix to each key.
3320
     *
3321
     * @param mixed $suffix
3322
     *
3323
     * @return static
3324
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
3325
     */
3326 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...
3327
    {
3328
        // init
3329 10
        $result = [];
3330
3331 10
        foreach ($this->getGenerator() as $key => $item) {
3332 9
            if ($item instanceof self) {
3333
                $result[$key] = $item->prependToEachKey($suffix);
3334 9
            } elseif (\is_array($item) === true) {
3335
                $result[$key] = self::create(
3336
                    $item,
3337
                    $this->iteratorClass,
3338
                    false
3339
                )->prependToEachKey($suffix)
3340
                    ->toArray();
3341
            } else {
3342 9
                $result[$key . $suffix] = $item;
3343
            }
3344
        }
3345
3346 10
        return self::create(
3347 10
            $result,
3348 10
            $this->iteratorClass,
3349 10
            false
3350
        );
3351
    }
3352
3353
    /**
3354
     * Add a suffix to each value.
3355
     *
3356
     * @param mixed $suffix
3357
     *
3358
     * @return static
3359
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
3360
     */
3361 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...
3362
    {
3363
        // init
3364 10
        $result = [];
3365
3366 10
        foreach ($this->getGenerator() as $key => $item) {
3367 9
            if ($item instanceof self) {
3368
                $result[$key] = $item->prependToEachValue($suffix);
3369 9
            } elseif (\is_array($item) === true) {
3370
                $result[$key] = self::create(
3371
                    $item,
3372
                    $this->iteratorClass,
3373
                    false
3374
                )->prependToEachValue($suffix)
3375
                    ->toArray();
3376 9
            } elseif (\is_object($item) === true) {
3377 1
                $result[$key] = $item;
3378
            } else {
3379 8
                $result[$key] = $item . $suffix;
3380
            }
3381
        }
3382
3383 10
        return self::create(
3384 10
            $result,
3385 10
            $this->iteratorClass,
3386 10
            false
3387
        );
3388
    }
3389
3390
    /**
3391
     * Return the value of a given key and
3392
     * delete the key.
3393
     *
3394
     * @param int|int[]|string|string[]|null $keyOrKeys
3395
     * @param mixed                          $fallback
3396
     *
3397
     * @return mixed
3398
     */
3399 1
    public function pull($keyOrKeys = null, $fallback = null)
3400
    {
3401 1
        if ($keyOrKeys === null) {
3402
            $array = $this->getArray();
3403
            $this->clear();
3404
3405
            return $array;
3406
        }
3407
3408 1
        if (\is_array($keyOrKeys) === true) {
3409 1
            $valueOrValues = [];
3410 1
            foreach ($keyOrKeys as $key) {
3411 1
                $valueOrValues[] = $this->get($key, $fallback);
3412 1
                $this->offsetUnset($key);
3413
            }
3414
        } else {
3415 1
            $valueOrValues = $this->get($keyOrKeys, $fallback);
3416 1
            $this->offsetUnset($keyOrKeys);
3417
        }
3418
3419 1
        return $valueOrValues;
3420
    }
3421
3422
    /**
3423
     * Push one or more values onto the end of array at once.
3424
     *
3425
     * @param array ...$args
3426
     *
3427
     * @return static
3428
     *                <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
3429
     *
3430
     * @noinspection ReturnTypeCanBeDeclaredInspection
3431
     */
3432 5
    public function push(...$args)
3433
    {
3434 5
        $this->generatorToArray();
3435
3436
        if (
3437 5
            $this->checkPropertyTypes
3438
            &&
3439 5
            $this->properties !== []
3440
        ) {
3441 1
            foreach ($args as $key => $value) {
3442 1
                $this->checkType($key, $value);
3443
            }
3444
        }
3445
3446 5
        \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...
3447
3448 5
        return $this;
3449
    }
3450
3451
    /**
3452
     * Get a random value from the current array.
3453
     *
3454
     * @param int|null $number <p>How many values you will take?</p>
3455
     *
3456
     * @return static
3457
     *                <p>(Immutable)</p>
3458
     */
3459 19
    public function randomImmutable(int $number = null): self
3460
    {
3461 19
        $this->generatorToArray();
3462
3463 19 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...
3464 1
            return static::create(
3465 1
                [],
3466 1
                $this->iteratorClass,
3467 1
                false
3468
            );
3469
        }
3470
3471 18 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...
3472
            /** @noinspection NonSecureArrayRandUsageInspection */
3473 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3474
3475 13
            return static::create(
3476 13
                $arrayRandValue,
3477 13
                $this->iteratorClass,
3478 13
                false
3479
            );
3480
        }
3481
3482 6
        $arrayTmp = $this->array;
3483
        /** @noinspection NonSecureShuffleUsageInspection */
3484 6
        \shuffle($arrayTmp);
3485
3486 6
        return static::create(
3487 6
            $arrayTmp,
3488 6
            $this->iteratorClass,
3489 6
            false
3490 6
        )->firstsImmutable($number);
3491
    }
3492
3493
    /**
3494
     * Pick a random key/index from the keys of this array.
3495
     *
3496
     * @throws \RangeException If array is empty
3497
     *
3498
     * @return mixed
3499
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
3500
     */
3501 4
    public function randomKey()
3502
    {
3503 4
        $result = $this->randomKeys(1);
3504
3505 4
        if (!isset($result[0])) {
3506
            $result[0] = null;
3507
        }
3508
3509 4
        return $result[0];
3510
    }
3511
3512
    /**
3513
     * Pick a given number of random keys/indexes out of this array.
3514
     *
3515
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
3516
     *
3517
     * @throws \RangeException If array is empty
3518
     *
3519
     * @return static
3520
     *                <p>(Immutable)</p>
3521
     */
3522 13
    public function randomKeys(int $number): self
3523
    {
3524 13
        $this->generatorToArray();
3525
3526 13
        $count = \count($this->array, \COUNT_NORMAL);
3527
3528 13
        if ($number === 0 || $number > $count) {
3529 2
            throw new \RangeException(
3530 2
                \sprintf(
3531 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
3532 2
                    $number,
3533 2
                    $count
3534
                )
3535
            );
3536
        }
3537
3538 11
        $result = (array) \array_rand($this->array, $number);
3539
3540 11
        return static::create(
3541 11
            $result,
3542 11
            $this->iteratorClass,
3543 11
            false
3544
        );
3545
    }
3546
3547
    /**
3548
     * Get a random value from the current array.
3549
     *
3550
     * @param int|null $number <p>How many values you will take?</p>
3551
     *
3552
     * @return static
3553
     *                <p>(Mutable)</p>
3554
     */
3555 17
    public function randomMutable(int $number = null): self
3556
    {
3557 17
        $this->generatorToArray();
3558
3559 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...
3560
            return static::create(
3561
                [],
3562
                $this->iteratorClass,
3563
                false
3564
            );
3565
        }
3566
3567 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...
3568
            /** @noinspection NonSecureArrayRandUsageInspection */
3569 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3570 7
            $this->array = $arrayRandValue;
3571
3572 7
            return $this;
3573
        }
3574
3575
        /** @noinspection NonSecureShuffleUsageInspection */
3576 11
        \shuffle($this->array);
3577
3578 11
        return $this->firstsMutable($number);
3579
    }
3580
3581
    /**
3582
     * Pick a random value from the values of this array.
3583
     *
3584
     * @return mixed
3585
     *               <p>Get a random value or null if there wasn't a value.</p>
3586
     */
3587 4
    public function randomValue()
3588
    {
3589 4
        $result = $this->randomImmutable();
3590
3591 4
        if (!isset($result[0])) {
3592
            $result[0] = null;
3593
        }
3594
3595 4
        return $result[0];
3596
    }
3597
3598
    /**
3599
     * Pick a given number of random values out of this array.
3600
     *
3601
     * @param int $number
3602
     *
3603
     * @return static
3604
     *                <p>(Mutable)</p>
3605
     */
3606 7
    public function randomValues(int $number): self
3607
    {
3608 7
        return $this->randomMutable($number);
3609
    }
3610
3611
    /**
3612
     * Get a random value from an array, with the ability to skew the results.
3613
     *
3614
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3615
     *
3616
     * @param array    $array
3617
     * @param int|null $number <p>How many values you will take?</p>
3618
     *
3619
     * @return static
3620
     *                <p>(Immutable)</p>
3621
     */
3622 9
    public function randomWeighted(array $array, int $number = null): self
3623
    {
3624
        // init
3625 9
        $options = [];
3626
3627 9
        foreach ($array as $option => $weight) {
3628 9
            if ($this->searchIndex($option) !== false) {
3629 2
                for ($i = 0; $i < $weight; ++$i) {
3630 1
                    $options[] = $option;
3631
                }
3632
            }
3633
        }
3634
3635 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3636
    }
3637
3638
    /**
3639
     * Reduce the current array via callable e.g. anonymous-function.
3640
     *
3641
     * @param callable $callable
3642
     * @param mixed    $init
3643
     *
3644
     * @return static
3645
     *                <p>(Immutable)</p>
3646
     */
3647 18
    public function reduce($callable, $init = []): self
3648
    {
3649 18
        if ($this->generator) {
3650 1
            $result = $init;
3651
3652 1
            foreach ($this->getGenerator() as $value) {
3653 1
                $result = $callable($result, $value);
3654
            }
3655
3656 1
            return static::create(
3657 1
                $result,
3658 1
                $this->iteratorClass,
3659 1
                false
3660
            );
3661
        }
3662
3663 18
        $result = \array_reduce($this->array, $callable, $init);
3664
3665 18
        if ($result === null) {
3666
            $this->array = [];
3667
        } else {
3668 18
            $this->array = (array) $result;
3669
        }
3670
3671 18
        return static::create(
3672 18
            $this->array,
3673 18
            $this->iteratorClass,
3674 18
            false
3675
        );
3676
    }
3677
3678
    /**
3679
     * @param bool $unique
3680
     *
3681
     * @return static
3682
     *                <p>(Immutable)</p>
3683
     */
3684 14
    public function reduce_dimension(bool $unique = true): self
3685
    {
3686
        // init
3687 14
        $result = [];
3688
3689 14
        foreach ($this->getGenerator() as $val) {
3690 12
            if (\is_array($val) === true) {
3691 5
                $result[] = (new static($val))->reduce_dimension($unique)->getArray();
3692
            } else {
3693 12
                $result[] = [$val];
3694
            }
3695
        }
3696
3697 14
        $result = $result === [] ? [] : \array_merge(...$result);
3698
3699 14
        $resultArrayy = new static($result);
3700
3701 14
        return $unique ? $resultArrayy->unique() : $resultArrayy;
3702
    }
3703
3704
    /**
3705
     * Create a numerically re-indexed Arrayy object.
3706
     *
3707
     * @return static
3708
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
3709
     */
3710 9
    public function reindex(): self
3711
    {
3712 9
        $this->generatorToArray();
3713
3714 9
        $this->array = \array_values($this->array);
3715
3716 9
        return $this;
3717
    }
3718
3719
    /**
3720
     * Return all items that fail the truth test.
3721
     *
3722
     * @param \Closure $closure
3723
     *
3724
     * @return static
3725
     *                <p>(Immutable)</p>
3726
     */
3727 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...
3728
    {
3729
        // init
3730 1
        $filtered = [];
3731
3732 1
        foreach ($this->getGenerator() as $key => $value) {
3733 1
            if (!$closure($value, $key)) {
3734 1
                $filtered[$key] = $value;
3735
            }
3736
        }
3737
3738 1
        return static::create(
3739 1
            $filtered,
3740 1
            $this->iteratorClass,
3741 1
            false
3742
        );
3743
    }
3744
3745
    /**
3746
     * Remove a value from the current array (optional using dot-notation).
3747
     *
3748
     * @param mixed $key
3749
     *
3750
     * @return static
3751
     *                <p>(Mutable)</p>
3752
     */
3753 18
    public function remove($key)
3754
    {
3755
        // recursive call
3756 18
        if (\is_array($key) === true) {
3757
            foreach ($key as $k) {
3758
                $this->internalRemove($k);
3759
            }
3760
3761
            return static::create(
3762
                $this->getArray(),
3763
                $this->iteratorClass,
3764
                false
3765
            );
3766
        }
3767
3768 18
        $this->internalRemove($key);
3769
3770 18
        return static::create(
3771 18
            $this->getArray(),
3772 18
            $this->iteratorClass,
3773 18
            false
3774
        );
3775
    }
3776
3777
    /**
3778
     * alias: for "Arrayy->removeValue()"
3779
     *
3780
     * @param mixed $element
3781
     *
3782
     * @return static
3783
     */
3784 8
    public function removeElement($element)
3785
    {
3786 8
        return $this->removeValue($element);
3787
    }
3788
3789
    /**
3790
     * Remove the first value from the current array.
3791
     *
3792
     * @return static
3793
     *                <p>(Immutable)</p>
3794
     */
3795 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...
3796
    {
3797 7
        $tmpArray = $this->getArray();
3798
3799 7
        \array_shift($tmpArray);
3800
3801 7
        return static::create(
3802 7
            $tmpArray,
3803 7
            $this->iteratorClass,
3804 7
            false
3805
        );
3806
    }
3807
3808
    /**
3809
     * Remove the last value from the current array.
3810
     *
3811
     * @return static
3812
     *                <p>(Immutable)</p>
3813
     */
3814 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...
3815
    {
3816 7
        $tmpArray = $this->getArray();
3817
3818 7
        \array_pop($tmpArray);
3819
3820 7
        return static::create(
3821 7
            $tmpArray,
3822 7
            $this->iteratorClass,
3823 7
            false
3824
        );
3825
    }
3826
3827
    /**
3828
     * Removes a particular value from an array (numeric or associative).
3829
     *
3830
     * @param mixed $value
3831
     *
3832
     * @return static
3833
     *                <p>(Immutable)</p>
3834
     */
3835 8
    public function removeValue($value): self
3836
    {
3837 8
        $this->generatorToArray();
3838
3839
        // init
3840 8
        $isSequentialArray = $this->isSequential();
3841
3842 8
        foreach ($this->array as $key => $item) {
3843 7
            if ($item === $value) {
3844 7
                unset($this->array[$key]);
3845
            }
3846
        }
3847
3848 8
        if ($isSequentialArray) {
3849 6
            $this->array = \array_values($this->array);
3850
        }
3851
3852 8
        return static::create(
3853 8
            $this->array,
3854 8
            $this->iteratorClass,
3855 8
            false
3856
        );
3857
    }
3858
3859
    /**
3860
     * Generate array of repeated arrays.
3861
     *
3862
     * @param int $times <p>How many times has to be repeated.</p>
3863
     *
3864
     * @return static
3865
     *                <p>(Immutable)</p>
3866
     */
3867 1
    public function repeat($times): self
3868
    {
3869 1
        if ($times === 0) {
3870 1
            return static::create([], $this->iteratorClass);
3871
        }
3872
3873 1
        return static::create(
3874 1
            \array_fill(0, (int) $times, $this->getArray()),
3875 1
            $this->iteratorClass,
3876 1
            false
3877
        );
3878
    }
3879
3880
    /**
3881
     * Replace a key with a new key/value pair.
3882
     *
3883
     * @param mixed $replace
3884
     * @param mixed $key
3885
     * @param mixed $value
3886
     *
3887
     * @return static
3888
     *                <p>(Immutable)</p>
3889
     */
3890 2
    public function replace($replace, $key, $value): self
3891
    {
3892 2
        $that = clone $this;
3893
3894 2
        return $that->remove($replace)
3895 2
            ->set($key, $value);
3896
    }
3897
3898
    /**
3899
     * Create an array using the current array as values and the other array as keys.
3900
     *
3901
     * @param array $keys <p>An array of keys.</p>
3902
     *
3903
     * @return static
3904
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
3905
     */
3906 2
    public function replaceAllKeys(array $keys): self
3907
    {
3908 2
        return static::create(
3909 2
            \array_combine($keys, $this->getArray()),
3910 2
            $this->iteratorClass,
3911 2
            false
3912
        );
3913
    }
3914
3915
    /**
3916
     * Create an array using the current array as keys and the other array as values.
3917
     *
3918
     * @param array $array <p>An array o values.</p>
3919
     *
3920
     * @return static
3921
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3922
     */
3923 2
    public function replaceAllValues(array $array): self
3924
    {
3925 2
        return static::create(
3926 2
            \array_combine($this->array, $array),
3927 2
            $this->iteratorClass,
3928 2
            false
3929
        );
3930
    }
3931
3932
    /**
3933
     * Replace the keys in an array with another set.
3934
     *
3935
     * @param array $keys <p>An array of keys matching the array's size</p>
3936
     *
3937
     * @return static
3938
     *                <p>(Immutable)</p>
3939
     */
3940 1
    public function replaceKeys(array $keys): self
3941
    {
3942 1
        $values = \array_values($this->getArray());
3943 1
        $result = \array_combine($keys, $values);
3944
3945 1
        return static::create(
3946 1
            $result,
3947 1
            $this->iteratorClass,
3948 1
            false
3949
        );
3950
    }
3951
3952
    /**
3953
     * Replace the first matched value in an array.
3954
     *
3955
     * @param mixed $search      <p>The value to replace.</p>
3956
     * @param mixed $replacement <p>The value to replace.</p>
3957
     *
3958
     * @return static
3959
     *                <p>(Immutable)</p>
3960
     */
3961 3
    public function replaceOneValue($search, $replacement = ''): self
3962
    {
3963 3
        $array = $this->getArray();
3964 3
        $key = \array_search($search, $array, true);
3965
3966 3
        if ($key !== false) {
3967 3
            $array[$key] = $replacement;
3968
        }
3969
3970 3
        return static::create(
3971 3
            $array,
3972 3
            $this->iteratorClass,
3973 3
            false
3974
        );
3975
    }
3976
3977
    /**
3978
     * Replace values in the current array.
3979
     *
3980
     * @param mixed $search      <p>The value to replace.</p>
3981
     * @param mixed $replacement <p>What to replace it with.</p>
3982
     *
3983
     * @return static
3984
     *                <p>(Immutable)</p>
3985
     */
3986 1
    public function replaceValues($search, $replacement = ''): self
3987
    {
3988 1
        return $this->each(
3989
            static function ($value) use ($search, $replacement) {
3990 1
                return \str_replace($search, $replacement, $value);
3991 1
            }
3992
        );
3993
    }
3994
3995
    /**
3996
     * Get the last elements from index $from until the end of this array.
3997
     *
3998
     * @param int $from
3999
     *
4000
     * @return static
4001
     *                <p>(Immutable)</p>
4002
     */
4003 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...
4004
    {
4005 15
        $tmpArray = $this->getArray();
4006
4007 15
        return static::create(
4008 15
            \array_splice($tmpArray, $from),
4009 15
            $this->iteratorClass,
4010 15
            false
4011
        );
4012
    }
4013
4014
    /**
4015
     * Return the array in the reverse order.
4016
     *
4017
     * @return static
4018
     *                <p>(Mutable) Return this Arrayy object.</p>
4019
     */
4020 9
    public function reverse(): self
4021
    {
4022 9
        $this->generatorToArray();
4023
4024 9
        $this->array = \array_reverse($this->array);
4025
4026 9
        return $this;
4027
    }
4028
4029
    /**
4030
     * Sort an array in reverse order.
4031
     *
4032
     * @param int $sort_flags [optional] <p>
4033
     *                        You may modify the behavior of the sort using the optional
4034
     *                        parameter sort_flags, for details
4035
     *                        see sort.
4036
     *                        </p>
4037
     *
4038
     * @return static
4039
     *                <p>(Mutable) Return this Arrayy object.</p>
4040
     */
4041 4
    public function rsort(int $sort_flags = 0): self
4042
    {
4043 4
        $this->generatorToArray();
4044
4045 4
        \rsort($this->array, $sort_flags);
4046
4047 4
        return $this;
4048
    }
4049
4050
    /**
4051
     * Search for the first index of the current array via $value.
4052
     *
4053
     * @param mixed $value
4054
     *
4055
     * @return false|float|int|string
4056
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
4057
     */
4058 21
    public function searchIndex($value)
4059
    {
4060 21
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
4061 20
            if ($value === $valueFromArray) {
4062 10
                return $keyFromArray;
4063
            }
4064
        }
4065
4066 11
        return false;
4067
    }
4068
4069
    /**
4070
     * Search for the value of the current array via $index.
4071
     *
4072
     * @param mixed $index
4073
     *
4074
     * @return static
4075
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
4076
     */
4077 9
    public function searchValue($index): self
4078
    {
4079 9
        $this->generatorToArray();
4080
4081
        // init
4082 9
        $return = [];
4083
4084 9
        if ($this->array === []) {
4085
            return static::create(
4086
                [],
4087
                $this->iteratorClass,
4088
                false
4089
            );
4090
        }
4091
4092
        // php cast "bool"-index into "int"-index
4093 9
        if ((bool) $index === $index) {
4094 1
            $index = (int) $index;
4095
        }
4096
4097 9
        if ($this->offsetExists($index)) {
4098 7
            $return = [$this->array[$index]];
4099
        }
4100
4101 9
        return static::create(
4102 9
            $return,
4103 9
            $this->iteratorClass,
4104 9
            false
4105
        );
4106
    }
4107
4108
    /**
4109
     * Set a value for the current array (optional using dot-notation).
4110
     *
4111
     * @param string $key   <p>The key to set.</p>
4112
     * @param mixed  $value <p>Its value.</p>
4113
     *
4114
     * @return static
4115
     *                <p>(Mutable)</p>
4116
     */
4117 18
    public function set($key, $value): self
4118
    {
4119 18
        $this->generatorToArray();
4120
4121 18
        $this->internalSet($key, $value);
4122
4123 18
        return $this;
4124
    }
4125
4126
    /**
4127
     * Get a value from a array and set it if it was not.
4128
     *
4129
     * WARNING: this method only set the value, if the $key is not already set
4130
     *
4131
     * @param mixed $key      <p>The key</p>
4132
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
4133
     *
4134
     * @return mixed
4135
     *               <p>(Mutable)</p>
4136
     */
4137 11
    public function setAndGet($key, $fallback = null)
4138
    {
4139 11
        $this->generatorToArray();
4140
4141
        // If the key doesn't exist, set it.
4142 11
        if (!$this->has($key)) {
4143 4
            $this->array = $this->set($key, $fallback)->getArray();
4144
        }
4145
4146 11
        return $this->get($key);
4147
    }
4148
4149
    /**
4150
     * Shifts a specified value off the beginning of array.
4151
     *
4152
     * @return mixed
4153
     *               <p>(Mutable) A shifted element from the current array.</p>
4154
     */
4155 5
    public function shift()
4156
    {
4157 5
        $this->generatorToArray();
4158
4159 5
        return \array_shift($this->array);
4160
    }
4161
4162
    /**
4163
     * Shuffle the current array.
4164
     *
4165
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
4166
     * @param array $array  [optional]
4167
     *
4168
     * @return static
4169
     *                <p>(Immutable)</p>
4170
     */
4171 2
    public function shuffle(bool $secure = false, array $array = null): self
4172
    {
4173 2
        if ($array === null) {
4174 2
            $array = $this->getArray();
4175
        }
4176
4177 2
        if ($secure !== true) {
4178
            /** @noinspection NonSecureShuffleUsageInspection */
4179 2
            \shuffle($array);
4180
        } else {
4181 1
            $size = \count($array, \COUNT_NORMAL);
4182 1
            $keys = \array_keys($array);
4183 1
            for ($i = $size - 1; $i > 0; --$i) {
4184
                try {
4185 1
                    $r = \random_int(0, $i);
4186
                } catch (\Exception $e) {
4187
                    /** @noinspection RandomApiMigrationInspection */
4188
                    $r = \mt_rand(0, $i);
4189
                }
4190 1
                if ($r !== $i) {
4191
                    $temp = $array[$keys[$r]];
4192
                    $array[$keys[$r]] = $array[$keys[$i]];
4193
                    $array[$keys[$i]] = $temp;
4194
                }
4195
            }
4196
4197
            // reset indices
4198 1
            $array = \array_values($array);
4199
        }
4200
4201 2
        foreach ($array as $key => $value) {
4202
            // check if recursive is needed
4203 2
            if (\is_array($value) === true) {
4204
                $array[$key] = $this->shuffle($secure, $value);
4205
            }
4206
        }
4207
4208 2
        return static::create(
4209 2
            $array,
4210 2
            $this->iteratorClass,
4211 2
            false
4212
        );
4213
    }
4214
4215
    /**
4216
     * Count the values from the current array.
4217
     *
4218
     * alias: for "Arrayy->count()"
4219
     *
4220
     * @param int $mode
4221
     *
4222
     * @return int
4223
     */
4224 20
    public function size(int $mode = \COUNT_NORMAL): int
4225
    {
4226 20
        return $this->count($mode);
4227
    }
4228
4229
    /**
4230
     * Checks whether array has exactly $size items.
4231
     *
4232
     * @param int $size
4233
     *
4234
     * @return bool
4235
     */
4236 1 View Code Duplication
    public function sizeIs(int $size): 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...
4237
    {
4238
        // init
4239 1
        $itemsTempCount = 0;
4240
4241 1
        foreach ($this->getGenerator() as $key => $value) {
4242 1
            ++$itemsTempCount;
4243 1
            if ($itemsTempCount > $size) {
4244 1
                return false;
4245
            }
4246
        }
4247
4248 1
        return $itemsTempCount === $size;
4249
    }
4250
4251
    /**
4252
     * Checks whether array has between $fromSize to $toSize items. $toSize can be
4253
     * smaller than $fromSize.
4254
     *
4255
     * @param int $fromSize
4256
     * @param int $toSize
4257
     *
4258
     * @return bool
4259
     */
4260 1
    public function sizeIsBetween(int $fromSize, int $toSize): bool
4261
    {
4262 1
        if ($fromSize > $toSize) {
4263 1
            $tmp = $toSize;
4264 1
            $toSize = $fromSize;
4265 1
            $fromSize = $tmp;
4266
        }
4267
4268
        // init
4269 1
        $itemsTempCount = 0;
4270
4271 1
        foreach ($this->getGenerator() as $key => $value) {
4272 1
            ++$itemsTempCount;
4273 1
            if ($itemsTempCount > $toSize) {
4274 1
                return false;
4275
            }
4276
        }
4277
4278 1
        return $fromSize < $itemsTempCount && $itemsTempCount < $toSize;
4279
    }
4280
4281
    /**
4282
     * Checks whether array has more than $size items.
4283
     *
4284
     * @param int $size
4285
     *
4286
     * @return bool
4287
     */
4288 1 View Code Duplication
    public function sizeIsGreaterThan(int $size): 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...
4289
    {
4290
        // init
4291 1
        $itemsTempCount = 0;
4292
4293 1
        foreach ($this->getGenerator() as $key => $value) {
4294 1
            ++$itemsTempCount;
4295 1
            if ($itemsTempCount > $size) {
4296 1
                return true;
4297
            }
4298
        }
4299
4300 1
        return $itemsTempCount > $size;
4301
    }
4302
4303
    /**
4304
     * Checks whether array has less than $size items.
4305
     *
4306
     * @param int $size
4307
     *
4308
     * @return bool
4309
     */
4310 1 View Code Duplication
    public function sizeIsLessThan(int $size): 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...
4311
    {
4312
        // init
4313 1
        $itemsTempCount = 0;
4314
4315 1
        foreach ($this->getGenerator() as $key => $value) {
4316 1
            ++$itemsTempCount;
4317 1
            if ($itemsTempCount > $size) {
4318 1
                return false;
4319
            }
4320
        }
4321
4322 1
        return $itemsTempCount < $size;
4323
    }
4324
4325
    /**
4326
     * Counts all elements in an array, or something in an object.
4327
     *
4328
     * <p>
4329
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
4330
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
4331
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
4332
     * implemented and used in PHP.
4333
     * </p>
4334
     *
4335
     * @return int
4336
     *             <p>
4337
     *             The number of elements in var, which is
4338
     *             typically an array, since anything else will have one
4339
     *             element.
4340
     *             </p>
4341
     *             <p>
4342
     *             If var is not an array or an object with
4343
     *             implemented Countable interface,
4344
     *             1 will be returned.
4345
     *             There is one exception, if var is &null;,
4346
     *             0 will be returned.
4347
     *             </p>
4348
     *             <p>
4349
     *             Caution: count may return 0 for a variable that isn't set,
4350
     *             but it may also return 0 for a variable that has been initialized with an
4351
     *             empty array. Use isset to test if a variable is set.
4352
     *             </p>
4353
     */
4354 10
    public function sizeRecursive(): int
4355
    {
4356 10
        return \count($this->getArray(), \COUNT_RECURSIVE);
4357
    }
4358
4359
    /**
4360
     * Extract a slice of the array.
4361
     *
4362
     * @param int      $offset       <p>Slice begin index.</p>
4363
     * @param int|null $length       <p>Length of the slice.</p>
4364
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
4365
     *
4366
     * @return static
4367
     *                <p>A slice of the original array with length $length.</p>
4368
     */
4369 5
    public function slice(int $offset, int $length = null, bool $preserveKeys = false)
4370
    {
4371 5
        return static::create(
4372 5
            \array_slice(
4373 5
                $this->getArray(),
4374 5
                $offset,
4375 5
                $length,
4376 5
                $preserveKeys
4377
            ),
4378 5
            $this->iteratorClass,
4379 5
            false
4380
        );
4381
    }
4382
4383
    /**
4384
     * Sort the current array and optional you can keep the keys.
4385
     *
4386
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4387
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
4388
     *                              <strong>SORT_NATURAL</strong></p>
4389
     * @param bool       $keepKeys
4390
     *
4391
     * @return static
4392
     *                <p>(Mutable) Return this Arrayy object.</p>
4393
     */
4394 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4395
    {
4396 20
        $this->generatorToArray();
4397
4398 20
        return $this->sorting(
4399 20
            $this->array,
4400 20
            $direction,
4401 20
            $strategy,
4402 20
            $keepKeys
4403
        );
4404
    }
4405
4406
    /**
4407
     * Sort the current array by key.
4408
     *
4409
     * @see http://php.net/manual/en/function.ksort.php
4410
     * @see http://php.net/manual/en/function.krsort.php
4411
     *
4412
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4413
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4414
     *                              <strong>SORT_NATURAL</strong></p>
4415
     *
4416
     * @return static
4417
     *                <p>(Mutable) Return this Arrayy object.</p>
4418
     */
4419 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4420
    {
4421 18
        $this->generatorToArray();
4422
4423 18
        $this->sorterKeys($this->array, $direction, $strategy);
4424
4425 18
        return $this;
4426
    }
4427
4428
    /**
4429
     * Sort the current array by value.
4430
     *
4431
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4432
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4433
     *                              <strong>SORT_NATURAL</strong></p>
4434
     *
4435
     * @return static
4436
     *                <p>(Mutable)</p>
4437
     */
4438 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4439
    {
4440 1
        return $this->sort($direction, $strategy, true);
4441
    }
4442
4443
    /**
4444
     * Sort the current array by value.
4445
     *
4446
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4447
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4448
     *                              <strong>SORT_NATURAL</strong></p>
4449
     *
4450
     * @return static
4451
     *                <p>(Mutable)</p>
4452
     */
4453 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4454
    {
4455 1
        return $this->sort($direction, $strategy, false);
4456
    }
4457
4458
    /**
4459
     * Sort a array by value, by a closure or by a property.
4460
     *
4461
     * - If the sorter is null, the array is sorted naturally.
4462
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
4463
     *
4464
     * @param callable|string|null $sorter
4465
     * @param int|string           $direction <p>use <strong>SORT_ASC</strong> (default) or
4466
     *                                        <strong>SORT_DESC</strong></p>
4467
     * @param int                  $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4468
     *                                        <strong>SORT_NATURAL</strong></p>
4469
     *
4470
     * @return static
4471
     *                <p>(Immutable)</p>
4472
     */
4473 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4474
    {
4475 1
        $array = $this->getArray();
4476 1
        $direction = $this->getDirection($direction);
4477
4478
        // Transform all values into their results.
4479 1
        if ($sorter) {
4480 1
            $arrayy = static::create(
4481 1
                $array,
4482 1
                $this->iteratorClass,
4483 1
                false
4484
            );
4485
4486 1
            $results = $arrayy->each(
4487
                function ($value) use ($sorter) {
4488 1
                    if (\is_callable($sorter) === true) {
4489 1
                        return $sorter($value);
4490
                    }
4491
4492 1
                    return $this->get($sorter);
4493 1
                }
4494
            );
4495
4496 1
            $results = $results->getArray();
4497
        } else {
4498 1
            $results = $array;
4499
        }
4500
4501
        // Sort by the results and replace by original values
4502 1
        \array_multisort($results, $direction, $strategy, $array);
4503
4504 1
        return static::create(
4505 1
            $array,
4506 1
            $this->iteratorClass,
4507 1
            false
4508
        );
4509
    }
4510
4511
    /**
4512
     * @param int      $offset
4513
     * @param int|null $length
4514
     * @param array    $replacement
4515
     *
4516
     * @return static
4517
     *                <p>(Immutable)</p>
4518
     */
4519 1
    public function splice(int $offset, int $length = null, $replacement = []): self
4520
    {
4521 1
        $tmpArray = $this->getArray();
4522
4523 1
        \array_splice($tmpArray, $offset, $length ?? $this->count(), $replacement);
4524
4525 1
        return static::create(
4526 1
            $tmpArray,
4527 1
            $this->iteratorClass,
4528 1
            false
4529
        );
4530
    }
4531
4532
    /**
4533
     * Split an array in the given amount of pieces.
4534
     *
4535
     * @param int  $numberOfPieces
4536
     * @param bool $keepKeys
4537
     *
4538
     * @return static
4539
     *                <p>(Immutable)</p>
4540
     */
4541 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
4542
    {
4543 1
        $this->generatorToArray();
4544
4545 1
        $arrayCount = \count($this->array, \COUNT_NORMAL);
4546
4547 1
        if ($arrayCount === 0) {
4548 1
            $result = [];
4549
        } else {
4550 1
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
4551 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
4552
        }
4553
4554 1
        return static::create(
4555 1
            $result,
4556 1
            $this->iteratorClass,
4557 1
            false
4558
        );
4559
    }
4560
4561
    /**
4562
     * Stripe all empty items.
4563
     *
4564
     * @return static
4565
     *                <p>(Immutable)</p>
4566
     */
4567 1
    public function stripEmpty(): self
4568
    {
4569 1
        return $this->filter(
4570
            static function ($item) {
4571 1
                if ($item === null) {
4572 1
                    return false;
4573
                }
4574
4575 1
                return (bool) \trim((string) $item);
4576 1
            }
4577
        );
4578
    }
4579
4580
    /**
4581
     * Swap two values between positions by key.
4582
     *
4583
     * @param int|string $swapA <p>a key in the array</p>
4584
     * @param int|string $swapB <p>a key in the array</p>
4585
     *
4586
     * @return static
4587
     *                <p>(Immutable)</p>
4588
     */
4589 1
    public function swap($swapA, $swapB): self
4590
    {
4591 1
        $array = $this->getArray();
4592
4593 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
4594
4595 1
        return static::create(
4596 1
            $array,
4597 1
            $this->iteratorClass,
4598 1
            false
4599
        );
4600
    }
4601
4602
    /**
4603
     * alias: for "Arrayy->getArray()"
4604
     *
4605
     * @param bool $convertAllArrayyElements
4606
     *
4607
     * @return array
4608
     *
4609
     * @see Arrayy::getArray()
4610
     */
4611 237
    public function toArray(bool $convertAllArrayyElements = false): array
4612
    {
4613 237
        return $this->getArray($convertAllArrayyElements);
4614
    }
4615
4616
    /**
4617
     * Convert the current array to JSON.
4618
     *
4619
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
4620
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
4621
     *
4622
     * @return string
4623
     */
4624 7
    public function toJson(int $options = 0, int $depth = 512): string
4625
    {
4626 7
        $return = \json_encode($this->getArray(), $options, $depth);
4627 7
        if ($return === false) {
4628
            return '';
4629
        }
4630
4631 7
        return $return;
4632
    }
4633
4634
    /**
4635
     * Implodes array to a string with specified separator.
4636
     *
4637
     * @param string $separator [optional] <p>The element's separator.</p>
4638
     *
4639
     * @return string
4640
     *                <p>The string representation of array, separated by ",".</p>
4641
     */
4642 19
    public function toString(string $separator = ','): string
4643
    {
4644 19
        return $this->implode($separator);
4645
    }
4646
4647
    /**
4648
     * Return a duplicate free copy of the current array.
4649
     *
4650
     * @return static
4651
     *                <p>(Mutable)</p>
4652
     */
4653 13
    public function unique(): self
4654
    {
4655
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
4656
4657 13
        $this->array = $this->reduce(
4658
            static function ($resultArray, $value) {
4659 12
                if (!\in_array($value, $resultArray, true)) {
4660 12
                    $resultArray[] = $value;
4661
                }
4662
4663 12
                return $resultArray;
4664 13
            },
4665 13
            []
4666 13
        )->getArray();
4667 13
        $this->generator = null;
4668
4669 13
        return $this;
4670
    }
4671
4672
    /**
4673
     * Return a duplicate free copy of the current array. (with the old keys)
4674
     *
4675
     * @return static
4676
     *                <p>(Mutable)</p>
4677
     */
4678 11
    public function uniqueKeepIndex(): self
4679
    {
4680
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
4681
4682
        // init
4683 11
        $array = $this->getArray();
4684
4685 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...
4686 11
            \array_keys($array),
4687
            static function ($resultArray, $key) use ($array) {
4688 10
                if (!\in_array($array[$key], $resultArray, true)) {
4689 10
                    $resultArray[$key] = $array[$key];
4690
                }
4691
4692 10
                return $resultArray;
4693 11
            },
4694 11
            []
4695
        );
4696 11
        $this->generator = null;
4697
4698 11
        if ($this->array === null) {
4699
            $this->array = [];
4700
        } else {
4701 11
            $this->array = (array) $this->array;
4702
        }
4703
4704 11
        return $this;
4705
    }
4706
4707
    /**
4708
     * alias: for "Arrayy->unique()"
4709
     *
4710
     * @return static
4711
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
4712
     *
4713
     * @see Arrayy::unique()
4714
     */
4715 10
    public function uniqueNewIndex(): self
4716
    {
4717 10
        return $this->unique();
4718
    }
4719
4720
    /**
4721
     * Prepends one or more values to the beginning of array at once.
4722
     *
4723
     * @param array ...$args
4724
     *
4725
     * @return static
4726
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
4727
     */
4728 4
    public function unshift(...$args): self
4729
    {
4730 4
        $this->generatorToArray();
4731
4732 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...
4733
4734 4
        return $this;
4735
    }
4736
4737
    /**
4738
     * Get all values from a array.
4739
     *
4740
     * @return static
4741
     *                <p>(Immutable)</p>
4742
     */
4743 2
    public function values(): self
4744
    {
4745 2
        return static::create(
4746
            function () {
4747
                /** @noinspection YieldFromCanBeUsedInspection */
4748 2
                foreach ($this->getGenerator() as $value) {
4749 2
                    yield $value;
4750
                }
4751 2
            },
4752 2
            $this->iteratorClass,
4753 2
            false
4754
        );
4755
    }
4756
4757
    /**
4758
     * Apply the given function to every element in the array, discarding the results.
4759
     *
4760
     * @param callable $callable
4761
     * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
4762
     *
4763
     * @return static
4764
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
4765
     */
4766 12
    public function walk($callable, bool $recursive = false): self
4767
    {
4768 12
        $this->generatorToArray();
4769
4770 12
        if ($recursive === true) {
4771 6
            \array_walk_recursive($this->array, $callable);
4772
        } else {
4773 6
            \array_walk($this->array, $callable);
4774
        }
4775
4776 12
        return $this;
4777
    }
4778
4779
    /**
4780
     * Returns a collection of matching items.
4781
     *
4782
     * @param string $keyOrPropertyOrMethod the property or method to evaluate
4783
     * @param mixed  $value                 the value to match
4784
     *
4785
     * @throws \InvalidArgumentException if property or method is not defined
4786
     *
4787
     * @return static
4788
     *
4789
     * @psalm-return static<T>
4790
     */
4791 1
    public function where(string $keyOrPropertyOrMethod, $value): self
4792
    {
4793 1
        return $this->filter(
4794
            function ($item) use ($keyOrPropertyOrMethod, $value) {
4795 1
                $accessorValue = $this->extractValue(
4796 1
                    $item,
4797 1
                    $keyOrPropertyOrMethod
4798
                );
4799
4800 1
                return $accessorValue === $value;
4801 1
            }
4802
        );
4803
    }
4804
4805
    /**
4806
     * Convert an array into a object.
4807
     *
4808
     * @param array $array PHP array
4809
     *
4810
     * @return \stdClass
4811
     */
4812 4
    final protected static function arrayToObject(array $array = []): \stdClass
4813
    {
4814
        // init
4815 4
        $object = new \stdClass();
4816
4817 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
4818 1
            return $object;
4819
        }
4820
4821 3
        foreach ($array as $name => $value) {
4822 3
            if (\is_array($value) === true) {
4823 1
                $object->{$name} = static::arrayToObject($value);
4824
            } else {
4825 3
                $object->{$name} = $value;
4826
            }
4827
        }
4828
4829 3
        return $object;
4830
    }
4831
4832
    /**
4833
     * @param array|\Generator|null $input         <p>
4834
     *                                             An array containing keys to return.
4835
     *                                             </p>
4836
     * @param mixed|null            $search_values [optional] <p>
4837
     *                                             If specified, then only keys containing these values are returned.
4838
     *                                             </p>
4839
     * @param bool                  $strict        [optional] <p>
4840
     *                                             Determines if strict comparison (===) should be used during the
4841
     *                                             search.
4842
     *                                             </p>
4843
     *
4844
     * @return array
4845
     *               <p>an array of all the keys in input</p>
4846
     */
4847 11
    protected function array_keys_recursive(
4848
        $input = null,
4849
        $search_values = null,
4850
        bool $strict = true
4851
    ): array {
4852
        // init
4853 11
        $keys = [];
4854 11
        $keysTmp = [];
4855
4856 11
        if ($input === null) {
4857 4
            $input = $this->getGenerator();
4858
        }
4859
4860 11
        if ($search_values === null) {
4861 11
            foreach ($input as $key => $value) {
4862 11
                $keys[] = $key;
4863
4864
                // check if recursive is needed
4865 11
                if (\is_array($value) === true) {
4866 4
                    $keysTmp[] = $this->array_keys_recursive($value);
4867
                }
4868
            }
4869
        } else {
4870 1
            $is_array_tmp = \is_array($search_values);
4871
4872 1
            foreach ($input as $key => $value) {
4873 View Code Duplication
                if (
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...
4874
                    (
4875 1
                        $is_array_tmp === false
4876
                        &&
4877 1
                        $strict === true
4878
                        &&
4879 1
                        $search_values === $value
4880
                    )
4881
                    ||
4882
                    (
4883 1
                        $is_array_tmp === false
4884
                        &&
4885 1
                        $strict === false
4886
                        &&
4887 1
                        $search_values == $value
4888
                    )
4889
                    ||
4890
                    (
4891 1
                        $is_array_tmp === true
4892
                        &&
4893 1
                        \in_array($value, $search_values, $strict)
4894
                    )
4895
                ) {
4896 1
                    $keys[] = $key;
4897
                }
4898
4899
                // check if recursive is needed
4900 1
                if (\is_array($value) === true) {
4901 1
                    $keysTmp[] = $this->array_keys_recursive($value);
4902
                }
4903
            }
4904
        }
4905
4906 11
        return $keysTmp === [] ? $keys : \array_merge($keys, ...$keysTmp);
4907
    }
4908
4909
    /**
4910
     * @param mixed      $path
4911
     * @param callable   $callable
4912
     * @param array|null $currentOffset
4913
     *
4914
     * @return void
4915
     */
4916 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
4917
    {
4918 4
        $this->generatorToArray();
4919
4920 4
        if ($currentOffset === null) {
4921 4
            $currentOffset = &$this->array;
4922
        }
4923
4924 4
        $explodedPath = \explode($this->pathSeparator, $path);
4925 4
        if ($explodedPath === false) {
4926
            return;
4927
        }
4928
4929 4
        $nextPath = \array_shift($explodedPath);
4930
4931 4
        if (!isset($currentOffset[$nextPath])) {
4932
            return;
4933
        }
4934
4935 4
        if (!empty($explodedPath)) {
4936 1
            $this->callAtPath(
4937 1
                \implode($this->pathSeparator, $explodedPath),
4938 1
                $callable,
4939 1
                $currentOffset[$nextPath]
4940
            );
4941
        } else {
4942 4
            $callable($currentOffset[$nextPath]);
4943
        }
4944 4
    }
4945
4946
    /**
4947
     * create a fallback for array
4948
     *
4949
     * 1. use the current array, if it's a array
4950
     * 2. fallback to empty array, if there is nothing
4951
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
4952
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
4953
     * 5. call "__toArray()" on object, if the method exists
4954
     * 6. cast a string or object with "__toString()" into an array
4955
     * 7. throw a "InvalidArgumentException"-Exception
4956
     *
4957
     * @param mixed $data
4958
     *
4959
     * @throws \InvalidArgumentException
4960
     *
4961
     * @return array
4962
     */
4963 1053
    protected function fallbackForArray(&$data): array
4964
    {
4965 1053
        $data = $this->internalGetArray($data);
4966
4967 1053
        if ($data === null) {
4968 2
            throw new \InvalidArgumentException('Passed value should be a array');
4969
        }
4970
4971 1051
        return $data;
4972
    }
4973
4974
    /**
4975
     * @return bool
4976
     *
4977
     * @noinspection ReturnTypeCanBeDeclaredInspection
4978
     */
4979 970
    protected function generatorToArray()
4980
    {
4981 970
        if ($this->generator) {
4982 2
            $this->array = $this->getArray();
4983 2
            $this->generator = null;
4984
4985 2
            return true;
4986
        }
4987
4988 970
        return false;
4989
    }
4990
4991
    /**
4992
     * Get correct PHP constant for direction.
4993
     *
4994
     * @param int|string $direction
4995
     *
4996
     * @return int
4997
     */
4998 39
    protected function getDirection($direction): int
4999
    {
5000 39
        if ((string) $direction === $direction) {
5001 10
            $direction = \strtolower($direction);
5002
5003 10
            if ($direction === 'desc') {
5004 2
                $direction = \SORT_DESC;
5005
            } else {
5006 8
                $direction = \SORT_ASC;
5007
            }
5008
        }
5009
5010
        if (
5011 39
            $direction !== \SORT_DESC
5012
            &&
5013 39
            $direction !== \SORT_ASC
5014
        ) {
5015
            $direction = \SORT_ASC;
5016
        }
5017
5018 39
        return $direction;
5019
    }
5020
5021
    /**
5022
     * @return TypeCheckPhpDoc[]
5023
     *
5024
     * @noinspection ReturnTypeCanBeDeclaredInspection
5025
     */
5026 16
    protected function getPropertiesFromPhpDoc()
5027
    {
5028 16
        static $PROPERTY_CACHE = [];
5029 16
        $cacheKey = 'Class::' . static::class;
5030
5031 16
        if (isset($PROPERTY_CACHE[$cacheKey])) {
5032 15
            return $PROPERTY_CACHE[$cacheKey];
5033
        }
5034
5035
        // init
5036 2
        $properties = [];
5037
5038 2
        $reflector = new \ReflectionClass($this);
5039 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
5040 2
        $docComment = $reflector->getDocComment();
5041 2
        if ($docComment) {
5042 2
            $docblock = $factory->create($docComment);
5043
            /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
5044 2
            foreach ($docblock->getTagsByName('property') as $tag) {
5045 2
                $properties[$tag->getVariableName()] = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag);
5046
            }
5047
        }
5048
5049 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
5050
    }
5051
5052
    /**
5053
     * @param mixed $glue
5054
     * @param mixed $pieces
5055
     * @param bool  $useKeys
5056
     *
5057
     * @return string
5058
     */
5059 36
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
5060
    {
5061 36
        if ($pieces instanceof self) {
5062 1
            $pieces = $pieces->getArray();
5063
        }
5064
5065 36
        if (\is_array($pieces) === true) {
5066 36
            $pieces_count = \count($pieces, \COUNT_NORMAL);
5067 36
            $pieces_count_not_zero = $pieces_count > 0;
5068
5069 36
            return \implode(
5070 36
                $glue,
5071 36
                \array_map(
5072 36
                    [$this, 'implode_recursive'],
5073 36
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
5074 36
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
5075
                )
5076
            );
5077
        }
5078
5079
        if (
5080 36
            \is_scalar($pieces) === true
5081
            ||
5082 36
            (\is_object($pieces) && \method_exists($pieces, '__toString'))
5083
        ) {
5084 32
            return (string) $pieces;
5085
        }
5086
5087 8
        return '';
5088
    }
5089
5090
    /**
5091
     * @param mixed                 $needle   <p>
5092
     *                                        The searched value.
5093
     *                                        </p>
5094
     *                                        <p>
5095
     *                                        If needle is a string, the comparison is done
5096
     *                                        in a case-sensitive manner.
5097
     *                                        </p>
5098
     * @param array|\Generator|null $haystack <p>
5099
     *                                        The array.
5100
     *                                        </p>
5101
     * @param bool                  $strict   [optional] <p>
5102
     *                                        If the third parameter strict is set to true
5103
     *                                        then the in_array function will also check the
5104
     *                                        types of the
5105
     *                                        needle in the haystack.
5106
     *                                        </p>
5107
     *
5108
     * @return bool
5109
     *              <p>true if needle is found in the array, false otherwise</p>
5110
     */
5111 18
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
5112
    {
5113 18
        if ($haystack === null) {
5114
            $haystack = $this->getGenerator();
5115
        }
5116
5117 18
        foreach ($haystack as $item) {
5118 14
            if (\is_array($item) === true) {
5119 3
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
5120
            } else {
5121
                /** @noinspection NestedPositiveIfStatementsInspection */
5122 14
                if ($strict === true) {
5123 14
                    $returnTmp = $item === $needle;
5124
                } else {
5125
                    $returnTmp = $item == $needle;
5126
                }
5127
            }
5128
5129 14
            if ($returnTmp === true) {
5130 10
                return true;
5131
            }
5132
        }
5133
5134 8
        return false;
5135
    }
5136
5137
    /**
5138
     * @param mixed $data
5139
     *
5140
     * @return array|null
5141
     */
5142 1053
    protected function internalGetArray(&$data)
5143
    {
5144 1053
        if (\is_array($data) === true) {
5145 1050
            return $data;
5146
        }
5147
5148 51
        if (!$data) {
5149 6
            return [];
5150
        }
5151
5152 50
        if (\is_object($data) === true) {
5153 45
            if ($data instanceof \ArrayObject) {
5154 4
                return $data->getArrayCopy();
5155
            }
5156
5157 42
            if ($data instanceof \Generator) {
5158
                return static::createFromGeneratorImmutable($data)->getArray();
5159
            }
5160
5161 42
            if ($data instanceof \Traversable) {
5162
                return static::createFromObject($data)->getArray();
5163
            }
5164
5165 42
            if ($data 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...
5166
                return (array) $data->jsonSerialize();
5167
            }
5168
5169 42
            if (\method_exists($data, '__toArray')) {
5170
                return (array) $data->__toArray();
5171
            }
5172
5173 42
            if (\method_exists($data, '__toString')) {
5174
                return [(string) $data];
5175
            }
5176
        }
5177
5178 47
        if (\is_callable($data)) {
5179 40
            $this->generator = new ArrayyRewindableGenerator($data);
5180
5181 40
            return [];
5182
        }
5183
5184 9
        if (\is_scalar($data)) {
5185 7
            return [$data];
5186
        }
5187
5188 2
        return null;
5189
    }
5190
5191
    /**
5192
     * Internal mechanics of remove method.
5193
     *
5194
     * @param mixed $key
5195
     *
5196
     * @return bool
5197
     */
5198 18
    protected function internalRemove($key): bool
5199
    {
5200 18
        $this->generatorToArray();
5201
5202
        if (
5203 18
            $this->pathSeparator
5204
            &&
5205 18
            (string) $key === $key
5206
            &&
5207 18
            \strpos($key, $this->pathSeparator) !== false
5208
        ) {
5209
            $path = \explode($this->pathSeparator, (string) $key);
5210
5211
            if ($path !== false) {
5212
                // crawl though the keys
5213
                while (\count($path, \COUNT_NORMAL) > 1) {
5214
                    $key = \array_shift($path);
5215
5216
                    if (!$this->has($key)) {
5217
                        return false;
5218
                    }
5219
5220
                    $this->array = &$this->array[$key];
5221
                }
5222
5223
                $key = \array_shift($path);
5224
            }
5225
        }
5226
5227 18
        unset($this->array[$key]);
5228
5229 18
        return true;
5230
    }
5231
5232
    /**
5233
     * Internal mechanic of set method.
5234
     *
5235
     * @param int|string|null $key
5236
     * @param mixed           $value
5237
     * @param bool            $checkProperties
5238
     *
5239
     * @return bool
5240
     */
5241 927
    protected function internalSet(
5242
        $key,
5243
        &$value,
5244
        bool $checkProperties = true
5245
    ): bool {
5246
        if (
5247 927
            $checkProperties === true
5248
            &&
5249 927
            $this->properties !== []
5250
        ) {
5251 84
            $this->checkType($key, $value);
5252
        }
5253
5254 925
        if ($key === null) {
5255
            return false;
5256
        }
5257
5258 925
        $this->generatorToArray();
5259
5260 925
        $array = &$this->array;
5261
5262
        if (
5263 925
            $this->pathSeparator
5264
            &&
5265 925
            (string) $key === $key
5266
            &&
5267 925
            \strpos($key, $this->pathSeparator) !== false
5268
        ) {
5269 3
            $path = \explode($this->pathSeparator, (string) $key);
5270
5271 3
            if ($path !== false) {
5272
                // crawl through the keys
5273 3
                while (\count($path, \COUNT_NORMAL) > 1) {
5274 3
                    $key = \array_shift($path);
5275
5276 3
                    $array = &$array[$key];
5277
                }
5278
5279 3
                $key = \array_shift($path);
5280
            }
5281
        }
5282
5283 925
        $array[$key] = $value;
5284
5285 925
        return true;
5286
    }
5287
5288
    /**
5289
     * Convert a object into an array.
5290
     *
5291
     * @param object $object
5292
     *
5293
     * @return mixed
5294
     */
5295 5
    protected static function objectToArray($object)
5296
    {
5297 5
        if (!\is_object($object)) {
5298 4
            return $object;
5299
        }
5300
5301 5
        if (\is_object($object)) {
5302 5
            $object = \get_object_vars($object);
5303
        }
5304
5305 5
        return \array_map(['static', 'objectToArray'], $object);
5306
    }
5307
5308
    /**
5309
     * @param array $data
5310
     * @param bool  $checkPropertiesInConstructor
5311
     *
5312
     * @return void
5313
     */
5314 1051
    protected function setInitialValuesAndProperties(array &$data, bool $checkPropertiesInConstructor)
5315
    {
5316 1051
        $checkPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
5317
                                        &&
5318 1051
                                        $checkPropertiesInConstructor === true;
5319
5320 1051
        if ($this->properties !== []) {
5321 75
            foreach ($data as $key => &$valueInner) {
5322 75
                $this->internalSet(
5323 75
                    $key,
5324 75
                    $valueInner,
5325 75
                    $checkPropertiesInConstructor
5326
                );
5327
            }
5328
        } else {
5329
            if (
5330 987
                $this->checkPropertyTypes === true
5331
                ||
5332 987
                $checkPropertiesInConstructor === true
5333
            ) {
5334 16
                $this->properties = $this->getPropertiesFromPhpDoc();
5335
            }
5336
5337
            if (
5338 987
                $this->checkPropertiesMismatchInConstructor === true
5339
                &&
5340 987
                \count($data) !== 0
5341
                &&
5342 987
                \count(\array_diff_key($this->properties, $data)) > 0
5343
            ) {
5344 1
                throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($this->properties), true));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'Property mismatch - inp...his->properties), true).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
5345
            }
5346
5347 986
            foreach ($data as $key => &$valueInner) {
5348 856
                $this->internalSet(
5349 856
                    $key,
5350 856
                    $valueInner,
5351 856
                    $checkPropertiesInConstructor
5352
                );
5353
            }
5354
        }
5355 1044
    }
5356
5357
    /**
5358
     * sorting keys
5359
     *
5360
     * @param array      $elements
5361
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5362
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5363
     *                              <strong>SORT_NATURAL</strong></p>
5364
     *
5365
     * @return static
5366
     *                <p>(Mutable) Return this Arrayy object.</p>
5367
     */
5368 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
5369
    {
5370 18
        $direction = $this->getDirection($direction);
5371
5372 18
        switch ($direction) {
5373 18
            case 'desc':
5374
            case \SORT_DESC:
5375 6
                \krsort($elements, $strategy);
5376
5377 6
                break;
5378 13
            case 'asc':
5379 13
            case \SORT_ASC:
5380
            default:
5381 13
                \ksort($elements, $strategy);
5382
        }
5383
5384 18
        return $this;
5385
    }
5386
5387
    /**
5388
     * @param array      $elements  <p>Warning: used as reference</p>
5389
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5390
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5391
     *                              <strong>SORT_NATURAL</strong></p>
5392
     * @param bool       $keepKeys
5393
     *
5394
     * @return static
5395
     *                <p>(Mutable) Return this Arrayy object.</p>
5396
     */
5397 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
5398
    {
5399 20
        $direction = $this->getDirection($direction);
5400
5401 20
        if (!$strategy) {
5402 20
            $strategy = \SORT_REGULAR;
5403
        }
5404
5405 20
        switch ($direction) {
5406 20
            case 'desc':
5407
            case \SORT_DESC:
5408 9
                if ($keepKeys) {
5409 5
                    \arsort($elements, $strategy);
5410
                } else {
5411 4
                    \rsort($elements, $strategy);
5412
                }
5413
5414 9
                break;
5415 11
            case 'asc':
5416 11
            case \SORT_ASC:
5417
            default:
5418 11
                if ($keepKeys) {
5419 4
                    \asort($elements, $strategy);
5420
                } else {
5421 7
                    \sort($elements, $strategy);
5422
                }
5423
        }
5424
5425 20
        return $this;
5426
    }
5427
5428
    /**
5429
     * Extracts the value of the given property or method from the object.
5430
     *
5431
     * @param \Arrayy\Arrayy $object                <p>The object to extract the value from.</p>
5432
     * @param string         $keyOrPropertyOrMethod <p>The property or method for which the
5433
     *                                              value should be extracted.</p>
5434
     *
5435
     * @throws \InvalidArgumentException if the method or property is not defined
5436
     *
5437
     * @return mixed
5438
     *               <p>The value extracted from the specified property or method.</p>
5439
     */
5440 2
    final protected function extractValue(Arrayy $object, string $keyOrPropertyOrMethod)
5441
    {
5442 2
        if (isset($object[$keyOrPropertyOrMethod])) {
5443 2
            $return = $object->get($keyOrPropertyOrMethod);
5444
5445 2
            if ($return instanceof Arrayy) {
5446 1
                return $return->getArray();
5447
            }
5448
5449 1
            return $return;
5450
        }
5451
5452
        if (\property_exists($object, $keyOrPropertyOrMethod)) {
5453
            return $object->{$keyOrPropertyOrMethod};
5454
        }
5455
5456
        if (\method_exists($object, $keyOrPropertyOrMethod)) {
5457
            return $object->{$keyOrPropertyOrMethod}();
5458
        }
5459
5460
        throw new \InvalidArgumentException(\sprintf('array-key & property & method "%s" not defined in %s', $keyOrPropertyOrMethod, \gettype($object)));
5461
    }
5462
5463
    /**
5464
     * @param int|string|null $key
5465
     * @param mixed           $value
5466
     *
5467
     * @return void
5468
     */
5469 84
    private function checkType($key, $value)
5470
    {
5471
        if (
5472 84
            $key !== null
5473
            &&
5474 84
            isset($this->properties[$key]) === false
5475
            &&
5476 84
            $this->checkPropertiesMismatch === true
5477
        ) {
5478
            throw new \TypeError('The key ' . $key . ' does not exists in "properties". Maybe because @property was not used for the class (' . \get_class($this) . ').');
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'The key ' . $key . ' do...get_class($this) . ').'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
5479
        }
5480
5481 84
        if (isset($this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES])) {
5482 73
            $this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES]->checkType($value);
5483 17
        } elseif ($key !== null && isset($this->properties[$key])) {
5484 17
            $this->properties[$key]->checkType($value);
5485
        }
5486 82
    }
5487
}
5488