Completed
Push — master ( 3bd5ac...d91a6c )
by Lars
01:37
created

Arrayy::checkType()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 7.049

Importance

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