Completed
Push — master ( 8d51f3...1466a5 )
by Lars
02:00 queued 16s
created

Arrayy::replaceOneValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 15
ccs 9
cts 9
cp 1
crap 2
rs 9.7666
c 0
b 0
f 0
1
<?php
2
3
/** @noinspection ReturnTypeCanBeDeclaredInspection */
4
/** @noinspection ClassReImplementsParentInterfaceInspection */
5
6
declare(strict_types=1);
7
8
namespace Arrayy;
9
10
use Arrayy\Type\TypeInterface;
11
use Arrayy\TypeCheck\TypeCheckArray;
12
use Arrayy\TypeCheck\TypeCheckInterface;
13
use Arrayy\TypeCheck\TypeCheckPhpDoc;
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 TKey of array-key
22
 * @template T
23
 * @template-extends \ArrayObject<TKey,T>
24
 * @template-implements \IteratorAggregate<TKey,T>
25
 * @template-implements \ArrayAccess<TKey|null,T>
26
 */
27
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \JsonSerializable, \Countable
28
{
29
    const ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES = '!!!!Arrayy_Helper_Types_For_All_Properties!!!!';
30
31
    /**
32
     * @var array
33
     *
34
     * @psalm-var array<mixed,mixed>|array<TKey,T>
35
     */
36
    protected $array = [];
37
38
    /**
39
     * @var \Arrayy\ArrayyRewindableGenerator|null
40
     *
41
     * @psalm-var \Arrayy\ArrayyRewindableGenerator<TKey,T>|null
42
     */
43
    protected $generator;
44
45
    /**
46
     * @var string
47
     *
48
     * @psalm-var class-string<\Arrayy\ArrayyIterator>
49
     */
50
    protected $iteratorClass = ArrayyIterator::class;
51
52
    /**
53
     * @var string
54
     */
55
    protected $pathSeparator = '.';
56
57
    /**
58
     * @var bool
59
     */
60
    protected $checkPropertyTypes = false;
61
62
    /**
63
     * @var bool
64
     */
65
    protected $checkForMissingPropertiesInConstructor = false;
66
67
    /**
68
     * @var bool
69
     */
70
    protected $checkPropertiesMismatchInConstructor = false;
71
72
    /**
73
     * @var bool
74
     */
75
    protected $checkPropertiesMismatch = true;
76
77
    /**
78
     * @var array<int|string,TypeCheckInterface>|mixed|TypeCheckArray<int|string,TypeCheckInterface>|TypeInterface
79
     */
80
    protected $properties = [];
81
82
    /**
83
     * Initializes
84
     *
85
     * @param mixed  $data                         <p>
86
     *                                             Should be an array or a generator, otherwise it will try
87
     *                                             to convert it into an array.
88
     *                                             </p>
89
     * @param string $iteratorClass                optional <p>
90
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
91
     *                                             need this option.
92
     *                                             </p>
93
     * @param bool   $checkPropertiesInConstructor optional <p>
94
     *                                             You need to extend the "Arrayy"-class and you need to set
95
     *                                             the $checkPropertiesMismatchInConstructor class property
96
     *                                             to
97
     *                                             true, otherwise this option didn't not work anyway.
98
     *                                             </p>
99
     *
100
     * @psalm-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
101
     */
102 1185
    public function __construct(
103
        $data = [],
104
        string $iteratorClass = ArrayyIterator::class,
105
        bool $checkPropertiesInConstructor = true
106
    ) {
107 1185
        $data = $this->fallbackForArray($data);
108
109
        // used only for serialize + unserialize, all other methods are overwritten
110
        /**
111
         * @psalm-suppress InvalidArgument - why?
112
         */
113 1183
        parent::__construct([], 0, $iteratorClass);
114
115 1183
        $this->setInitialValuesAndProperties($data, $checkPropertiesInConstructor);
116
117 1176
        $this->setIteratorClass($iteratorClass);
118 1176
    }
119
120
    /**
121
     * @return void
122
     */
123 50
    public function __clone()
124
    {
125 50
        if (!\is_array($this->properties)) {
126
            $this->properties = clone $this->properties;
0 ignored issues
show
Documentation Bug introduced by
It seems like clone $this->properties of type object is incompatible with the declared type array of property $properties.

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

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

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

Loading history...
2249
    {
2250 8
        foreach ($this->getGenerator() as $key => $value) {
2251 6
            if ($closure($value, $key)) {
2252 6
                return $value;
2253
            }
2254
        }
2255
2256 3
        return false;
2257
    }
2258
2259
    /**
2260
     * find by ...
2261
     *
2262
     * @param string          $property
2263
     * @param string|string[] $value
2264
     * @param string          $comparisonOp
2265
     *
2266
     * @return static
2267
     *                <p>(Immutable)</p>
2268
     *
2269
     * @psalm-return static<TKey,T>
2270
     * @psalm-mutation-free
2271
     */
2272 1
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
2273
    {
2274 1
        return $this->filterBy($property, $value, $comparisonOp);
2275
    }
2276
2277
    /**
2278
     * Get the first value from the current array.
2279
     *
2280
     * @return mixed
2281
     *               <p>Return null if there wasn't a element.</p>
2282
     */
2283 21
    public function first()
2284
    {
2285 21
        $key_first = $this->firstKey();
2286 21
        if ($key_first === null) {
2287 3
            return null;
2288
        }
2289
2290 18
        return $this->get($key_first);
2291
    }
2292
2293
    /**
2294
     * Get the first key from the current array.
2295
     *
2296
     * @return mixed
2297
     *               <p>Return null if there wasn't a element.</p>
2298
     * @psalm-mutation-free
2299
     */
2300 28
    public function firstKey()
2301
    {
2302 28
        $this->generatorToArray();
2303
2304 28
        return \array_key_first($this->array);
2305
    }
2306
2307
    /**
2308
     * Get the first value(s) from the current array.
2309
     * And will return an empty array if there was no first entry.
2310
     *
2311
     * @param int|null $number <p>How many values you will take?</p>
2312
     *
2313
     * @return static
2314
     *                <p>(Immutable)</p>
2315
     *
2316
     * @psalm-return static<TKey,T>
2317
     * @psalm-mutation-free
2318
     */
2319 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...
2320
    {
2321 37
        $arrayTmp = $this->toArray();
2322
2323 37
        if ($number === null) {
2324 14
            $array = (array) \array_shift($arrayTmp);
2325
        } else {
2326 23
            $number = (int) $number;
2327 23
            $array = \array_splice($arrayTmp, 0, $number);
2328
        }
2329
2330 37
        return static::create(
2331 37
            $array,
2332 37
            $this->iteratorClass,
2333 37
            false
2334
        );
2335
    }
2336
2337
    /**
2338
     * Get the first value(s) from the current array.
2339
     * And will return an empty array if there was no first entry.
2340
     *
2341
     * @param int|null $number <p>How many values you will take?</p>
2342
     *
2343
     * @return static
2344
     *                <p>(Immutable)</p>
2345
     *
2346
     * @psalm-return static<TKey,T>
2347
     * @psalm-mutation-free
2348
     */
2349 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...
2350
    {
2351 3
        $arrayTmp = $this->keys()->toArray();
2352
2353 3
        if ($number === null) {
2354
            $array = (array) \array_shift($arrayTmp);
2355
        } else {
2356 3
            $number = (int) $number;
2357 3
            $array = \array_splice($arrayTmp, 0, $number);
2358
        }
2359
2360 3
        return static::create(
2361 3
            $array,
2362 3
            $this->iteratorClass,
2363 3
            false
2364
        );
2365
    }
2366
2367
    /**
2368
     * Get and rmove the first value(s) from the current array.
2369
     * And will return an empty array if there was no first entry.
2370
     *
2371
     * @param int|null $number <p>How many values you will take?</p>
2372
     *
2373
     * @return $this
2374
     *               <p>(Mutable)</p>
2375
     *
2376
     * @psalm-return static<TKey,T>
2377
     */
2378 34
    public function firstsMutable(int $number = null): self
2379
    {
2380 34
        $this->generatorToArray();
2381
2382 34
        if ($number === null) {
2383 19
            $this->array = (array) \array_shift($this->array);
2384
        } else {
2385 15
            $number = (int) $number;
2386 15
            $this->array = \array_splice($this->array, 0, $number);
2387
        }
2388
2389 34
        return $this;
2390
    }
2391
2392
    /**
2393
     * Exchanges all keys with their associated values in an array.
2394
     *
2395
     * @return static
2396
     *                <p>(Immutable)</p>
2397
     *
2398
     * @psalm-return static<TKey,T>
2399
     * @psalm-mutation-free
2400
     */
2401 1
    public function flip(): self
2402
    {
2403 1
        return static::create(
2404 1
            \array_flip($this->toArray()),
2405 1
            $this->iteratorClass,
2406 1
            false
2407
        );
2408
    }
2409
2410
    /**
2411
     * Get a value from an array (optional using dot-notation).
2412
     *
2413
     * @param mixed $key      <p>The key to look for.</p>
2414
     * @param mixed $fallback <p>Value to fallback to.</p>
2415
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
2416
     *                        class.</p>
2417
     *
2418
     * @return mixed|static
2419
     *
2420
     * @psalm-param array<mixed,mixed>|array<TKey,T> $array
2421
     * @psalm-mutation-free
2422
     */
2423 231
    public function get($key, $fallback = null, array $array = null)
2424
    {
2425 231
        if ($array !== null) {
2426 4
            $usedArray = $array;
2427
        } else {
2428 228
            $this->generatorToArray();
2429
2430 228
            $usedArray = $this->array;
2431
        }
2432
2433 231
        if ($key === null) {
2434 1
            return static::create(
2435 1
                $usedArray,
2436 1
                $this->iteratorClass,
2437 1
                false
2438
            );
2439
        }
2440
2441
        // php cast "bool"-index into "int"-index
2442 231
        if ((bool) $key === $key) {
2443 3
            $key = (int) $key;
2444
        }
2445
2446 231
        if (\array_key_exists($key, $usedArray) === true) {
2447 194
            if (\is_array($usedArray[$key]) === true) {
2448 18
                return static::create(
2449 18
                    $usedArray[$key],
2450 18
                    $this->iteratorClass,
2451 18
                    false
2452
                );
2453
            }
2454
2455 180
            return $usedArray[$key];
2456
        }
2457
2458
        // crawl through array, get key according to object or not
2459 56
        $usePath = false;
2460
        if (
2461 56
            $this->pathSeparator
2462
            &&
2463 56
            (string) $key === $key
2464
            &&
2465 56
            \strpos($key, $this->pathSeparator) !== false
2466
        ) {
2467 30
            $segments = \explode($this->pathSeparator, (string) $key);
2468 30
            if ($segments !== false) {
2469 30
                $usePath = true;
2470
2471 30
                foreach ($segments as $segment) {
2472
                    if (
2473
                        (
2474 30
                            \is_array($usedArray) === true
2475
                            ||
2476 30
                            $usedArray instanceof \ArrayAccess
2477
                        )
2478
                        &&
2479 30
                        isset($usedArray[$segment])
2480
                    ) {
2481 30
                        $usedArray = $usedArray[$segment];
2482
2483 30
                        continue;
2484
                    }
2485
2486
                    if (
2487 12
                        \is_object($usedArray) === true
2488
                        &&
2489 12
                        \property_exists($usedArray, $segment)
2490
                    ) {
2491 1
                        $usedArray = $usedArray->{$segment};
2492
2493 1
                        continue;
2494
                    }
2495
2496 11
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
2497
                }
2498
            }
2499
        }
2500
2501 54
        if (!$usePath && !isset($usedArray[$key])) {
2502 26
            return $fallback instanceof \Closure ? $fallback() : $fallback;
2503
        }
2504
2505 28
        if (\is_array($usedArray) === true) {
2506 6
            return static::create(
2507 6
                $usedArray,
2508 6
                $this->iteratorClass,
2509 6
                false
2510
            );
2511
        }
2512
2513 28
        return $usedArray;
2514
    }
2515
2516
    /**
2517
     * alias: for "Arrayy->toArray()"
2518
     *
2519
     * @return array
2520
     *
2521
     * @see          Arrayy::getArray()
2522
     *
2523
     * @psalm-return array<mixed,mixed>|array<TKey,T>
2524
     */
2525 12
    public function getAll(): array
2526
    {
2527 12
        return $this->toArray();
2528
    }
2529
2530
    /**
2531
     * Get the current array from the "Arrayy"-object.
2532
     *
2533
     * alias for "toArray()"
2534
     *
2535
     * @param bool $convertAllArrayyElements <p>
2536
     *                                       Convert all Child-"Arrayy" objects also to arrays.
2537
     *                                       </p>
2538
     * @param bool $preserveKeys             <p>
2539
     *                                       e.g.: A generator maybe return the same key more then once,
2540
     *                                       so maybe you will ignore the keys.
2541
     *                                       </p>
2542
     *
2543
     * @return array
2544
     *
2545
     * @psalm-return array<mixed,mixed>|array<TKey,T>
2546
     * @psalm-mutation-free
2547
     *
2548
     * @see Arrayy::toArray()
2549
     */
2550 497
    public function getArray(
2551
        bool $convertAllArrayyElements = false,
2552
        bool $preserveKeys = true
2553
    ): array {
2554 497
        return $this->toArray(
2555 497
            $convertAllArrayyElements,
2556 497
            $preserveKeys
2557
        );
2558
    }
2559
2560
    /**
2561
     * Get the current array from the "Arrayy"-object as list.
2562
     *
2563
     * alias for "toList()"
2564
     *
2565
     * @param bool $convertAllArrayyElements <p>
2566
     *                                       Convert all Child-"Arrayy" objects also to arrays.
2567
     *                                       </p>
2568
     *
2569
     * @return array
2570
     *
2571
     * @psalm-return array<int,mixed>|array<int,T>
2572
     * @psalm-mutation-free
2573
     *
2574
     * @see Arrayy::toList()
2575
     */
2576 1
    public function getList(bool $convertAllArrayyElements = false): array
2577
    {
2578 1
        return $this->toList($convertAllArrayyElements);
2579
    }
2580
2581
    /**
2582
     * Returns the values from a single column of the input array, identified by
2583
     * the $columnKey, can be used to extract data-columns from multi-arrays.
2584
     *
2585
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
2586
     * array by the values from the $indexKey column in the input array.
2587
     *
2588
     * @param mixed $columnKey
2589
     * @param mixed $indexKey
2590
     *
2591
     * @return static
2592
     *                <p>(Immutable)</p>
2593
     *
2594
     * @psalm-return static<TKey,T>
2595
     * @psalm-mutation-free
2596
     */
2597 1
    public function getColumn($columnKey = null, $indexKey = null): self
2598
    {
2599 1
        return static::create(
2600 1
            \array_column($this->toArray(), $columnKey, $indexKey),
2601 1
            $this->iteratorClass,
2602 1
            false
2603
        );
2604
    }
2605
2606
    /**
2607
     * Get the current array from the "Arrayy"-object as generator by reference.
2608
     *
2609
     * @return \Generator
2610
     *
2611
     * @psalm-return \Generator<mixed,T>|\Generator<TKey,T>
2612
     */
2613 75
    public function &getGeneratorByReference(): \Generator
2614
    {
2615 75
        if ($this->generator instanceof ArrayyRewindableGenerator) {
2616
            // -> false-positive -> see "&" from method
2617
            /** @noinspection YieldFromCanBeUsedInspection */
2618 17
            foreach ($this->generator as $key => $value) {
2619 17
                yield $key => $value;
2620
            }
2621
2622 5
            return;
2623
        }
2624
2625
        // -> false-positive -> see "&$value"
2626
        /** @noinspection YieldFromCanBeUsedInspection */
2627 59
        foreach ($this->array as $key => &$value) {
2628 54
            yield $key => $value;
2629
        }
2630 35
    }
2631
2632
    /**
2633
     * Get the current array from the "Arrayy"-object as generator.
2634
     *
2635
     * @return \Generator
2636
     *
2637
     * @psalm-return \Generator<mixed,T>|\Generator<TKey,T>
2638
     * @psalm-mutation-free
2639
     */
2640 988
    public function getGenerator(): \Generator
2641
    {
2642 988
        if ($this->generator instanceof ArrayyRewindableGenerator) {
2643 25
            yield from $this->generator;
2644
2645 25
            return;
2646
        }
2647
2648 986
        yield from $this->array;
2649 960
    }
2650
2651
    /**
2652
     * alias: for "Arrayy->keys()"
2653
     *
2654
     * @return static
2655
     *                <p>(Immutable)</p>
2656
     *
2657
     * @see          Arrayy::keys()
2658
     *
2659
     * @psalm-return static<array-key,TKey>
2660
     * @psalm-mutation-free
2661
     */
2662 2
    public function getKeys()
2663
    {
2664 2
        return $this->keys();
2665
    }
2666
2667
    /**
2668
     * Get the current array from the "Arrayy"-object as object.
2669
     *
2670
     * @return \stdClass
2671
     */
2672 4
    public function getObject(): \stdClass
2673
    {
2674 4
        return self::arrayToObject($this->toArray());
2675
    }
2676
2677
    /**
2678
     * alias: for "Arrayy->randomImmutable()"
2679
     *
2680
     * @return static
2681
     *                <p>(Immutable)</p>
2682
     *
2683
     * @see          Arrayy::randomImmutable()
2684
     *
2685
     * @psalm-return static<int|array-key,T>
2686
     */
2687 4
    public function getRandom(): self
2688
    {
2689 4
        return $this->randomImmutable();
2690
    }
2691
2692
    /**
2693
     * alias: for "Arrayy->randomKey()"
2694
     *
2695
     * @return mixed
2696
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2697
     *
2698
     * @see Arrayy::randomKey()
2699
     */
2700 3
    public function getRandomKey()
2701
    {
2702 3
        return $this->randomKey();
2703
    }
2704
2705
    /**
2706
     * alias: for "Arrayy->randomKeys()"
2707
     *
2708
     * @param int $number
2709
     *
2710
     * @return static
2711
     *                <p>(Immutable)</p>
2712
     *
2713
     * @see          Arrayy::randomKeys()
2714
     *
2715
     * @psalm-return static<TKey,T>
2716
     */
2717 8
    public function getRandomKeys(int $number): self
2718
    {
2719 8
        return $this->randomKeys($number);
2720
    }
2721
2722
    /**
2723
     * alias: for "Arrayy->randomValue()"
2724
     *
2725
     * @return mixed
2726
     *               <p>Get a random value or null if there wasn't a value.</p>
2727
     *
2728
     * @see Arrayy::randomValue()
2729
     */
2730 3
    public function getRandomValue()
2731
    {
2732 3
        return $this->randomValue();
2733
    }
2734
2735
    /**
2736
     * alias: for "Arrayy->randomValues()"
2737
     *
2738
     * @param int $number
2739
     *
2740
     * @return static
2741
     *                <p>(Immutable)</p>
2742
     *
2743
     * @see          Arrayy::randomValues()
2744
     *
2745
     * @psalm-return static<TKey,T>
2746
     */
2747 6
    public function getRandomValues(int $number): self
2748
    {
2749 6
        return $this->randomValues($number);
2750
    }
2751
2752
    /**
2753
     * Gets all values.
2754
     *
2755
     * @return static
2756
     *                <p>The values of all elements in this array, in the order they
2757
     *                appear in the array.</p>
2758
     *
2759
     * @psalm-return static<TKey,T>
2760
     */
2761 4
    public function getValues()
2762
    {
2763 4
        $this->generatorToArray(false);
2764
2765 4
        return static::create(
2766 4
            \array_values($this->array),
2767 4
            $this->iteratorClass,
2768 4
            false
2769
        );
2770
    }
2771
2772
    /**
2773
     * Gets all values via Generator.
2774
     *
2775
     * @return \Generator
2776
     *                    <p>The values of all elements in this array, in the order they
2777
     *                    appear in the array as Generator.</p>
2778
     *
2779
     * @psalm-return \Generator<TKey,T>
2780
     */
2781 4
    public function getValuesYield(): \Generator
2782
    {
2783 4
        yield from $this->getGenerator();
2784 4
    }
2785
2786
    /**
2787
     * Group values from a array according to the results of a closure.
2788
     *
2789
     * @param callable|string $grouper  <p>A callable function name.</p>
2790
     * @param bool            $saveKeys
2791
     *
2792
     * @return static
2793
     *                <p>(Immutable)</p>
2794
     *
2795
     * @psalm-return static<TKey,T>
2796
     * @psalm-mutation-free
2797
     */
2798 4
    public function group($grouper, bool $saveKeys = false): self
2799
    {
2800
        // init
2801 4
        $result = [];
2802
2803
        // Iterate over values, group by property/results from closure.
2804 4
        foreach ($this->getGenerator() as $key => $value) {
2805 4
            if (\is_callable($grouper) === true) {
2806 3
                $groupKey = $grouper($value, $key);
2807
            } else {
2808 1
                $groupKey = $this->get($grouper);
2809
            }
2810
2811 4
            $newValue = $this->get($groupKey, null, $result);
2812
2813 4
            if ($groupKey instanceof self) {
2814
                $groupKey = $groupKey->toArray();
2815
            }
2816
2817 4
            if ($newValue instanceof self) {
2818 4
                $newValue = $newValue->toArray();
2819
            }
2820
2821
            // Add to results.
2822 4
            if ($groupKey !== null) {
2823 3
                if ($saveKeys) {
2824 2
                    $result[$groupKey] = $newValue;
2825 2
                    $result[$groupKey][$key] = $value;
2826
                } else {
2827 1
                    $result[$groupKey] = $newValue;
2828 4
                    $result[$groupKey][] = $value;
2829
                }
2830
            }
2831
        }
2832
2833 4
        return static::create(
2834 4
            $result,
2835 4
            $this->iteratorClass,
2836 4
            false
2837
        );
2838
    }
2839
2840
    /**
2841
     * Check if an array has a given key.
2842
     *
2843
     * @param mixed $key
2844
     *
2845
     * @return bool
2846
     */
2847 30
    public function has($key): bool
2848
    {
2849 30
        static $UN_FOUND = null;
2850
2851 30
        if ($UN_FOUND === null) {
2852
            // Generate unique string to use as marker.
2853 1
            $UN_FOUND = \uniqid('arrayy', true);
2854
        }
2855
2856 30
        if (\is_array($key)) {
2857 1
            if ($key === []) {
2858
                return false;
2859
            }
2860
2861 1
            foreach ($key as $keyTmp) {
2862 1
                $found = ($this->get($keyTmp, $UN_FOUND) !== $UN_FOUND);
2863 1
                if ($found === false) {
2864 1
                    return false;
2865
                }
2866
            }
2867
2868 1
            return true;
2869
        }
2870
2871 29
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2872
    }
2873
2874
    /**
2875
     * Check if an array has a given value.
2876
     *
2877
     * INFO: if you need to search recursive please use ```contains()```
2878
     *
2879
     * @param mixed $value
2880
     *
2881
     * @return bool
2882
     */
2883 1
    public function hasValue($value): bool
2884
    {
2885 1
        return $this->contains($value);
2886
    }
2887
2888
    /**
2889
     * Implodes the values of this array.
2890
     *
2891
     * @param string $glue
2892
     *
2893
     * @return string
2894
     * @psalm-mutation-free
2895
     */
2896 28
    public function implode(string $glue = ''): string
2897
    {
2898 28
        return $this->implode_recursive($glue, $this->toArray(), false);
2899
    }
2900
2901
    /**
2902
     * Implodes the keys of this array.
2903
     *
2904
     * @param string $glue
2905
     *
2906
     * @return string
2907
     * @psalm-mutation-free
2908
     */
2909 8
    public function implodeKeys(string $glue = ''): string
2910
    {
2911 8
        return $this->implode_recursive($glue, $this->toArray(), true);
2912
    }
2913
2914
    /**
2915
     * Given a list and an iterate-function that returns
2916
     * a key for each element in the list (or a property name),
2917
     * returns an object with an index of each item.
2918
     *
2919
     * @param mixed $key
2920
     *
2921
     * @return static
2922
     *                <p>(Immutable)</p>
2923
     *
2924
     * @psalm-return static<TKey,T>
2925
     * @psalm-mutation-free
2926
     */
2927 4
    public function indexBy($key): self
2928
    {
2929
        // init
2930 4
        $results = [];
2931
2932 4
        foreach ($this->getGenerator() as $a) {
2933 4
            if (\array_key_exists($key, $a) === true) {
2934 4
                $results[$a[$key]] = $a;
2935
            }
2936
        }
2937
2938 4
        return static::create(
2939 4
            $results,
2940 4
            $this->iteratorClass,
2941 4
            false
2942
        );
2943
    }
2944
2945
    /**
2946
     * alias: for "Arrayy->searchIndex()"
2947
     *
2948
     * @param mixed $value <p>The value to search for.</p>
2949
     *
2950
     * @return false|mixed
2951
     *
2952
     * @see Arrayy::searchIndex()
2953
     */
2954 4
    public function indexOf($value)
2955
    {
2956 4
        return $this->searchIndex($value);
2957
    }
2958
2959
    /**
2960
     * Get everything but the last..$to items.
2961
     *
2962
     * @param int $to
2963
     *
2964
     * @return static
2965
     *                <p>(Immutable)</p>
2966
     *
2967
     * @psalm-return static<TKey,T>
2968
     * @psalm-mutation-free
2969
     */
2970 12
    public function initial(int $to = 1): self
2971
    {
2972 12
        return $this->firstsImmutable(\count($this->toArray(), \COUNT_NORMAL) - $to);
2973
    }
2974
2975
    /**
2976
     * Return an array with all elements found in input array.
2977
     *
2978
     * @param array $search
2979
     * @param bool  $keepKeys
2980
     *
2981
     * @return static
2982
     *                <p>(Immutable)</p>
2983
     *
2984
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $search
2985
     * @psalm-return static<TKey,T>
2986
     * @psalm-mutation-free
2987
     */
2988 4
    public function intersection(array $search, bool $keepKeys = false): self
2989
    {
2990 4
        if ($keepKeys) {
2991
            /**
2992
             * @psalm-suppress MissingClosureReturnType
2993
             * @psalm-suppress MissingClosureParamType
2994
             */
2995 1
            return static::create(
2996 1
                \array_uintersect(
2997 1
                    $this->toArray(),
2998 1
                    $search,
2999 1
                    static function ($a, $b) {
3000 1
                        return $a === $b ? 0 : -1;
3001 1
                    }
3002
                ),
3003 1
                $this->iteratorClass,
3004 1
                false
3005
            );
3006
        }
3007
3008 3
        return static::create(
3009 3
            \array_values(\array_intersect($this->toArray(), $search)),
3010 3
            $this->iteratorClass,
3011 3
            false
3012
        );
3013
    }
3014
3015
    /**
3016
     * Return an array with all elements found in input array.
3017
     *
3018
     * @param array ...$array
3019
     *
3020
     * @return static
3021
     *                <p>(Immutable)</p>
3022
     *
3023
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$array
3024
     * @psalm-return static<TKey,T>
3025
     * @psalm-mutation-free
3026
     */
3027 1
    public function intersectionMulti(...$array): self
3028
    {
3029 1
        return static::create(
3030 1
            \array_values(\array_intersect($this->toArray(), ...$array)),
3031 1
            $this->iteratorClass,
3032 1
            false
3033
        );
3034
    }
3035
3036
    /**
3037
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
3038
     *
3039
     * @param array $search
3040
     *
3041
     * @return bool
3042
     *
3043
     * @psalm-param array<mixed,mixed>|array<TKey,T> $search
3044
     */
3045 1
    public function intersects(array $search): bool
3046
    {
3047 1
        return $this->intersection($search)->count() > 0;
3048
    }
3049
3050
    /**
3051
     * Invoke a function on all of an array's values.
3052
     *
3053
     * @param callable $callable
3054
     * @param mixed    $arguments
3055
     *
3056
     * @return static
3057
     *                <p>(Immutable)</p>
3058
     *
3059
     * @psalm-param  callable(T=,mixed):mixed $callable
3060
     * @psalm-return static<TKey,T>
3061
     * @psalm-mutation-free
3062
     */
3063 1 View Code Duplication
    public function invoke($callable, $arguments = []): 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...
3064
    {
3065
        // If one argument given for each iteration, create an array for it.
3066 1
        if (\is_array($arguments) === false) {
3067 1
            $arguments = \array_fill(
3068 1
                0,
3069 1
                $this->count(),
3070 1
                $arguments
3071
            );
3072
        }
3073
3074
        // If the callable has arguments, pass them.
3075 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...
3076 1
            $array = \array_map($callable, $this->toArray(), $arguments);
3077
        } else {
3078 1
            $array = $this->map($callable);
3079
        }
3080
3081 1
        return static::create(
3082 1
            $array,
3083 1
            $this->iteratorClass,
3084 1
            false
3085
        );
3086
    }
3087
3088
    /**
3089
     * Check whether array is associative or not.
3090
     *
3091
     * @param bool $recursive
3092
     *
3093
     * @return bool
3094
     *              <p>Returns true if associative, false otherwise.</p>
3095
     */
3096 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...
3097
    {
3098 15
        if ($this->isEmpty()) {
3099 3
            return false;
3100
        }
3101
3102 13
        foreach ($this->keys($recursive)->getGeneratorByReference() as &$key) {
3103 13
            if ((string) $key !== $key) {
3104 13
                return false;
3105
            }
3106
        }
3107
3108 3
        return true;
3109
    }
3110
3111
    /**
3112
     * Check if a given key or keys are empty.
3113
     *
3114
     * @param int|int[]|string|string[]|null $keys
3115
     *
3116
     * @return bool
3117
     *              <p>Returns true if empty, false otherwise.</p>
3118
     * @psalm-mutation-free
3119
     */
3120 45
    public function isEmpty($keys = null): bool
3121
    {
3122 45
        if ($this->generator) {
3123
            return $this->toArray() === [];
3124
        }
3125
3126 45
        if ($keys === null) {
3127 43
            return $this->array === [];
3128
        }
3129
3130 2
        foreach ((array) $keys as $key) {
3131 2
            if (!empty($this->get($key))) {
3132 2
                return false;
3133
            }
3134
        }
3135
3136 2
        return true;
3137
    }
3138
3139
    /**
3140
     * Check if the current array is equal to the given "$array" or not.
3141
     *
3142
     * @param array $array
3143
     *
3144
     * @return bool
3145
     *
3146
     * @psalm-param array<mixed,mixed> $array
3147
     */
3148 1
    public function isEqual(array $array): bool
3149
    {
3150 1
        return $this->toArray() === $array;
3151
    }
3152
3153
    /**
3154
     * Check if the current array is a multi-array.
3155
     *
3156
     * @return bool
3157
     */
3158 22
    public function isMultiArray(): bool
3159
    {
3160
        return !(
3161 22
            \count($this->toArray(), \COUNT_NORMAL)
3162
            ===
3163 22
            \count($this->toArray(), \COUNT_RECURSIVE)
3164
        );
3165
    }
3166
3167
    /**
3168
     * Check whether array is numeric or not.
3169
     *
3170
     * @return bool
3171
     *              <p>Returns true if numeric, false otherwise.</p>
3172
     */
3173 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...
3174
    {
3175 5
        if ($this->isEmpty()) {
3176 2
            return false;
3177
        }
3178
3179 4
        foreach ($this->keys()->getGeneratorByReference() as &$key) {
3180 4
            if ((int) $key !== $key) {
3181 4
                return false;
3182
            }
3183
        }
3184
3185 2
        return true;
3186
    }
3187
3188
    /**
3189
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
3190
     *
3191
     * @param bool $recursive
3192
     *
3193
     * @return bool
3194
     * @psalm-mutation-free
3195
     */
3196 9
    public function isSequential(bool $recursive = false): bool
3197
    {
3198
3199
        // recursive
3200
3201 9
        if ($recursive === true) {
3202
            return $this->array_keys_recursive($this->toArray())
3203
                   ===
3204
                   \range(0, \count($this->toArray(), \COUNT_RECURSIVE) - 1);
3205
        }
3206
3207
        // non recursive
3208
3209 9
        return \array_keys($this->toArray())
3210
               ===
3211 9
               \range(0, \count($this->toArray(), \COUNT_NORMAL) - 1);
3212
    }
3213
3214
    /**
3215
     * @return array
3216
     *
3217
     * @psalm-return array<mixed,mixed>|array<TKey,T>
3218
     */
3219 1
    public function jsonSerialize(): array
3220
    {
3221 1
        return $this->toArray();
3222
    }
3223
3224
    /**
3225
     * Gets the key/index of the element at the current internal iterator position.
3226
     *
3227
     * @return int|string|null
3228
     */
3229
    public function key()
3230
    {
3231
        return \key($this->array);
3232
    }
3233
3234
    /**
3235
     * Checks if the given key exists in the provided array.
3236
     *
3237
     * INFO: This method only use "array_key_exists()" if you want to use "dot"-notation,
3238
     *       then you need to use "Arrayy->offsetExists()".
3239
     *
3240
     * @param int|string $key the key to look for
3241
     *
3242
     * @return bool
3243
     * @psalm-mutation-free
3244
     */
3245 154
    public function keyExists($key): bool
3246
    {
3247 154
        return \array_key_exists($key, $this->array);
3248
    }
3249
3250
    /**
3251
     * Get all keys from the current array.
3252
     *
3253
     * @param bool       $recursive     [optional] <p>
3254
     *                                  Get all keys, also from all sub-arrays from an multi-dimensional array.
3255
     *                                  </p>
3256
     * @param mixed|null $search_values [optional] <p>
3257
     *                                  If specified, then only keys containing these values are returned.
3258
     *                                  </p>
3259
     * @param bool       $strict        [optional] <p>
3260
     *                                  Determines if strict comparison (===) should be used during the search.
3261
     *                                  </p>
3262
     *
3263
     * @return static
3264
     *                <p>(Immutable) An array of all the keys in input.</p>
3265
     *
3266
     * @psalm-return static<array-key,TKey>
3267
     * @psalm-mutation-free
3268
     */
3269 29
    public function keys(
3270
        bool $recursive = false,
3271
        $search_values = null,
3272
        bool $strict = true
3273
    ): self {
3274
3275
        // recursive
3276
3277 29
        if ($recursive === true) {
3278 4
            $array = $this->array_keys_recursive(
3279 4
                null,
3280 4
                $search_values,
3281 4
                $strict
3282
            );
3283
3284 4
            return static::create(
3285 4
                $array,
3286 4
                $this->iteratorClass,
3287 4
                false
3288
            );
3289
        }
3290
3291
        // non recursive
3292
3293 28
        if ($search_values === null) {
3294 28
            $arrayFunction = function (): \Generator {
3295 28
                foreach ($this->getGenerator() as $key => $value) {
3296 26
                    yield $key;
3297
                }
3298 28
            };
3299
        } else {
3300 1
            $arrayFunction = function () use ($search_values, $strict): \Generator {
3301 1
                $is_array_tmp = \is_array($search_values);
3302
3303 1
                foreach ($this->getGeneratorByReference() as $key => &$value) {
3304 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...
3305
                        (
3306 1
                            $is_array_tmp === false
3307
                            &&
3308 1
                            $strict === true
3309
                            &&
3310 1
                            $search_values === $value
3311
                        )
3312
                        ||
3313
                        (
3314 1
                            $is_array_tmp === false
3315
                            &&
3316 1
                            $strict === false
3317
                            &&
3318 1
                            $search_values == $value
3319
                        )
3320
                        ||
3321
                        (
3322 1
                            $is_array_tmp === true
3323
                            &&
3324 1
                            \in_array($value, $search_values, $strict)
3325
                        )
3326
                    ) {
3327 1
                        yield $key;
3328
                    }
3329
                }
3330 1
            };
3331
        }
3332
3333 28
        return static::create(
3334 28
            $arrayFunction,
3335 28
            $this->iteratorClass,
3336 28
            false
3337
        );
3338
    }
3339
3340
    /**
3341
     * Sort an array by key in reverse order.
3342
     *
3343
     * @param int $sort_flags [optional] <p>
3344
     *                        You may modify the behavior of the sort using the optional
3345
     *                        parameter sort_flags, for details
3346
     *                        see sort.
3347
     *                        </p>
3348
     *
3349
     * @return $this
3350
     *               <p>(Mutable) Return this Arrayy object.</p>
3351
     *
3352
     * @psalm-return static<TKey,T>
3353
     */
3354 4
    public function krsort(int $sort_flags = 0): self
3355
    {
3356 4
        $this->generatorToArray();
3357
3358 4
        \krsort($this->array, $sort_flags);
3359
3360 4
        return $this;
3361
    }
3362
3363
    /**
3364
     * Sort an array by key in reverse order.
3365
     *
3366
     * @param int $sort_flags [optional] <p>
3367
     *                        You may modify the behavior of the sort using the optional
3368
     *                        parameter sort_flags, for details
3369
     *                        see sort.
3370
     *                        </p>
3371
     *
3372
     * @return $this
3373
     *               <p>(Immutable) Return this Arrayy object.</p>
3374
     *
3375
     * @psalm-return static<TKey,T>
3376
     * @psalm-mutation-free
3377
     */
3378 4
    public function krsortImmutable(int $sort_flags = 0): self
3379
    {
3380 4
        $that = clone $this;
3381
3382
        /**
3383
         * @psalm-suppress ImpureMethodCall - object is already cloned
3384
         */
3385 4
        $that->krsort($sort_flags);
3386
3387 4
        return $that;
3388
    }
3389
3390
    /**
3391
     * Get the last value from the current array.
3392
     *
3393
     * @return mixed|null
3394
     *                    <p>Return null if there wasn't a element.</p>
3395
     * @psalm-mutation-free
3396
     */
3397 17
    public function last()
3398
    {
3399 17
        $key_last = $this->lastKey();
3400 17
        if ($key_last === null) {
3401 2
            return null;
3402
        }
3403
3404 15
        return $this->get($key_last);
3405
    }
3406
3407
    /**
3408
     * Get the last key from the current array.
3409
     *
3410
     * @return mixed|null
3411
     *                    <p>Return null if there wasn't a element.</p>
3412
     * @psalm-mutation-free
3413
     */
3414 21
    public function lastKey()
3415
    {
3416 21
        $this->generatorToArray();
3417
3418 21
        return \array_key_last($this->array);
3419
    }
3420
3421
    /**
3422
     * Get the last value(s) from the current array.
3423
     *
3424
     * @param int|null $number
3425
     *
3426
     * @return static
3427
     *                <p>(Immutable)</p>
3428
     *
3429
     * @psalm-return static<TKey,T>
3430
     * @psalm-mutation-free
3431
     */
3432 13
    public function lastsImmutable(int $number = null): self
3433
    {
3434 13
        if ($this->isEmpty()) {
3435 1
            return static::create(
3436 1
                [],
3437 1
                $this->iteratorClass,
3438 1
                false
3439
            );
3440
        }
3441
3442 12
        if ($number === null) {
3443 8
            $poppedValue = $this->last();
3444
3445 8
            if ($poppedValue === null) {
3446 1
                $poppedValue = [$poppedValue];
3447
            } else {
3448 7
                $poppedValue = (array) $poppedValue;
3449
            }
3450
3451 8
            $arrayy = static::create(
3452 8
                $poppedValue,
3453 8
                $this->iteratorClass,
3454 8
                false
3455
            );
3456
        } else {
3457 4
            $number = (int) $number;
3458 4
            $arrayy = $this->rest(-$number);
3459
        }
3460
3461 12
        return $arrayy;
3462
    }
3463
3464
    /**
3465
     * Get the last value(s) from the current array.
3466
     *
3467
     * @param int|null $number
3468
     *
3469
     * @return $this
3470
     *               <p>(Mutable)</p>
3471
     *
3472
     * @psalm-return static<TKey,T>
3473
     */
3474 13
    public function lastsMutable(int $number = null): self
3475
    {
3476 13
        if ($this->isEmpty()) {
3477 1
            return $this;
3478
        }
3479
3480 12
        if ($number === null) {
3481 8
            $poppedValue = $this->last();
3482
3483 8
            if ($poppedValue === null) {
3484 1
                $poppedValue = [$poppedValue];
3485
            } else {
3486 7
                $poppedValue = (array) $poppedValue;
3487
            }
3488
3489 8
            $this->array = static::create(
3490 8
                $poppedValue,
3491 8
                $this->iteratorClass,
3492 8
                false
3493 8
            )->toArray();
3494
        } else {
3495 4
            $number = (int) $number;
3496 4
            $this->array = $this->rest(-$number)->toArray();
3497
        }
3498
3499 12
        $this->generator = null;
3500
3501 12
        return $this;
3502
    }
3503
3504
    /**
3505
     * Count the values from the current array.
3506
     *
3507
     * alias: for "Arrayy->count()"
3508
     *
3509
     * @param int $mode
3510
     *
3511
     * @return int
3512
     *
3513
     * @see Arrayy::count()
3514
     */
3515 20
    public function length(int $mode = \COUNT_NORMAL): int
3516
    {
3517 20
        return $this->count($mode);
3518
    }
3519
3520
    /**
3521
     * Apply the given function to the every element of the array,
3522
     * collecting the results.
3523
     *
3524
     * @param callable $callable
3525
     * @param bool     $useKeyAsSecondParameter
3526
     * @param mixed    ...$arguments
3527
     *
3528
     * @return static
3529
     *                <p>(Immutable) Arrayy object with modified elements.</p>
3530
     *
3531
     * @psalm-param  callable(T,TKey=,mixed=):mixed $callable
3532
     * @psalm-return static<TKey,T>
3533
     * @psalm-mutation-free
3534
     */
3535 5
    public function map(
3536
        callable $callable,
3537
        bool $useKeyAsSecondParameter = false,
3538
        ...$arguments
3539
    ) {
3540
        /**
3541
         * @psalm-suppress ImpureFunctionCall - func_num_args is only used to detect the number of args
3542
         */
3543 5
        $useArguments = \func_num_args() > 2;
3544
3545 5
        return static::create(
3546 5
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
3547 5
                foreach ($this->getGenerator() as $key => $value) {
3548 4
                    if ($useArguments) {
3549 3
                        if ($useKeyAsSecondParameter) {
3550
                            yield $key => $callable($value, $key, ...$arguments);
3551
                        } else {
3552 3
                            yield $key => $callable($value, ...$arguments);
3553
                        }
3554
                    } else {
3555
                        /** @noinspection NestedPositiveIfStatementsInspection */
3556 4
                        if ($useKeyAsSecondParameter) {
3557
                            yield $key => $callable($value, $key);
3558
                        } else {
3559 4
                            yield $key => $callable($value);
3560
                        }
3561
                    }
3562
                }
3563 5
            },
3564 5
            $this->iteratorClass,
3565 5
            false
3566
        );
3567
    }
3568
3569
    /**
3570
     * Check if all items in current array match a truth test.
3571
     *
3572
     * @param \Closure $closure
3573
     *
3574
     * @return bool
3575
     */
3576 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...
3577
    {
3578 15
        if ($this->count() === 0) {
3579 2
            return false;
3580
        }
3581
3582 13
        foreach ($this->getGenerator() as $key => $value) {
3583 13
            $value = $closure($value, $key);
3584
3585 13
            if ($value === false) {
3586 13
                return false;
3587
            }
3588
        }
3589
3590 7
        return true;
3591
    }
3592
3593
    /**
3594
     * Check if any item in the current array matches a truth test.
3595
     *
3596
     * @param \Closure $closure
3597
     *
3598
     * @return bool
3599
     */
3600 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...
3601
    {
3602 14
        if ($this->count() === 0) {
3603 2
            return false;
3604
        }
3605
3606 12
        foreach ($this->getGenerator() as $key => $value) {
3607 12
            $value = $closure($value, $key);
3608
3609 12
            if ($value === true) {
3610 12
                return true;
3611
            }
3612
        }
3613
3614 4
        return false;
3615
    }
3616
3617
    /**
3618
     * Get the max value from an array.
3619
     *
3620
     * @return false|mixed
3621
     *                     <p>Will return false if there are no values.</p>
3622
     */
3623 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...
3624
    {
3625 10
        if ($this->count() === 0) {
3626 1
            return false;
3627
        }
3628
3629 9
        $max = false;
3630 9
        foreach ($this->getGeneratorByReference() as &$value) {
3631
            if (
3632 9
                $max === false
3633
                ||
3634 9
                $value > $max
3635
            ) {
3636 9
                $max = $value;
3637
            }
3638
        }
3639
3640 9
        return $max;
3641
    }
3642
3643
    /**
3644
     * Merge the new $array into the current array.
3645
     *
3646
     * - keep key,value from the current array, also if the index is in the new $array
3647
     *
3648
     * @param array $array
3649
     * @param bool  $recursive
3650
     *
3651
     * @return static
3652
     *                <p>(Immutable)</p>
3653
     *
3654
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3655
     * @psalm-return static<int|TKey,T>
3656
     * @psalm-mutation-free
3657
     */
3658 32 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...
3659
    {
3660 32
        if ($recursive === true) {
3661 9
            $array = $this->getArrayRecursiveHelperArrayy($array);
3662 9
            $result = \array_replace_recursive($this->toArray(), $array);
3663
        } else {
3664 23
            $result = \array_replace($this->toArray(), $array);
3665
        }
3666
3667 32
        return static::create(
3668 32
            $result,
3669 32
            $this->iteratorClass,
3670 32
            false
3671
        );
3672
    }
3673
3674
    /**
3675
     * Merge the new $array into the current array.
3676
     *
3677
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
3678
     * - create new indexes
3679
     *
3680
     * @param array $array
3681
     * @param bool  $recursive
3682
     *
3683
     * @return static
3684
     *                <p>(Immutable)</p>
3685
     *
3686
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3687
     * @psalm-return static<TKey,T>
3688
     * @psalm-mutation-free
3689
     */
3690 19 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...
3691
    {
3692 19
        if ($recursive === true) {
3693 5
            $array = $this->getArrayRecursiveHelperArrayy($array);
3694 5
            $result = \array_merge_recursive($this->toArray(), $array);
3695
        } else {
3696 14
            $result = \array_merge($this->toArray(), $array);
3697
        }
3698
3699 19
        return static::create(
3700 19
            $result,
3701 19
            $this->iteratorClass,
3702 19
            false
3703
        );
3704
    }
3705
3706
    /**
3707
     * Merge the the current array into the $array.
3708
     *
3709
     * - use key,value from the new $array, also if the index is in the current array
3710
     *
3711
     * @param array $array
3712
     * @param bool  $recursive
3713
     *
3714
     * @return static
3715
     *                <p>(Immutable)</p>
3716
     *
3717
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3718
     * @psalm-return static<TKey,T>
3719
     * @psalm-mutation-free
3720
     */
3721 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...
3722
    {
3723 16
        if ($recursive === true) {
3724 4
            $array = $this->getArrayRecursiveHelperArrayy($array);
3725 4
            $result = \array_replace_recursive($array, $this->toArray());
3726
        } else {
3727 12
            $result = \array_replace($array, $this->toArray());
3728
        }
3729
3730 16
        return static::create(
3731 16
            $result,
3732 16
            $this->iteratorClass,
3733 16
            false
3734
        );
3735
    }
3736
3737
    /**
3738
     * Merge the current array into the new $array.
3739
     *
3740
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
3741
     * - create new indexes
3742
     *
3743
     * @param array $array
3744
     * @param bool  $recursive
3745
     *
3746
     * @return static
3747
     *                <p>(Immutable)</p>
3748
     *
3749
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3750
     * @psalm-return static<TKey,T>
3751
     * @psalm-mutation-free
3752
     */
3753 20 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...
3754
    {
3755 20
        if ($recursive === true) {
3756 7
            $array = $this->getArrayRecursiveHelperArrayy($array);
3757 7
            $result = \array_merge_recursive($array, $this->toArray());
3758
        } else {
3759 13
            $result = \array_merge($array, $this->toArray());
3760
        }
3761
3762 20
        return static::create(
3763 20
            $result,
3764 20
            $this->iteratorClass,
3765 20
            false
3766
        );
3767
    }
3768
3769
    /**
3770
     * @return ArrayyMeta|static
3771
     */
3772 15
    public static function meta()
3773
    {
3774 15
        return (new ArrayyMeta())->getMetaObject(static::class);
3775
    }
3776
3777
    /**
3778
     * Get the min value from an array.
3779
     *
3780
     * @return false|mixed
3781
     *                     <p>Will return false if there are no values.</p>
3782
     */
3783 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...
3784
    {
3785 10
        if ($this->count() === 0) {
3786 1
            return false;
3787
        }
3788
3789 9
        $min = false;
3790 9
        foreach ($this->getGeneratorByReference() as &$value) {
3791
            if (
3792 9
                $min === false
3793
                ||
3794 9
                $value < $min
3795
            ) {
3796 9
                $min = $value;
3797
            }
3798
        }
3799
3800 9
        return $min;
3801
    }
3802
3803
    /**
3804
     * Get the most used value from the array.
3805
     *
3806
     * @return mixed|null
3807
     *                    <p>(Immutable) Return null if there wasn't a element.</p>
3808
     * @psalm-mutation-free
3809
     */
3810 3
    public function mostUsedValue()
3811
    {
3812 3
        return $this->countValues()->arsortImmutable()->firstKey();
3813
    }
3814
3815
    /**
3816
     * Get the most used value from the array.
3817
     *
3818
     * @param int|null $number <p>How many values you will take?</p>
3819
     *
3820
     * @return static
3821
     *                <p>(Immutable)</p>
3822
     *
3823
     * @psalm-return static<TKey,T>
3824
     * @psalm-mutation-free
3825
     */
3826 3
    public function mostUsedValues(int $number = null): self
3827
    {
3828 3
        return $this->countValues()->arsortImmutable()->firstsKeys($number);
3829
    }
3830
3831
    /**
3832
     * Move an array element to a new index.
3833
     *
3834
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
3835
     *
3836
     * @param int|string $from
3837
     * @param int        $to
3838
     *
3839
     * @return static
3840
     *                <p>(Immutable)</p>
3841
     *
3842
     * @psalm-return static<TKey,T>
3843
     * @psalm-mutation-free
3844
     */
3845 1
    public function moveElement($from, $to): self
3846
    {
3847 1
        $array = $this->toArray();
3848
3849 1
        if ((int) $from === $from) {
3850 1
            $tmp = \array_splice($array, $from, 1);
3851 1
            \array_splice($array, (int) $to, 0, $tmp);
3852 1
            $output = $array;
3853 1
        } elseif ((string) $from === $from) {
3854 1
            $indexToMove = \array_search($from, \array_keys($array), true);
3855 1
            $itemToMove = $array[$from];
3856 1
            if ($indexToMove !== false) {
3857 1
                \array_splice($array, $indexToMove, 1);
3858
            }
3859 1
            $i = 0;
3860 1
            $output = [];
3861 1
            foreach ($array as $key => $item) {
3862 1
                if ($i === $to) {
3863 1
                    $output[$from] = $itemToMove;
3864
                }
3865 1
                $output[$key] = $item;
3866 1
                ++$i;
3867
            }
3868
        } else {
3869
            $output = [];
3870
        }
3871
3872 1
        return static::create(
3873 1
            $output,
3874 1
            $this->iteratorClass,
3875 1
            false
3876
        );
3877
    }
3878
3879
    /**
3880
     * Move an array element to the first place.
3881
     *
3882
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3883
     *       loss the keys of an indexed array.
3884
     *
3885
     * @param int|string $key
3886
     *
3887
     * @return static
3888
     *                <p>(Immutable)</p>
3889
     *
3890
     * @psalm-return static<TKey,T>
3891
     * @psalm-mutation-free
3892
     */
3893 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...
3894
    {
3895 1
        $array = $this->toArray();
3896
3897 1
        if ($this->offsetExists($key)) {
3898 1
            $tmpValue = $this->get($key);
3899 1
            unset($array[$key]);
3900 1
            $array = [$key => $tmpValue] + $array;
3901
        }
3902
3903 1
        return static::create(
3904 1
            $array,
3905 1
            $this->iteratorClass,
3906 1
            false
3907
        );
3908
    }
3909
3910
    /**
3911
     * Move an array element to the last place.
3912
     *
3913
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3914
     *       loss the keys of an indexed array.
3915
     *
3916
     * @param int|string $key
3917
     *
3918
     * @return static
3919
     *                <p>(Immutable)</p>
3920
     *
3921
     * @psalm-return static<TKey,T>
3922
     * @psalm-mutation-free
3923
     */
3924 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...
3925
    {
3926 1
        $array = $this->toArray();
3927
3928 1
        if ($this->offsetExists($key)) {
3929 1
            $tmpValue = $this->get($key);
3930 1
            unset($array[$key]);
3931 1
            $array += [$key => $tmpValue];
3932
        }
3933
3934 1
        return static::create(
3935 1
            $array,
3936 1
            $this->iteratorClass,
3937 1
            false
3938
        );
3939
    }
3940
3941
    /**
3942
     * Moves the internal iterator position to the next element and returns this element.
3943
     *
3944
     * @return false|mixed
3945
     *                     <p>(Mutable) Will return false if there are no values.</p>
3946
     */
3947
    public function next()
3948
    {
3949
        return \next($this->array);
3950
    }
3951
3952
    /**
3953
     * Get the next nth keys and values from the array.
3954
     *
3955
     * @param int $step
3956
     * @param int $offset
3957
     *
3958
     * @return static
3959
     *                <p>(Immutable)</p>
3960
     *
3961
     * @psalm-return static<TKey,T>
3962
     * @psalm-mutation-free
3963
     */
3964
    public function nth(int $step, int $offset = 0): self
3965
    {
3966 1
        $arrayFunction = function () use ($step, $offset): \Generator {
3967 1
            $position = 0;
3968 1
            foreach ($this->getGenerator() as $key => $value) {
3969 1
                if ($position++ % $step !== $offset) {
3970 1
                    continue;
3971
                }
3972
3973 1
                yield $key => $value;
3974
            }
3975 1
        };
3976
3977 1
        return static::create(
3978 1
            $arrayFunction,
3979 1
            $this->iteratorClass,
3980 1
            false
3981
        );
3982
    }
3983
3984
    /**
3985
     * Get a subset of the items from the given array.
3986
     *
3987
     * @param mixed[] $keys
3988
     *
3989
     * @return static
3990
     *                <p>(Immutable)</p>
3991
     *
3992
     * @psalm-return static<TKey,T>
3993
     * @psalm-mutation-free
3994
     */
3995 1
    public function only(array $keys): self
3996
    {
3997 1
        $array = $this->toArray();
3998
3999 1
        return static::create(
4000 1
            \array_intersect_key($array, \array_flip($keys)),
4001 1
            $this->iteratorClass,
4002 1
            false
4003
        );
4004
    }
4005
4006
    /**
4007
     * Pad array to the specified size with a given value.
4008
     *
4009
     * @param int   $size  <p>Size of the result array.</p>
4010
     * @param mixed $value <p>Empty value by default.</p>
4011
     *
4012
     * @return static
4013
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
4014
     *
4015
     * @psalm-return static<TKey,T>
4016
     * @psalm-mutation-free
4017
     */
4018 5
    public function pad(int $size, $value): self
4019
    {
4020 5
        return static::create(
4021 5
            \array_pad($this->toArray(), $size, $value),
4022 5
            $this->iteratorClass,
4023 5
            false
4024
        );
4025
    }
4026
4027
    /**
4028
     * Partitions this array in two array according to a predicate.
4029
     * Keys are preserved in the resulting array.
4030
     *
4031
     * @param \Closure $closure
4032
     *                          <p>The predicate on which to partition.</p>
4033
     *
4034
     * @return array<int, static>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

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

Loading history...
4035
     *                    <p>An array with two elements. The first element contains the array
4036
     *                    of elements where the predicate returned TRUE, the second element
4037
     *                    contains the array of elements where the predicate returned FALSE.</p>
4038
     *
4039
     * @psalm-return array<int, static<TKey,T>>
4040
     */
4041 1
    public function partition(\Closure $closure): array
4042
    {
4043
        // init
4044 1
        $matches = [];
4045 1
        $noMatches = [];
4046
4047 1
        foreach ($this->array as $key => $value) {
4048 1
            if ($closure($value, $key)) {
4049 1
                $matches[$key] = $value;
4050
            } else {
4051 1
                $noMatches[$key] = $value;
4052
            }
4053
        }
4054
4055 1
        return [self::create($matches), self::create($noMatches)];
4056
    }
4057
4058
    /**
4059
     * Pop a specified value off the end of the current array.
4060
     *
4061
     * @return mixed|null
4062
     *                    <p>(Mutable) The popped element from the current array or null if the array is e.g. empty.</p>
4063
     */
4064 5
    public function pop()
4065
    {
4066 5
        $this->generatorToArray();
4067
4068 5
        return \array_pop($this->array);
4069
    }
4070
4071
    /**
4072
     * Prepend a (key) + value to the current array.
4073
     *
4074
     * @param mixed $value
4075
     * @param mixed $key
4076
     *
4077
     * @return $this
4078
     *               <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
4079
     *
4080
     * @psalm-return static<TKey,T>
4081
     */
4082 11
    public function prepend($value, $key = null)
4083
    {
4084 11
        $this->generatorToArray();
4085
4086 11
        if ($this->properties !== []) {
4087 3
            $this->checkType($key, $value);
4088
        }
4089
4090 9
        if ($key === null) {
4091 8
            \array_unshift($this->array, $value);
4092
        } else {
4093 2
            $this->array = [$key => $value] + $this->array;
4094
        }
4095
4096 9
        return $this;
4097
    }
4098
4099
    /**
4100
     * Add a suffix to each key.
4101
     *
4102
     * @param mixed $suffix
4103
     *
4104
     * @return static
4105
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
4106
     *
4107
     * @psalm-return static<TKey,T>
4108
     * @psalm-mutation-free
4109
     */
4110 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...
4111
    {
4112
        // init
4113 10
        $result = [];
4114
4115 10
        foreach ($this->getGenerator() as $key => $item) {
4116 9
            if ($item instanceof self) {
4117
                $result[$key] = $item->prependToEachKey($suffix);
4118 9
            } elseif (\is_array($item) === true) {
4119
                $result[$key] = self::create(
4120
                    $item,
4121
                    $this->iteratorClass,
4122
                    false
4123
                )->prependToEachKey($suffix)
4124
                    ->toArray();
4125
            } else {
4126 9
                $result[$key . $suffix] = $item;
4127
            }
4128
        }
4129
4130 10
        return self::create(
4131 10
            $result,
4132 10
            $this->iteratorClass,
4133 10
            false
4134
        );
4135
    }
4136
4137
    /**
4138
     * Add a suffix to each value.
4139
     *
4140
     * @param mixed $suffix
4141
     *
4142
     * @return static
4143
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
4144
     *
4145
     * @psalm-return static<TKey,T>
4146
     * @psalm-mutation-free
4147
     */
4148 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...
4149
    {
4150
        // init
4151 10
        $result = [];
4152
4153 10
        foreach ($this->getGenerator() as $key => $item) {
4154 9
            if ($item instanceof self) {
4155
                $result[$key] = $item->prependToEachValue($suffix);
4156 9
            } elseif (\is_array($item) === true) {
4157
                $result[$key] = self::create(
4158
                    $item,
4159
                    $this->iteratorClass,
4160
                    false
4161
                )->prependToEachValue($suffix)
4162
                    ->toArray();
4163 9
            } elseif (\is_object($item) === true) {
4164 1
                $result[$key] = $item;
4165
            } else {
4166 9
                $result[$key] = $item . $suffix;
4167
            }
4168
        }
4169
4170 10
        return self::create(
4171 10
            $result,
4172 10
            $this->iteratorClass,
4173 10
            false
4174
        );
4175
    }
4176
4177
    /**
4178
     * Return the value of a given key and
4179
     * delete the key.
4180
     *
4181
     * @param int|int[]|string|string[]|null $keyOrKeys
4182
     * @param mixed                          $fallback
4183
     *
4184
     * @return mixed
4185
     */
4186 5
    public function pull($keyOrKeys = null, $fallback = null)
4187
    {
4188 5
        if ($keyOrKeys === null) {
4189 1
            $array = $this->toArray();
4190 1
            $this->clear();
4191
4192 1
            return $array;
4193
        }
4194
4195 4
        if (\is_array($keyOrKeys) === true) {
4196 1
            $valueOrValues = [];
4197 1
            foreach ($keyOrKeys as $key) {
4198 1
                $valueOrValues[] = $this->get($key, $fallback);
4199 1
                $this->offsetUnset($key);
4200
            }
4201
        } else {
4202 4
            $valueOrValues = $this->get($keyOrKeys, $fallback);
4203 4
            $this->offsetUnset($keyOrKeys);
4204
        }
4205
4206 4
        return $valueOrValues;
4207
    }
4208
4209
    /**
4210
     * Push one or more values onto the end of array at once.
4211
     *
4212
     * @param array ...$args
4213
     *
4214
     * @return $this
4215
     *               <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
4216
     *
4217
     * @noinspection ReturnTypeCanBeDeclaredInspection
4218
     *
4219
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$args
4220
     * @psalm-return static<TKey,T>
4221
     */
4222 7
    public function push(...$args)
4223
    {
4224 7
        $this->generatorToArray();
4225
4226
        if (
4227 7
            $this->checkPropertyTypes
4228
            &&
4229 7
            $this->properties !== []
4230
        ) {
4231 1
            foreach ($args as $key => $value) {
4232 1
                $this->checkType($key, $value);
4233
            }
4234
        }
4235
4236 7
        \array_push($this->array, ...$args);
4237
4238 7
        return $this;
4239
    }
4240
4241
    /**
4242
     * Get a random value from the current array.
4243
     *
4244
     * @param int|null $number <p>How many values you will take?</p>
4245
     *
4246
     * @return static
4247
     *                <p>(Immutable)</p>
4248
     *
4249
     * @psalm-return static<int|array-key,T>
4250
     */
4251 19
    public function randomImmutable(int $number = null): self
4252
    {
4253 19
        $this->generatorToArray();
4254
4255 19
        if ($this->count() === 0) {
4256 1
            return static::create(
4257 1
                [],
4258 1
                $this->iteratorClass,
4259 1
                false
4260
            );
4261
        }
4262
4263 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...
4264
            /** @noinspection NonSecureArrayRandUsageInspection */
4265 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
4266
4267 13
            return static::create(
4268 13
                $arrayRandValue,
4269 13
                $this->iteratorClass,
4270 13
                false
4271
            );
4272
        }
4273
4274 6
        $arrayTmp = $this->array;
4275
        /** @noinspection NonSecureShuffleUsageInspection */
4276 6
        \shuffle($arrayTmp);
4277
4278 6
        return static::create(
4279 6
            $arrayTmp,
4280 6
            $this->iteratorClass,
4281 6
            false
4282 6
        )->firstsImmutable($number);
4283
    }
4284
4285
    /**
4286
     * Pick a random key/index from the keys of this array.
4287
     *
4288
     * @throws \RangeException If array is empty
4289
     *
4290
     * @return mixed
4291
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
4292
     */
4293 4
    public function randomKey()
4294
    {
4295 4
        $result = $this->randomKeys(1);
4296
4297 4
        if (!isset($result[0])) {
4298
            $result[0] = null;
4299
        }
4300
4301 4
        return $result[0];
4302
    }
4303
4304
    /**
4305
     * Pick a given number of random keys/indexes out of this array.
4306
     *
4307
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
4308
     *
4309
     * @throws \RangeException If array is empty
4310
     *
4311
     * @return static
4312
     *                <p>(Immutable)</p>
4313
     *
4314
     * @psalm-return static<TKey,T>
4315
     */
4316 13
    public function randomKeys(int $number): self
4317
    {
4318 13
        $this->generatorToArray();
4319
4320 13
        $count = $this->count();
4321
4322
        if (
4323 13
            $number === 0
4324
            ||
4325 13
            $number > $count
4326
        ) {
4327 2
            throw new \RangeException(
4328 2
                \sprintf(
4329 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
4330 2
                    $number,
4331 2
                    $count
4332
                )
4333
            );
4334
        }
4335
4336 11
        $result = (array) \array_rand($this->array, $number);
4337
4338 11
        return static::create(
4339 11
            $result,
4340 11
            $this->iteratorClass,
4341 11
            false
4342
        );
4343
    }
4344
4345
    /**
4346
     * Get a random value from the current array.
4347
     *
4348
     * @param int|null $number <p>How many values you will take?</p>
4349
     *
4350
     * @return $this
4351
     *               <p>(Mutable) Return this Arrayy object.</p>
4352
     *
4353
     * @psalm-return static<TKey,T>
4354
     */
4355 17
    public function randomMutable(int $number = null): self
4356
    {
4357 17
        $this->generatorToArray();
4358
4359 17
        if ($this->count() === 0) {
4360
            return static::create(
4361
                [],
4362
                $this->iteratorClass,
4363
                false
4364
            );
4365
        }
4366
4367 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...
4368
            /** @noinspection NonSecureArrayRandUsageInspection */
4369 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
4370 7
            $this->array = $arrayRandValue;
4371
4372 7
            return $this;
4373
        }
4374
4375
        /** @noinspection NonSecureShuffleUsageInspection */
4376 11
        \shuffle($this->array);
4377
4378 11
        return $this->firstsMutable($number);
4379
    }
4380
4381
    /**
4382
     * Pick a random value from the values of this array.
4383
     *
4384
     * @return mixed
4385
     *               <p>Get a random value or null if there wasn't a value.</p>
4386
     */
4387 4
    public function randomValue()
4388
    {
4389 4
        $result = $this->randomImmutable();
4390
4391 4
        if (!isset($result[0])) {
4392
            $result[0] = null;
4393
        }
4394
4395 4
        return $result[0];
4396
    }
4397
4398
    /**
4399
     * Pick a given number of random values out of this array.
4400
     *
4401
     * @param int $number
4402
     *
4403
     * @return static
4404
     *                <p>(Mutable)</p>
4405
     *
4406
     * @psalm-return static<TKey,T>
4407
     */
4408 7
    public function randomValues(int $number): self
4409
    {
4410 7
        return $this->randomMutable($number);
4411
    }
4412
4413
    /**
4414
     * Get a random value from an array, with the ability to skew the results.
4415
     *
4416
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
4417
     *
4418
     * @param array    $array
4419
     * @param int|null $number <p>How many values you will take?</p>
4420
     *
4421
     * @return static<int,mixed>
0 ignored issues
show
Documentation introduced by
The doc-type static<int,mixed> could not be parsed: Expected "|" or "end of type", but got "<" at position 6. (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...
4422
     *                           <p>(Immutable)</p>
4423
     *
4424
     * @psalm-param  array<mixed,mixed> $array
4425
     * @psalm-return static<int|array-key,T>
4426
     */
4427 9
    public function randomWeighted(array $array, int $number = null): self
4428
    {
4429
        // init
4430 9
        $options = [];
4431
4432 9
        foreach ($array as $option => $weight) {
4433 9
            if ($this->searchIndex($option) !== false) {
4434 9
                for ($i = 0; $i < $weight; ++$i) {
4435 1
                    $options[] = $option;
4436
                }
4437
            }
4438
        }
4439
4440 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
4441
    }
4442
4443
    /**
4444
     * Reduce the current array via callable e.g. anonymous-function.
4445
     *
4446
     * @param callable $callable
4447
     * @param mixed    $init
4448
     *
4449
     * @return static
4450
     *                <p>(Immutable)</p>
4451
     *
4452
     * @psalm-return static<TKey,T>
4453
     * @psalm-mutation-free
4454
     */
4455 18
    public function reduce($callable, $init = []): self
4456
    {
4457 18
        if ($this->generator) {
4458 1
            $result = $init;
4459
4460 1
            foreach ($this->getGenerator() as $value) {
4461 1
                $result = $callable($result, $value);
4462
            }
4463
4464 1
            return static::create(
4465 1
                $result,
4466 1
                $this->iteratorClass,
4467 1
                false
4468
            );
4469
        }
4470
4471 18
        $result = \array_reduce($this->array, $callable, $init);
4472
4473 18
        if ($result === null) {
4474
            $this->array = [];
4475
        } else {
4476 18
            $this->array = (array) $result;
4477
        }
4478
4479 18
        return static::create(
4480 18
            $this->array,
4481 18
            $this->iteratorClass,
4482 18
            false
4483
        );
4484
    }
4485
4486
    /**
4487
     * @param bool $unique
4488
     *
4489
     * @return static
4490
     *                <p>(Immutable)</p>
4491
     *
4492
     * @psalm-return static<TKey,T>
4493
     * @psalm-mutation-free
4494
     */
4495 14
    public function reduce_dimension(bool $unique = true): self
4496
    {
4497
        // init
4498 14
        $result = [];
4499
4500 14
        foreach ($this->getGenerator() as $val) {
4501 12
            if (\is_array($val) === true) {
4502 5
                $result[] = (new static($val))->reduce_dimension($unique)->toArray();
4503
            } else {
4504 12
                $result[] = [$val];
4505
            }
4506
        }
4507
4508 14
        $result = $result === [] ? [] : \array_merge(...$result);
4509
4510 14
        $resultArrayy = new static($result);
4511
4512
        /**
4513
         * @psalm-suppress ImpureMethodCall - object is already re-created
4514
         * @psalm-suppress InvalidReturnStatement - why?
4515
         */
4516 14
        return $unique ? $resultArrayy->unique() : $resultArrayy;
4517
    }
4518
4519
    /**
4520
     * Create a numerically re-indexed Arrayy object.
4521
     *
4522
     * @return $this
4523
     *               <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
4524
     *
4525
     * @psalm-return static<TKey,T>
4526
     */
4527 9
    public function reindex(): self
4528
    {
4529 9
        $this->generatorToArray(false);
4530
4531 9
        $this->array = \array_values($this->array);
4532
4533 9
        return $this;
4534
    }
4535
4536
    /**
4537
     * Return all items that fail the truth test.
4538
     *
4539
     * @param \Closure $closure
4540
     *
4541
     * @return static
4542
     *                <p>(Immutable)</p>
4543
     *
4544
     * @psalm-return static<TKey,T>
4545
     * @psalm-mutation-free
4546
     */
4547 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...
4548
    {
4549
        // init
4550 1
        $filtered = [];
4551
4552 1
        foreach ($this->getGenerator() as $key => $value) {
4553 1
            if (!$closure($value, $key)) {
4554 1
                $filtered[$key] = $value;
4555
            }
4556
        }
4557
4558 1
        return static::create(
4559 1
            $filtered,
4560 1
            $this->iteratorClass,
4561 1
            false
4562
        );
4563
    }
4564
4565
    /**
4566
     * Remove a value from the current array (optional using dot-notation).
4567
     *
4568
     * @param mixed $key
4569
     *
4570
     * @return static
4571
     *                <p>(Mutable)</p>
4572
     *
4573
     * @psalm-param  TKey $key
4574
     * @psalm-return static<TKey,T>
4575
     */
4576 21
    public function remove($key)
4577
    {
4578
        // recursive call
4579 21
        if (\is_array($key) === true) {
4580
            foreach ($key as $k) {
4581
                $this->internalRemove($k);
4582
            }
4583
4584
            return static::create(
4585
                $this->toArray(),
4586
                $this->iteratorClass,
4587
                false
4588
            );
4589
        }
4590
4591 21
        $this->internalRemove($key);
4592
4593 21
        return static::create(
4594 21
            $this->toArray(),
4595 21
            $this->iteratorClass,
4596 21
            false
4597
        );
4598
    }
4599
4600
    /**
4601
     * alias: for "Arrayy->removeValue()"
4602
     *
4603
     * @param mixed $element
4604
     *
4605
     * @return static
4606
     *                <p>(Immutable)</p>
4607
     *
4608
     * @psalm-param  T $element
4609
     * @psalm-return static<TKey,T>
4610
     * @psalm-mutation-free
4611
     */
4612 8
    public function removeElement($element)
4613
    {
4614 8
        return $this->removeValue($element);
4615
    }
4616
4617
    /**
4618
     * Remove the first value from the current array.
4619
     *
4620
     * @return static
4621
     *                <p>(Immutable)</p>
4622
     *
4623
     * @psalm-return static<TKey,T>
4624
     * @psalm-mutation-free
4625
     */
4626 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...
4627
    {
4628 7
        $tmpArray = $this->toArray();
4629
4630 7
        \array_shift($tmpArray);
4631
4632 7
        return static::create(
4633 7
            $tmpArray,
4634 7
            $this->iteratorClass,
4635 7
            false
4636
        );
4637
    }
4638
4639
    /**
4640
     * Remove the last value from the current array.
4641
     *
4642
     * @return static
4643
     *                <p>(Immutable)</p>
4644
     *
4645
     * @psalm-return static<TKey,T>
4646
     * @psalm-mutation-free
4647
     */
4648 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...
4649
    {
4650 7
        $tmpArray = $this->toArray();
4651
4652 7
        \array_pop($tmpArray);
4653
4654 7
        return static::create(
4655 7
            $tmpArray,
4656 7
            $this->iteratorClass,
4657 7
            false
4658
        );
4659
    }
4660
4661
    /**
4662
     * Removes a particular value from an array (numeric or associative).
4663
     *
4664
     * @param mixed $value
4665
     *
4666
     * @return static
4667
     *                <p>(Immutable)</p>
4668
     *
4669
     * @psalm-param  T $value
4670
     * @psalm-return static<TKey,T>
4671
     * @psalm-mutation-free
4672
     */
4673 8
    public function removeValue($value): self
4674
    {
4675 8
        $this->generatorToArray();
4676
4677
        // init
4678 8
        $isSequentialArray = $this->isSequential();
4679
4680 8
        foreach ($this->array as $key => $item) {
4681 7
            if ($item === $value) {
4682 7
                unset($this->array[$key]);
4683
            }
4684
        }
4685
4686 8
        if ($isSequentialArray) {
4687 6
            $this->array = \array_values($this->array);
4688
        }
4689
4690 8
        return static::create(
4691 8
            $this->array,
4692 8
            $this->iteratorClass,
4693 8
            false
4694
        );
4695
    }
4696
4697
    /**
4698
     * Generate array of repeated arrays.
4699
     *
4700
     * @param int $times <p>How many times has to be repeated.</p>
4701
     *
4702
     * @return static
4703
     *                <p>(Immutable)</p>
4704
     *
4705
     * @psalm-return static<TKey,T>
4706
     * @psalm-mutation-free
4707
     */
4708 1
    public function repeat($times): self
4709
    {
4710 1
        if ($times === 0) {
4711 1
            return static::create([], $this->iteratorClass);
4712
        }
4713
4714 1
        return static::create(
4715 1
            \array_fill(0, (int) $times, $this->toArray()),
4716 1
            $this->iteratorClass,
4717 1
            false
4718
        );
4719
    }
4720
4721
    /**
4722
     * Replace a key with a new key/value pair.
4723
     *
4724
     * @param mixed $oldKey
4725
     * @param mixed $newKey
4726
     * @param mixed $newValue
4727
     *
4728
     * @return static
4729
     *                <p>(Immutable)</p>
4730
     *
4731
     * @psalm-return static<TKey,T>
4732
     * @psalm-mutation-free
4733
     */
4734 5
    public function replace($oldKey, $newKey, $newValue): self
4735
    {
4736 5
        $that = clone $this;
4737
4738
        /**
4739
         * @psalm-suppress ImpureMethodCall - object is already cloned
4740
         */
4741 5
        return $that->remove($oldKey)
4742 5
            ->set($newKey, $newValue);
4743
    }
4744
4745
    /**
4746
     * Create an array using the current array as values and the other array as keys.
4747
     *
4748
     * @param array $keys <p>An array of keys.</p>
4749
     *
4750
     * @return static
4751
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
4752
     *
4753
     * @psalm-param  array<mixed,mixed>|array<mixed,TKey> $keys
4754
     * @psalm-return static<TKey,T>
4755
     * @psalm-mutation-free
4756
     */
4757 2
    public function replaceAllKeys(array $keys): self
4758
    {
4759 2
        return static::create(
4760 2
            \array_combine($keys, $this->toArray()),
4761 2
            $this->iteratorClass,
4762 2
            false
4763
        );
4764
    }
4765
4766
    /**
4767
     * Create an array using the current array as keys and the other array as values.
4768
     *
4769
     * @param array $array <p>An array o values.</p>
4770
     *
4771
     * @return static
4772
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
4773
     *
4774
     * @psalm-param  array<mixed,T> $array
4775
     * @psalm-return static<TKey,T>
4776
     * @psalm-mutation-free
4777
     */
4778 2
    public function replaceAllValues(array $array): self
4779
    {
4780 2
        return static::create(
4781 2
            \array_combine($this->array, $array),
4782 2
            $this->iteratorClass,
4783 2
            false
4784
        );
4785
    }
4786
4787
    /**
4788
     * Replace the keys in an array with another set.
4789
     *
4790
     * @param array $keys <p>An array of keys matching the array's size</p>
4791
     *
4792
     * @return static
4793
     *                <p>(Immutable)</p>
4794
     *
4795
     * @psalm-param  array<mixed,mixed>|array<mixed,TKey> $keys
4796
     * @psalm-return static<TKey,T>
4797
     * @psalm-mutation-free
4798
     */
4799 1
    public function replaceKeys(array $keys): self
4800
    {
4801 1
        $values = \array_values($this->toArray());
4802 1
        $result = \array_combine($keys, $values);
4803
4804 1
        return static::create(
4805 1
            $result,
4806 1
            $this->iteratorClass,
4807 1
            false
4808
        );
4809
    }
4810
4811
    /**
4812
     * Replace the first matched value in an array.
4813
     *
4814
     * @param mixed $search      <p>The value to replace.</p>
4815
     * @param mixed $replacement <p>The value to replace.</p>
4816
     *
4817
     * @return static
4818
     *                <p>(Immutable)</p>
4819
     *
4820
     * @psalm-return static<TKey,T>
4821
     * @psalm-mutation-free
4822
     */
4823 3
    public function replaceOneValue($search, $replacement = ''): self
4824
    {
4825 3
        $array = $this->toArray();
4826 3
        $key = \array_search($search, $array, true);
4827
4828 3
        if ($key !== false) {
4829 3
            $array[$key] = $replacement;
4830
        }
4831
4832 3
        return static::create(
4833 3
            $array,
4834 3
            $this->iteratorClass,
4835 3
            false
4836
        );
4837
    }
4838
4839
    /**
4840
     * Replace values in the current array.
4841
     *
4842
     * @param mixed $search      <p>The value to replace.</p>
4843
     * @param mixed $replacement <p>What to replace it with.</p>
4844
     *
4845
     * @return static
4846
     *                <p>(Immutable)</p>
4847
     *
4848
     * @psalm-return static<TKey,T>
4849
     * @psalm-mutation-free
4850
     */
4851 1
    public function replaceValues($search, $replacement = ''): self
4852
    {
4853
        /**
4854
         * @psalm-suppress MissingClosureReturnType
4855
         * @psalm-suppress MissingClosureParamType
4856
         */
4857 1
        return $this->each(
4858 1
            static function ($value) use ($search, $replacement) {
4859 1
                return \str_replace($search, $replacement, $value);
4860 1
            }
4861
        );
4862
    }
4863
4864
    /**
4865
     * Get the last elements from index $from until the end of this array.
4866
     *
4867
     * @param int $from
4868
     *
4869
     * @return static
4870
     *                <p>(Immutable)</p>
4871
     *
4872
     * @psalm-return static<TKey,T>
4873
     * @psalm-mutation-free
4874
     */
4875 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...
4876
    {
4877 15
        $tmpArray = $this->toArray();
4878
4879 15
        return static::create(
4880 15
            \array_splice($tmpArray, $from),
4881 15
            $this->iteratorClass,
4882 15
            false
4883
        );
4884
    }
4885
4886
    /**
4887
     * Return the array in the reverse order.
4888
     *
4889
     * @return $this
4890
     *               <p>(Mutable) Return this Arrayy object.</p>
4891
     *
4892
     * @psalm-return static<TKey,T>
4893
     */
4894 9
    public function reverse(): self
4895
    {
4896 9
        $this->generatorToArray();
4897
4898 9
        $this->array = \array_reverse($this->array);
4899
4900 9
        return $this;
4901
    }
4902
4903
    /**
4904
     * Sort an array in reverse order.
4905
     *
4906
     * @param int $sort_flags [optional] <p>
4907
     *                        You may modify the behavior of the sort using the optional
4908
     *                        parameter sort_flags, for details
4909
     *                        see sort.
4910
     *                        </p>
4911
     *
4912
     * @return $this
4913
     *               <p>(Mutable) Return this Arrayy object.</p>
4914
     *
4915
     * @psalm-return static<TKey,T>
4916
     */
4917 4
    public function rsort(int $sort_flags = 0): self
4918
    {
4919 4
        $this->generatorToArray();
4920
4921 4
        \rsort($this->array, $sort_flags);
4922
4923 4
        return $this;
4924
    }
4925
4926
    /**
4927
     * Sort an array in reverse order.
4928
     *
4929
     * @param int $sort_flags [optional] <p>
4930
     *                        You may modify the behavior of the sort using the optional
4931
     *                        parameter sort_flags, for details
4932
     *                        see sort.
4933
     *                        </p>
4934
     *
4935
     * @return $this
4936
     *               <p>(Immutable) Return this Arrayy object.</p>
4937
     *
4938
     * @psalm-return static<TKey,T>
4939
     * @psalm-mutation-free
4940
     */
4941 4
    public function rsortImmutable(int $sort_flags = 0): self
4942
    {
4943 4
        $that = clone $this;
4944
4945
        /**
4946
         * @psalm-suppress ImpureMethodCall - object is already cloned
4947
         */
4948 4
        $that->rsort($sort_flags);
4949
4950 4
        return $that;
4951
    }
4952
4953
    /**
4954
     * Search for the first index of the current array via $value.
4955
     *
4956
     * @param mixed $value
4957
     *
4958
     * @return false|float|int|string
4959
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
4960
     * @psalm-mutation-free
4961
     */
4962 21
    public function searchIndex($value)
4963
    {
4964 21
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
4965 20
            if ($value === $valueFromArray) {
4966 20
                return $keyFromArray;
4967
            }
4968
        }
4969
4970 11
        return false;
4971
    }
4972
4973
    /**
4974
     * Search for the value of the current array via $index.
4975
     *
4976
     * @param mixed $index
4977
     *
4978
     * @return static
4979
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
4980
     *
4981
     * @psalm-return static<TKey,T>
4982
     * @psalm-mutation-free
4983
     */
4984 9
    public function searchValue($index): self
4985
    {
4986 9
        $this->generatorToArray();
4987
4988
        // init
4989 9
        $return = [];
4990
4991 9
        if ($this->array === []) {
4992
            return static::create(
4993
                [],
4994
                $this->iteratorClass,
4995
                false
4996
            );
4997
        }
4998
4999
        // php cast "bool"-index into "int"-index
5000 9
        if ((bool) $index === $index) {
5001 1
            $index = (int) $index;
5002
        }
5003
5004 9
        if ($this->offsetExists($index)) {
5005 7
            $return = [$this->array[$index]];
5006
        }
5007
5008 9
        return static::create(
5009 9
            $return,
5010 9
            $this->iteratorClass,
5011 9
            false
5012
        );
5013
    }
5014
5015
    /**
5016
     * Set a value for the current array (optional using dot-notation).
5017
     *
5018
     * @param string $key   <p>The key to set.</p>
5019
     * @param mixed  $value <p>Its value.</p>
5020
     *
5021
     * @return $this
5022
     *               <p>(Mutable) Return this Arrayy object.</p>
5023
     *
5024
     * @psalm-param  TKey $key
5025
     * @psalm-param  T $value
5026
     * @psalm-return static<TKey,T>
5027
     */
5028 28
    public function set($key, $value): self
5029
    {
5030 28
        $this->internalSet($key, $value);
5031
5032 27
        return $this;
5033
    }
5034
5035
    /**
5036
     * Get a value from a array and set it if it was not.
5037
     *
5038
     * WARNING: this method only set the value, if the $key is not already set
5039
     *
5040
     * @param mixed $key      <p>The key</p>
5041
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
5042
     *
5043
     * @return mixed
5044
     *               <p>(Mutable)</p>
5045
     */
5046 11
    public function setAndGet($key, $fallback = null)
5047
    {
5048 11
        $this->generatorToArray();
5049
5050
        // If the key doesn't exist, set it.
5051 11
        if (!$this->has($key)) {
5052 4
            $this->array = $this->set($key, $fallback)->toArray();
5053
        }
5054
5055 11
        return $this->get($key);
5056
    }
5057
5058
    /**
5059
     * Shifts a specified value off the beginning of array.
5060
     *
5061
     * @return mixed
5062
     *               <p>(Mutable) A shifted element from the current array.</p>
5063
     */
5064 5
    public function shift()
5065
    {
5066 5
        $this->generatorToArray();
5067
5068 5
        return \array_shift($this->array);
5069
    }
5070
5071
    /**
5072
     * Shuffle the current array.
5073
     *
5074
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
5075
     * @param array $array  [optional]
5076
     *
5077
     * @return static
5078
     *                <p>(Immutable)</p>
5079
     *
5080
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
5081
     * @psalm-return static<TKey,T>
5082
     *
5083
     * @noinspection BadExceptionsProcessingInspection
5084
     * @noinspection RandomApiMigrationInspection
5085
     * @noinspection NonSecureShuffleUsageInspection
5086
     */
5087 2
    public function shuffle(bool $secure = false, array $array = null): self
5088
    {
5089 2
        if ($array === null) {
5090 2
            $array = $this->toArray(false);
5091
        }
5092
5093 2
        if ($secure !== true) {
5094 2
            \shuffle($array);
5095
        } else {
5096 1
            $size = \count($array, \COUNT_NORMAL);
5097 1
            $keys = \array_keys($array);
5098 1
            for ($i = $size - 1; $i > 0; --$i) {
5099
                try {
5100 1
                    $r = \random_int(0, $i);
5101
                } catch (\Exception $e) {
5102
                    $r = \mt_rand(0, $i);
5103
                }
5104 1
                if ($r !== $i) {
5105 1
                    $temp = $array[$keys[$r]];
5106 1
                    $array[$keys[$r]] = $array[$keys[$i]];
5107 1
                    $array[$keys[$i]] = $temp;
5108
                }
5109
            }
5110
        }
5111
5112 2
        foreach ($array as $key => $value) {
5113
            // check if recursive is needed
5114 2
            if (\is_array($value) === true) {
5115 2
                $array[$key] = $this->shuffle($secure, $value);
5116
            }
5117
        }
5118
5119 2
        return static::create(
5120 2
            $array,
5121 2
            $this->iteratorClass,
5122 2
            false
5123
        );
5124
    }
5125
5126
    /**
5127
     * Count the values from the current array.
5128
     *
5129
     * alias: for "Arrayy->count()"
5130
     *
5131
     * @param int $mode
5132
     *
5133
     * @return int
5134
     */
5135 20
    public function size(int $mode = \COUNT_NORMAL): int
5136
    {
5137 20
        return $this->count($mode);
5138
    }
5139
5140
    /**
5141
     * Checks whether array has exactly $size items.
5142
     *
5143
     * @param int $size
5144
     *
5145
     * @return bool
5146
     */
5147 1
    public function sizeIs(int $size): bool
5148
    {
5149
        // init
5150 1
        $itemsTempCount = 0;
5151
5152
        /** @noinspection PhpUnusedLocalVariableInspection */
5153 1
        foreach ($this->getGeneratorByReference() as &$value) {
5154 1
            ++$itemsTempCount;
5155 1
            if ($itemsTempCount > $size) {
5156 1
                return false;
5157
            }
5158
        }
5159
5160 1
        return $itemsTempCount === $size;
5161
    }
5162
5163
    /**
5164
     * Checks whether array has between $fromSize to $toSize items. $toSize can be
5165
     * smaller than $fromSize.
5166
     *
5167
     * @param int $fromSize
5168
     * @param int $toSize
5169
     *
5170
     * @return bool
5171
     */
5172 1
    public function sizeIsBetween(int $fromSize, int $toSize): bool
5173
    {
5174 1
        if ($fromSize > $toSize) {
5175 1
            $tmp = $toSize;
5176 1
            $toSize = $fromSize;
5177 1
            $fromSize = $tmp;
5178
        }
5179
5180
        // init
5181 1
        $itemsTempCount = 0;
5182
5183 1
        foreach ($this->getGenerator() as $key => $value) {
5184 1
            ++$itemsTempCount;
5185 1
            if ($itemsTempCount > $toSize) {
5186 1
                return false;
5187
            }
5188
        }
5189
5190 1
        return $fromSize < $itemsTempCount && $itemsTempCount < $toSize;
5191
    }
5192
5193
    /**
5194
     * Checks whether array has more than $size items.
5195
     *
5196
     * @param int $size
5197
     *
5198
     * @return bool
5199
     */
5200 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...
5201
    {
5202
        // init
5203 1
        $itemsTempCount = 0;
5204
5205 1
        foreach ($this->getGenerator() as $key => $value) {
5206 1
            ++$itemsTempCount;
5207 1
            if ($itemsTempCount > $size) {
5208 1
                return true;
5209
            }
5210
        }
5211
5212 1
        return $itemsTempCount > $size;
5213
    }
5214
5215
    /**
5216
     * Checks whether array has less than $size items.
5217
     *
5218
     * @param int $size
5219
     *
5220
     * @return bool
5221
     */
5222 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...
5223
    {
5224
        // init
5225 1
        $itemsTempCount = 0;
5226
5227 1
        foreach ($this->getGenerator() as $key => $value) {
5228 1
            ++$itemsTempCount;
5229 1
            if ($itemsTempCount > $size) {
5230 1
                return false;
5231
            }
5232
        }
5233
5234 1
        return $itemsTempCount < $size;
5235
    }
5236
5237
    /**
5238
     * Counts all elements in an array, or something in an object.
5239
     *
5240
     * <p>
5241
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
5242
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
5243
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
5244
     * implemented and used in PHP.
5245
     * </p>
5246
     *
5247
     * @return int
5248
     *             <p>
5249
     *             The number of elements in var, which is
5250
     *             typically an array, since anything else will have one
5251
     *             element.
5252
     *             </p>
5253
     *             <p>
5254
     *             If var is not an array or an object with
5255
     *             implemented Countable interface,
5256
     *             1 will be returned.
5257
     *             There is one exception, if var is &null;,
5258
     *             0 will be returned.
5259
     *             </p>
5260
     *             <p>
5261
     *             Caution: count may return 0 for a variable that isn't set,
5262
     *             but it may also return 0 for a variable that has been initialized with an
5263
     *             empty array. Use isset to test if a variable is set.
5264
     *             </p>
5265
     */
5266 10
    public function sizeRecursive(): int
5267
    {
5268 10
        return \count($this->toArray(), \COUNT_RECURSIVE);
5269
    }
5270
5271
    /**
5272
     * Extract a slice of the array.
5273
     *
5274
     * @param int      $offset       <p>Slice begin index.</p>
5275
     * @param int|null $length       <p>Length of the slice.</p>
5276
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
5277
     *
5278
     * @return static
5279
     *                <p>(Immutable) A slice of the original array with length $length.</p>
5280
     *
5281
     * @psalm-return static<TKey,T>
5282
     * @psalm-mutation-free
5283
     */
5284 5
    public function slice(int $offset, int $length = null, bool $preserveKeys = false)
5285
    {
5286 5
        return static::create(
5287 5
            \array_slice(
5288 5
                $this->toArray(),
5289 5
                $offset,
5290 5
                $length,
5291 5
                $preserveKeys
5292
            ),
5293 5
            $this->iteratorClass,
5294 5
            false
5295
        );
5296
    }
5297
5298
    /**
5299
     * Sort the current array and optional you can keep the keys.
5300
     *
5301
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5302
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
5303
     *                              <strong>SORT_NATURAL</strong></p>
5304
     * @param bool       $keepKeys
5305
     *
5306
     * @return static
5307
     *                <p>(Mutable) Return this Arrayy object.</p>
5308
     *
5309
     * @psalm-return static<TKey,T>
5310
     */
5311 20
    public function sort(
5312
        $direction = \SORT_ASC,
5313
        int $strategy = \SORT_REGULAR,
5314
        bool $keepKeys = false
5315
    ): self {
5316 20
        $this->generatorToArray();
5317
5318 20
        return $this->sorting(
5319 20
            $this->array,
5320 20
            $direction,
5321 20
            $strategy,
5322 20
            $keepKeys
5323
        );
5324
    }
5325
5326
    /**
5327
     * Sort the current array and optional you can keep the keys.
5328
     *
5329
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5330
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
5331
     *                              <strong>SORT_NATURAL</strong></p>
5332
     * @param bool       $keepKeys
5333
     *
5334
     * @return static
5335
     *                <p>(Immutable) Return this Arrayy object.</p>
5336
     *
5337
     * @psalm-return static<TKey,T>
5338
     */
5339 12
    public function sortImmutable(
5340
        $direction = \SORT_ASC,
5341
        int $strategy = \SORT_REGULAR,
5342
        bool $keepKeys = false
5343
    ): self {
5344 12
        $that = clone $this;
5345
5346 12
        $that->generatorToArray();
5347
5348 12
        return $that->sorting(
5349 12
            $that->array,
5350 12
            $direction,
5351 12
            $strategy,
5352 12
            $keepKeys
5353
        );
5354
    }
5355
5356
    /**
5357
     * Sort the current array by key.
5358
     *
5359
     * @see          http://php.net/manual/en/function.ksort.php
5360
     * @see          http://php.net/manual/en/function.krsort.php
5361
     *
5362
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5363
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5364
     *                              <strong>SORT_NATURAL</strong></p>
5365
     *
5366
     * @return $this
5367
     *               <p>(Mutable) Return this Arrayy object.</p>
5368
     *
5369
     * @psalm-return static<TKey,T>
5370
     */
5371 18
    public function sortKeys(
5372
        $direction = \SORT_ASC,
5373
        int $strategy = \SORT_REGULAR
5374
    ): self {
5375 18
        $this->generatorToArray();
5376
5377 18
        $this->sorterKeys($this->array, $direction, $strategy);
5378
5379 18
        return $this;
5380
    }
5381
5382
    /**
5383
     * Sort the current array by key.
5384
     *
5385
     * @see          http://php.net/manual/en/function.ksort.php
5386
     * @see          http://php.net/manual/en/function.krsort.php
5387
     *
5388
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5389
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5390
     *                              <strong>SORT_NATURAL</strong></p>
5391
     *
5392
     * @return $this
5393
     *               <p>(Immutable) Return this Arrayy object.</p>
5394
     *
5395
     * @psalm-return static<TKey,T>
5396
     * @psalm-mutation-free
5397
     */
5398 8
    public function sortKeysImmutable(
5399
        $direction = \SORT_ASC,
5400
        int $strategy = \SORT_REGULAR
5401
    ): self {
5402 8
        $that = clone $this;
5403
5404
        /**
5405
         * @psalm-suppress ImpureMethodCall - object is already cloned
5406
         */
5407 8
        $that->sortKeys($direction, $strategy);
5408
5409 8
        return $that;
5410
    }
5411
5412
    /**
5413
     * Sort the current array by value.
5414
     *
5415
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5416
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5417
     *                              <strong>SORT_NATURAL</strong></p>
5418
     *
5419
     * @return static
5420
     *                <p>(Mutable)</p>
5421
     *
5422
     * @psalm-return static<TKey,T>
5423
     */
5424 1
    public function sortValueKeepIndex(
5425
        $direction = \SORT_ASC,
5426
        int $strategy = \SORT_REGULAR
5427
    ): self {
5428 1
        return $this->sort($direction, $strategy, true);
5429
    }
5430
5431
    /**
5432
     * Sort the current array by value.
5433
     *
5434
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5435
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5436
     *                              <strong>SORT_NATURAL</strong></p>
5437
     *
5438
     * @return static
5439
     *                <p>(Mutable)</p>
5440
     *
5441
     * @psalm-return static<TKey,T>
5442
     */
5443 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
5444
    {
5445 1
        return $this->sort($direction, $strategy, false);
5446
    }
5447
5448
    /**
5449
     * Sort a array by value, by a closure or by a property.
5450
     *
5451
     * - If the sorter is null, the array is sorted naturally.
5452
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
5453
     *
5454
     * @param callable|string|null $sorter
5455
     * @param int|string           $direction <p>use <strong>SORT_ASC</strong> (default) or
5456
     *                                        <strong>SORT_DESC</strong></p>
5457
     * @param int                  $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5458
     *                                        <strong>SORT_NATURAL</strong></p>
5459
     *
5460
     * @return static
5461
     *                <p>(Immutable)</p>
5462
     *
5463
     * @psalm-return static<TKey,T>
5464
     * @psalm-mutation-free
5465
     */
5466 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
5467
    {
5468 1
        $array = $this->toArray();
5469 1
        $direction = $this->getDirection($direction);
5470
5471
        // Transform all values into their results.
5472 1
        if ($sorter) {
5473 1
            $arrayy = static::create(
5474 1
                $array,
5475 1
                $this->iteratorClass,
5476 1
                false
5477
            );
5478
5479
            /**
5480
             * @psalm-suppress MissingClosureReturnType
5481
             * @psalm-suppress MissingClosureParamType
5482
             */
5483 1
            $results = $arrayy->each(
5484 1
                function ($value) use ($sorter) {
5485 1
                    if (\is_callable($sorter) === true) {
5486 1
                        return $sorter($value);
5487
                    }
5488
5489 1
                    return $this->get($sorter);
5490 1
                }
5491
            );
5492
5493 1
            $results = $results->toArray();
5494
        } else {
5495 1
            $results = $array;
5496
        }
5497
5498
        // Sort by the results and replace by original values
5499 1
        \array_multisort($results, $direction, $strategy, $array);
5500
5501 1
        return static::create(
5502 1
            $array,
5503 1
            $this->iteratorClass,
5504 1
            false
5505
        );
5506
    }
5507
5508
    /**
5509
     * @param int      $offset
5510
     * @param int|null $length
5511
     * @param array    $replacement
5512
     *
5513
     * @return static
5514
     *                <p>(Immutable)</p>
5515
     *
5516
     * @psalm-param  array<mixed,mixed>|array<mixed,T> $replacement
5517
     * @psalm-return static<TKey,T>
5518
     * @psalm-mutation-free
5519
     */
5520 1
    public function splice(int $offset, int $length = null, $replacement = []): self
5521
    {
5522 1
        $tmpArray = $this->toArray();
5523
5524 1
        \array_splice(
5525 1
            $tmpArray,
5526 1
            $offset,
5527 1
            $length ?? $this->count(),
5528 1
            $replacement
5529
        );
5530
5531 1
        return static::create(
5532 1
            $tmpArray,
5533 1
            $this->iteratorClass,
5534 1
            false
5535
        );
5536
    }
5537
5538
    /**
5539
     * Split an array in the given amount of pieces.
5540
     *
5541
     * @param int  $numberOfPieces
5542
     * @param bool $keepKeys
5543
     *
5544
     * @return static
5545
     *                <p>(Immutable)</p>
5546
     *
5547
     * @psalm-return static<TKey,T>
5548
     * @psalm-mutation-free
5549
     */
5550 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
5551
    {
5552 1
        $this->generatorToArray();
5553
5554 1
        $count = $this->count();
5555
5556 1
        if ($count === 0) {
5557 1
            $result = [];
5558
        } else {
5559 1
            $splitSize = (int) \ceil($count / $numberOfPieces);
5560 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
5561
        }
5562
5563 1
        return static::create(
5564 1
            $result,
5565 1
            $this->iteratorClass,
5566 1
            false
5567
        );
5568
    }
5569
5570
    /**
5571
     * Stripe all empty items.
5572
     *
5573
     * @return static
5574
     *                <p>(Immutable)</p>
5575
     *
5576
     * @psalm-return static<TKey,T>
5577
     * @psalm-mutation-free
5578
     */
5579 1
    public function stripEmpty(): self
5580
    {
5581 1
        return $this->filter(
5582 1
            static function ($item) {
5583 1
                if ($item === null) {
5584 1
                    return false;
5585
                }
5586
5587 1
                return (bool) \trim((string) $item);
5588 1
            }
5589
        );
5590
    }
5591
5592
    /**
5593
     * Swap two values between positions by key.
5594
     *
5595
     * @param int|string $swapA <p>a key in the array</p>
5596
     * @param int|string $swapB <p>a key in the array</p>
5597
     *
5598
     * @return static
5599
     *                <p>(Immutable)</p>
5600
     *
5601
     * @psalm-return static<TKey,T>
5602
     * @psalm-mutation-free
5603
     */
5604 1
    public function swap($swapA, $swapB): self
5605
    {
5606 1
        $array = $this->toArray();
5607
5608 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
5609
5610 1
        return static::create(
5611 1
            $array,
5612 1
            $this->iteratorClass,
5613 1
            false
5614
        );
5615
    }
5616
5617
    /**
5618
     * Get the current array from the "Arrayy"-object.
5619
     * alias for "getArray()"
5620
     *
5621
     * @param bool $convertAllArrayyElements <p>
5622
     *                                       Convert all Child-"Arrayy" objects also to arrays.
5623
     *                                       </p>
5624
     * @param bool $preserveKeys             <p>
5625
     *                                       e.g.: A generator maybe return the same key more then once,
5626
     *                                       so maybe you will ignore the keys.
5627
     *                                       </p>
5628
     *
5629
     * @return array
5630
     *
5631
     * @psalm-return array<mixed,mixed>|array<TKey,T>
5632
     * @psalm-mutation-free
5633
     */
5634 937
    public function toArray(
5635
        bool $convertAllArrayyElements = false,
5636
        bool $preserveKeys = true
5637
    ): array {
5638
        // init
5639 937
        $array = [];
5640
5641 937
        if ($convertAllArrayyElements) {
5642 2
            foreach ($this->getGenerator() as $key => $value) {
5643 2
                if ($value instanceof self) {
5644 1
                    $value = $value->toArray(true);
5645
                }
5646
5647 2
                if ($preserveKeys) {
5648 1
                    $array[$key] = $value;
5649
                } else {
5650 2
                    $array[] = $value;
5651
                }
5652
            }
5653
        } else {
5654 937
            $array = \iterator_to_array($this->getGenerator(), $preserveKeys);
5655
        }
5656
5657 937
        return $array;
5658
    }
5659
5660
    /**
5661
     * Get the current array from the "Arrayy"-object as list.
5662
     *
5663
     * @param bool $convertAllArrayyElements <p>
5664
     *                                       Convert all Child-"Arrayy" objects also to arrays.
5665
     *                                       </p>
5666
     *
5667
     * @return array
5668
     *
5669
     * @psalm-return list<array<TKey,T>>
5670
     * @psalm-mutation-free
5671
     */
5672 1
    public function toList(bool $convertAllArrayyElements = false): array
5673
    {
5674 1
        return $this->toArray(
5675 1
            $convertAllArrayyElements,
5676 1
            false
5677
        );
5678
    }
5679
5680
    /**
5681
     * Convert the current array to JSON.
5682
     *
5683
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
5684
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
5685
     *
5686
     * @return string
5687
     */
5688 11
    public function toJson(int $options = 0, int $depth = 512): string
5689
    {
5690 11
        $return = \json_encode($this->toArray(), $options, $depth);
5691 11
        if ($return === false) {
5692
            return '';
5693
        }
5694
5695 11
        return $return;
5696
    }
5697
5698
    /**
5699
     * @param string[]|null $items  [optional]
5700
     * @param string[]      $helper [optional]
5701
     *
5702
     * @return static|static[]
5703
     *
5704
     * @psalm-return static<int, static<TKey,T>>
5705
     */
5706 1
    public function toPermutation(array $items = null, array $helper = []): self
5707
    {
5708
        // init
5709 1
        $return = [];
5710
5711 1
        if ($items === null) {
5712 1
            $items = $this->toArray();
5713
        }
5714
5715 1
        if (empty($items)) {
5716 1
            $return[] = $helper;
5717
        } else {
5718 1
            for ($i = \count($items) - 1; $i >= 0; --$i) {
5719 1
                $new_items = $items;
5720 1
                $new_helper = $helper;
5721 1
                list($tmp_helper) = \array_splice($new_items, $i, 1);
5722
                /** @noinspection PhpSillyAssignmentInspection */
5723
                /** @var string[] $new_items */
5724 1
                $new_items = $new_items;
0 ignored issues
show
Bug introduced by
Why assign $new_items to itself?

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

This assignement can be removed without consequences.

Loading history...
5725 1
                \array_unshift($new_helper, $tmp_helper);
5726
                /** @noinspection SlowArrayOperationsInLoopInspection */
5727 1
                $return = \array_merge(
5728 1
                    $return,
5729 1
                    $this->toPermutation($new_items, $new_helper)->toArray()
5730
                );
5731
            }
5732
        }
5733
5734 1
        return static::create(
5735 1
            $return,
5736 1
            $this->iteratorClass,
5737 1
            false
5738
        );
5739
    }
5740
5741
    /**
5742
     * Implodes array to a string with specified separator.
5743
     *
5744
     * @param string $separator [optional] <p>The element's separator.</p>
5745
     *
5746
     * @return string
5747
     *                <p>The string representation of array, separated by ",".</p>
5748
     */
5749 19
    public function toString(string $separator = ','): string
5750
    {
5751 19
        return $this->implode($separator);
5752
    }
5753
5754
    /**
5755
     * Return a duplicate free copy of the current array.
5756
     *
5757
     * @return $this
5758
     *               <p>(Mutable)</p>
5759
     *
5760
     * @psalm-return static<TKey,T>
5761
     */
5762 13
    public function unique(): self
5763
    {
5764
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
5765
5766
        /**
5767
         * @psalm-suppress MissingClosureReturnType
5768
         * @psalm-suppress MissingClosureParamType
5769
         */
5770 13
        $this->array = $this->reduce(
5771 13
            static function ($resultArray, $value) {
5772 12
                if (!\in_array($value, $resultArray, true)) {
5773 12
                    $resultArray[] = $value;
5774
                }
5775
5776 12
                return $resultArray;
5777 13
            },
5778 13
            []
5779 13
        )->toArray();
5780 13
        $this->generator = null;
5781
5782 13
        return $this;
5783
    }
5784
5785
    /**
5786
     * Return a duplicate free copy of the current array. (with the old keys)
5787
     *
5788
     * @return $this
5789
     *               <p>(Mutable)</p>
5790
     *
5791
     * @psalm-return static<TKey,T>
5792
     */
5793 11
    public function uniqueKeepIndex(): self
5794
    {
5795
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
5796
5797
        // init
5798 11
        $array = $this->toArray();
5799
5800
        /**
5801
         * @psalm-suppress MissingClosureReturnType
5802
         * @psalm-suppress MissingClosureParamType
5803
         */
5804 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...
5805 11
            \array_keys($array),
5806 11
            static function ($resultArray, $key) use ($array) {
5807 10
                if (!\in_array($array[$key], $resultArray, true)) {
5808 10
                    $resultArray[$key] = $array[$key];
5809
                }
5810
5811 10
                return $resultArray;
5812 11
            },
5813 11
            []
5814
        );
5815 11
        $this->generator = null;
5816
5817 11
        return $this;
5818
    }
5819
5820
    /**
5821
     * alias: for "Arrayy->unique()"
5822
     *
5823
     * @return static
5824
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
5825
     *
5826
     * @see          Arrayy::unique()
5827
     *
5828
     * @psalm-return static<TKey,T>
5829
     */
5830 10
    public function uniqueNewIndex(): self
5831
    {
5832 10
        return $this->unique();
5833
    }
5834
5835
    /**
5836
     * Prepends one or more values to the beginning of array at once.
5837
     *
5838
     * @param array ...$args
5839
     *
5840
     * @return $this
5841
     *               <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
5842
     *
5843
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$args
5844
     * @psalm-return static<TKey,T>
5845
     */
5846 4
    public function unshift(...$args): self
5847
    {
5848 4
        $this->generatorToArray();
5849
5850 4
        \array_unshift($this->array, ...$args);
5851
5852 4
        return $this;
5853
    }
5854
5855
    /**
5856
     * Tests whether the given closure return something valid for all elements of this array.
5857
     *
5858
     * @param \Closure $closure the predicate
5859
     *
5860
     * @return bool
5861
     *              <p>TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.</p>
5862
     */
5863 1 View Code Duplication
    public function validate(\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...
5864
    {
5865 1
        foreach ($this->getGenerator() as $key => $value) {
5866 1
            if (!$closure($value, $key)) {
5867 1
                return false;
5868
            }
5869
        }
5870
5871 1
        return true;
5872
    }
5873
5874
    /**
5875
     * Get all values from a array.
5876
     *
5877
     * @return static
5878
     *                <p>(Immutable)</p>
5879
     *
5880
     * @psalm-return static<TKey,T>
5881
     * @psalm-mutation-free
5882
     */
5883 2
    public function values(): self
5884
    {
5885 2
        return static::create(
5886 2
            function () {
5887
                /** @noinspection YieldFromCanBeUsedInspection */
5888 2
                foreach ($this->getGenerator() as $value) {
5889 2
                    yield $value;
5890
                }
5891 2
            },
5892 2
            $this->iteratorClass,
5893 2
            false
5894
        );
5895
    }
5896
5897
    /**
5898
     * Apply the given function to every element in the array, discarding the results.
5899
     *
5900
     * @param callable $callable
5901
     * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
5902
     *
5903
     * @return $this
5904
     *               <p>(Mutable) Return this Arrayy object, with modified elements.</p>
5905
     *
5906
     * @psalm-return static<TKey,T>
5907
     */
5908 12
    public function walk($callable, bool $recursive = false): self
5909
    {
5910 12
        $this->generatorToArray();
5911
5912 12
        if ($this->array !== []) {
5913 10
            if ($recursive === true) {
5914 5
                \array_walk_recursive($this->array, $callable);
5915
            } else {
5916 5
                \array_walk($this->array, $callable);
5917
            }
5918
        }
5919
5920 12
        return $this;
5921
    }
5922
5923
    /**
5924
     * Returns a collection of matching items.
5925
     *
5926
     * @param string $keyOrPropertyOrMethod the property or method to evaluate
5927
     * @param mixed  $value                 the value to match
5928
     *
5929
     * @throws \InvalidArgumentException if property or method is not defined
5930
     *
5931
     * @return static
5932
     *
5933
     * @psalm-param  T $value
5934
     * @psalm-return static<TKey,T>
5935
     */
5936 1
    public function where(string $keyOrPropertyOrMethod, $value): self
5937
    {
5938 1
        return $this->filter(
5939 1
            function ($item) use ($keyOrPropertyOrMethod, $value) {
5940 1
                $accessorValue = $this->extractValue(
5941 1
                    $item,
5942 1
                    $keyOrPropertyOrMethod
5943
                );
5944
5945 1
                return $accessorValue === $value;
5946 1
            }
5947
        );
5948
    }
5949
5950
    /**
5951
     * Convert an array into a object.
5952
     *
5953
     * @param array $array
5954
     *
5955
     * @return \stdClass
5956
     *
5957
     * @psalm-param array<mixed,mixed> $array
5958
     */
5959 4
    final protected static function arrayToObject(array $array = []): \stdClass
5960
    {
5961
        // init
5962 4
        $object = new \stdClass();
5963
5964 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
5965 1
            return $object;
5966
        }
5967
5968 3
        foreach ($array as $name => $value) {
5969 3
            if (\is_array($value) === true) {
5970 1
                $object->{$name} = static::arrayToObject($value);
5971
            } else {
5972 3
                $object->{$name} = $value;
5973
            }
5974
        }
5975
5976 3
        return $object;
5977
    }
5978
5979
    /**
5980
     * @param array|\Generator|null $input         <p>
5981
     *                                             An array containing keys to return.
5982
     *                                             </p>
5983
     * @param mixed|null            $search_values [optional] <p>
5984
     *                                             If specified, then only keys containing these values are returned.
5985
     *                                             </p>
5986
     * @param bool                  $strict        [optional] <p>
5987
     *                                             Determines if strict comparison (===) should be used during the
5988
     *                                             search.
5989
     *                                             </p>
5990
     *
5991
     * @return array
5992
     *               <p>an array of all the keys in input</p>
5993
     *
5994
     * @psalm-param  array<mixed,mixed>|\Generator<TKey,T>|null $input
5995
     * @psalm-return array<TKey|mixed>
5996
     * @psalm-mutation-free
5997
     */
5998 11
    protected function array_keys_recursive(
5999
        $input = null,
6000
        $search_values = null,
6001
        bool $strict = true
6002
    ): array {
6003
        // init
6004 11
        $keys = [];
6005 11
        $keysTmp = [];
6006
6007 11
        if ($input === null) {
6008 4
            $input = $this->getGenerator();
6009
        }
6010
6011 11
        if ($search_values === null) {
6012 11
            foreach ($input as $key => $value) {
6013 11
                $keys[] = $key;
6014
6015
                // check if recursive is needed
6016 11
                if (\is_array($value) === true) {
6017 11
                    $keysTmp[] = $this->array_keys_recursive($value);
6018
                }
6019
            }
6020
        } else {
6021 1
            $is_array_tmp = \is_array($search_values);
6022
6023 1
            foreach ($input as $key => $value) {
6024 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...
6025
                    (
6026 1
                        $is_array_tmp === false
6027
                        &&
6028 1
                        $strict === true
6029
                        &&
6030 1
                        $search_values === $value
6031
                    )
6032
                    ||
6033
                    (
6034 1
                        $is_array_tmp === false
6035
                        &&
6036 1
                        $strict === false
6037
                        &&
6038 1
                        $search_values == $value
6039
                    )
6040
                    ||
6041
                    (
6042 1
                        $is_array_tmp === true
6043
                        &&
6044 1
                        \in_array($value, $search_values, $strict)
6045
                    )
6046
                ) {
6047 1
                    $keys[] = $key;
6048
                }
6049
6050
                // check if recursive is needed
6051 1
                if (\is_array($value) === true) {
6052 1
                    $keysTmp[] = $this->array_keys_recursive($value);
6053
                }
6054
            }
6055
        }
6056
6057 11
        return $keysTmp === [] ? $keys : \array_merge($keys, ...$keysTmp);
6058
    }
6059
6060
    /**
6061
     * @param mixed      $path
6062
     * @param callable   $callable
6063
     * @param array|null $currentOffset
6064
     *
6065
     * @return void
6066
     *
6067
     * @psalm-param array<mixed,mixed>|array<TKey,T>|null $currentOffset
6068
     * @psalm-mutation-free
6069
     */
6070 11
    protected function callAtPath($path, $callable, &$currentOffset = null)
6071
    {
6072 11
        $this->generatorToArray();
6073
6074 11
        if ($currentOffset === null) {
6075 11
            $currentOffset = &$this->array;
6076
        }
6077
6078 11
        $explodedPath = \explode($this->pathSeparator, $path);
6079 11
        if ($explodedPath === false) {
6080
            return;
6081
        }
6082
6083 11
        $nextPath = \array_shift($explodedPath);
6084
6085 11
        if (!isset($currentOffset[$nextPath])) {
6086 1
            return;
6087
        }
6088
6089 10
        if (!empty($explodedPath)) {
6090 1
            $this->callAtPath(
6091 1
                \implode($this->pathSeparator, $explodedPath),
6092 1
                $callable,
6093 1
                $currentOffset[$nextPath]
6094
            );
6095
        } else {
6096 10
            $callable($currentOffset[$nextPath]);
6097
        }
6098 10
    }
6099
6100
    /**
6101
     * Extracts the value of the given property or method from the object.
6102
     *
6103
     * @param static $object                <p>The object to extract the value from.</p>
6104
     * @param string $keyOrPropertyOrMethod <p>The property or method for which the
6105
     *                                      value should be extracted.</p>
6106
     *
6107
     * @throws \InvalidArgumentException if the method or property is not defined
6108
     *
6109
     * @return mixed
6110
     *               <p>The value extracted from the specified property or method.</p>
6111
     *
6112
     * @psalm-param self<TKey,T> $object
6113
     */
6114 2
    final protected function extractValue(self $object, string $keyOrPropertyOrMethod)
6115
    {
6116 2
        if (isset($object[$keyOrPropertyOrMethod])) {
6117 2
            $return = $object->get($keyOrPropertyOrMethod);
6118
6119 2
            if ($return instanceof self) {
6120 1
                return $return->toArray();
6121
            }
6122
6123 1
            return $return;
6124
        }
6125
6126
        if (\property_exists($object, $keyOrPropertyOrMethod)) {
6127
            return $object->{$keyOrPropertyOrMethod};
6128
        }
6129
6130
        if (\method_exists($object, $keyOrPropertyOrMethod)) {
6131
            return $object->{$keyOrPropertyOrMethod}();
6132
        }
6133
6134
        throw new \InvalidArgumentException(\sprintf('array-key & property & method "%s" not defined in %s', $keyOrPropertyOrMethod, \gettype($object)));
6135
    }
6136
6137
    /**
6138
     * create a fallback for array
6139
     *
6140
     * 1. use the current array, if it's a array
6141
     * 2. fallback to empty array, if there is nothing
6142
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
6143
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
6144
     * 5. call "__toArray()" on object, if the method exists
6145
     * 6. cast a string or object with "__toString()" into an array
6146
     * 7. throw a "InvalidArgumentException"-Exception
6147
     *
6148
     * @param mixed $data
6149
     *
6150
     * @throws \InvalidArgumentException
6151
     *
6152
     * @return array
6153
     *
6154
     * @psalm-return array<mixed,mixed>|array<TKey,T>
6155
     */
6156 1185
    protected function fallbackForArray(&$data): array
6157
    {
6158 1185
        $data = $this->internalGetArray($data);
6159
6160 1185
        if ($data === null) {
6161 2
            throw new \InvalidArgumentException('Passed value should be a array');
6162
        }
6163
6164 1183
        return $data;
6165
    }
6166
6167
    /**
6168
     * @param bool $preserveKeys <p>
6169
     *                           e.g.: A generator maybe return the same key more then once,
6170
     *                           so maybe you will ignore the keys.
6171
     *                           </p>
6172
     *
6173
     * @return bool
6174
     *
6175
     * @noinspection ReturnTypeCanBeDeclaredInspection
6176
     * @psalm-mutation-free :/
6177
     */
6178 1097
    protected function generatorToArray(bool $preserveKeys = true)
6179
    {
6180 1097
        if ($this->generator) {
6181 2
            $this->array = $this->toArray(false, $preserveKeys);
6182 2
            $this->generator = null;
6183
6184 2
            return true;
6185
        }
6186
6187 1097
        return false;
6188
    }
6189
6190
    /**
6191
     * Get correct PHP constant for direction.
6192
     *
6193
     * @param int|string $direction
6194
     *
6195
     * @return int
6196
     * @psalm-mutation-free
6197
     */
6198 43
    protected function getDirection($direction): int
6199
    {
6200 43
        if ((string) $direction === $direction) {
6201 10
            $direction = \strtolower($direction);
6202
6203 10
            if ($direction === 'desc') {
6204 2
                $direction = \SORT_DESC;
6205
            } else {
6206 8
                $direction = \SORT_ASC;
6207
            }
6208
        }
6209
6210
        if (
6211 43
            $direction !== \SORT_DESC
6212
            &&
6213 43
            $direction !== \SORT_ASC
6214
        ) {
6215
            $direction = \SORT_ASC;
6216
        }
6217
6218 43
        return $direction;
6219
    }
6220
6221
    /**
6222
     * @return TypeCheckInterface[]
6223
     *
6224
     * @noinspection ReturnTypeCanBeDeclaredInspection
6225
     */
6226 16
    protected function getPropertiesFromPhpDoc()
6227
    {
6228 16
        static $PROPERTY_CACHE = [];
6229 16
        $cacheKey = 'Class::' . static::class;
6230
6231 16
        if (isset($PROPERTY_CACHE[$cacheKey])) {
6232 15
            return $PROPERTY_CACHE[$cacheKey];
6233
        }
6234
6235
        // init
6236 2
        $properties = [];
6237
6238 2
        $reflector = new \ReflectionClass($this);
6239 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
6240 2
        $docComment = $reflector->getDocComment();
6241 2
        if ($docComment) {
6242 2
            $docblock = $factory->create($docComment);
6243
            /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
6244 2
            foreach ($docblock->getTagsByName('property') as $tag) {
6245 2
                $typeName = $tag->getVariableName();
6246 2
                if ($typeName !== null) {
6247 2
                    $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName);
6248 2
                    if ($typeCheckPhpDoc !== null) {
6249 2
                        $properties[$typeName] = $typeCheckPhpDoc;
6250
                    }
6251
                }
6252
            }
6253
        }
6254
6255 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
6256
    }
6257
6258
    /**
6259
     * @param mixed $glue
6260
     * @param mixed $pieces
6261
     * @param bool  $useKeys
6262
     *
6263
     * @return string
6264
     * @psalm-mutation-free
6265
     */
6266 36
    protected function implode_recursive(
6267
        $glue = '',
6268
        $pieces = [],
6269
        bool $useKeys = false
6270
    ): string {
6271 36
        if ($pieces instanceof self) {
6272 1
            $pieces = $pieces->toArray();
6273
        }
6274
6275 36
        if (\is_array($pieces) === true) {
6276 36
            $pieces_count = \count($pieces, \COUNT_NORMAL);
6277 36
            $pieces_count_not_zero = $pieces_count > 0;
6278
6279 36
            return \implode(
6280 36
                $glue,
6281 36
                \array_map(
6282 36
                    [$this, 'implode_recursive'],
6283 36
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
6284 36
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
6285
                )
6286
            );
6287
        }
6288
6289
        if (
6290 36
            \is_scalar($pieces) === true
6291
            ||
6292 36
            (\is_object($pieces) && \method_exists($pieces, '__toString'))
6293
        ) {
6294 32
            return (string) $pieces;
6295
        }
6296
6297 8
        return '';
6298
    }
6299
6300
    /**
6301
     * @param mixed                 $needle   <p>
6302
     *                                        The searched value.
6303
     *                                        </p>
6304
     *                                        <p>
6305
     *                                        If needle is a string, the comparison is done
6306
     *                                        in a case-sensitive manner.
6307
     *                                        </p>
6308
     * @param array|\Generator|null $haystack <p>
6309
     *                                        The array.
6310
     *                                        </p>
6311
     * @param bool                  $strict   [optional] <p>
6312
     *                                        If the third parameter strict is set to true
6313
     *                                        then the in_array function will also check the
6314
     *                                        types of the
6315
     *                                        needle in the haystack.
6316
     *                                        </p>
6317
     *
6318
     * @return bool
6319
     *              <p>true if needle is found in the array, false otherwise</p>
6320
     *
6321
     * @psalm-param array<mixed,mixed>|\Generator<TKey,T>|null $haystack
6322
     * @psalm-mutation-free
6323
     */
6324 18
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
6325
    {
6326 18
        if ($haystack === null) {
6327
            $haystack = $this->getGenerator();
6328
        }
6329
6330 18
        foreach ($haystack as $item) {
6331 14
            if (\is_array($item) === true) {
6332 3
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
6333
            } else {
6334
                /** @noinspection NestedPositiveIfStatementsInspection */
6335 14
                if ($strict === true) {
6336 14
                    $returnTmp = $item === $needle;
6337
                } else {
6338
                    $returnTmp = $item == $needle;
6339
                }
6340
            }
6341
6342 14
            if ($returnTmp === true) {
6343 14
                return true;
6344
            }
6345
        }
6346
6347 8
        return false;
6348
    }
6349
6350
    /**
6351
     * @param mixed $data
6352
     *
6353
     * @return array|null
6354
     *
6355
     * @psalm-return array<mixed,mixed>|array<TKey,T>|null
6356
     */
6357 1185
    protected function internalGetArray(&$data)
6358
    {
6359 1185
        if (\is_array($data) === true) {
6360 1179
            return $data;
6361
        }
6362
6363 56
        if (!$data) {
6364 6
            return [];
6365
        }
6366
6367 55
        if (\is_object($data) === true) {
6368 49
            if ($data instanceof \ArrayObject) {
6369 5
                return $data->getArrayCopy();
6370
            }
6371
6372 45
            if ($data instanceof \Generator) {
6373
                return static::createFromGeneratorImmutable($data)->toArray();
6374
            }
6375
6376 45
            if ($data instanceof \Traversable) {
6377
                return static::createFromObject($data)->toArray();
6378
            }
6379
6380 45
            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...
6381
                return (array) $data->jsonSerialize();
6382
            }
6383
6384 45
            if (\method_exists($data, '__toArray')) {
6385
                return (array) $data->__toArray();
6386
            }
6387
6388 45
            if (\method_exists($data, '__toString')) {
6389
                return [(string) $data];
6390
            }
6391
        }
6392
6393 51
        if (\is_callable($data)) {
6394
            /**
6395
             * @psalm-suppress InvalidPropertyAssignmentValue - why?
6396
             */
6397 43
            $this->generator = new ArrayyRewindableGenerator($data);
6398
6399 43
            return [];
6400
        }
6401
6402 10
        if (\is_scalar($data)) {
6403 8
            return [$data];
6404
        }
6405
6406 2
        return null;
6407
    }
6408
6409
    /**
6410
     * Internal mechanics of remove method.
6411
     *
6412
     * @param mixed $key
6413
     *
6414
     * @return bool
6415
     */
6416 21
    protected function internalRemove($key): bool
6417
    {
6418 21
        $this->generatorToArray();
6419
6420
        if (
6421 21
            $this->pathSeparator
6422
            &&
6423 21
            (string) $key === $key
6424
            &&
6425 21
            \strpos($key, $this->pathSeparator) !== false
6426
        ) {
6427
            $path = \explode($this->pathSeparator, (string) $key);
6428
6429
            if ($path !== false) {
6430
                // crawl though the keys
6431
                while (\count($path, \COUNT_NORMAL) > 1) {
6432
                    $key = \array_shift($path);
6433
6434
                    if (!$this->has($key)) {
6435
                        return false;
6436
                    }
6437
6438
                    $this->array = &$this->array[$key];
6439
                }
6440
6441
                $key = \array_shift($path);
6442
            }
6443
        }
6444
6445 21
        unset($this->array[$key]);
6446
6447 21
        return true;
6448
    }
6449
6450
    /**
6451
     * Internal mechanic of set method.
6452
     *
6453
     * @param int|string|null $key
6454
     * @param mixed           $value
6455
     * @param bool            $checkProperties
6456
     *
6457
     * @return bool
6458
     */
6459 1036
    protected function internalSet(
6460
        $key,
6461
        &$value,
6462
        bool $checkProperties = true
6463
    ): bool {
6464
        if (
6465 1036
            $checkProperties === true
6466
            &&
6467 1036
            $this->properties !== []
6468
        ) {
6469 99
            $this->checkType($key, $value);
6470
        }
6471
6472 1034
        if ($key === null) {
6473
            return false;
6474
        }
6475
6476 1034
        $this->generatorToArray();
6477
6478
        /** @var array<int|string,mixed> $array */
6479 1034
        $array = &$this->array;
6480
6481
        /**
6482
         * https://github.com/vimeo/psalm/issues/2536
6483
         *
6484
         * @psalm-suppress PossiblyInvalidArgument
6485
         * @psalm-suppress InvalidScalarArgument
6486
         */
6487
        if (
6488 1034
            $this->pathSeparator
6489
            &&
6490 1034
            (string) $key === $key
6491
            &&
6492 1034
            \strpos($key, $this->pathSeparator) !== false
6493
        ) {
6494 9
            $path = \explode($this->pathSeparator, (string) $key);
6495
6496 9
            if ($path !== false) {
6497
                // crawl through the keys
6498 9
                while (\count($path, \COUNT_NORMAL) > 1) {
6499 9
                    $key = \array_shift($path);
6500
6501 9
                    $array = &$array[$key];
6502
                }
6503
6504 9
                $key = \array_shift($path);
6505
            }
6506
        }
6507
6508 1034
        if ($array === null) {
6509 4
            $array = [];
6510 1031
        } elseif (!\is_array($array)) {
6511 1
            throw new \RuntimeException('Can not set value at this path "' . $key . '" because (' . \gettype($array) . ')"' . \print_r($array, true) . '" is not an array.');
6512
        }
6513
6514 1034
        $array[$key] = $value;
6515
6516 1034
        return true;
6517
    }
6518
6519
    /**
6520
     * Convert a object into an array.
6521
     *
6522
     * @param mixed|object $object
6523
     *
6524
     * @return array|mixed
6525
     *
6526
     * @psalm-mutation-free
6527
     */
6528 5
    protected static function objectToArray($object)
6529
    {
6530 5
        if (!\is_object($object)) {
6531 4
            return $object;
6532
        }
6533
6534 5
        $object = \get_object_vars($object);
6535
6536
        /**
6537
         * @psalm-suppress PossiblyInvalidArgument - the parameter is always some kind of array - false-positive from psalm?
6538
         */
6539 5
        return \array_map(['static', 'objectToArray'], $object);
6540
    }
6541
6542
    /**
6543
     * @param array $data
6544
     * @param bool  $checkPropertiesInConstructor
6545
     *
6546
     * @return void
6547
     *
6548
     * @psalm-param array<mixed,T> $data
6549
     */
6550 1183
    protected function setInitialValuesAndProperties(array &$data, bool $checkPropertiesInConstructor)
6551
    {
6552 1183
        $checkPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
6553
                                        &&
6554 1183
                                        $checkPropertiesInConstructor === true;
6555
6556 1183
        if ($this->properties !== []) {
6557 90
            foreach ($data as $key => &$valueInner) {
6558 90
                $this->internalSet(
6559 90
                    $key,
6560 90
                    $valueInner,
6561 90
                    $checkPropertiesInConstructor
6562
                );
6563
            }
6564
        } else {
6565
            if (
6566 1108
                $this->checkPropertyTypes === true
6567
                ||
6568 1108
                $checkPropertiesInConstructor === true
6569
            ) {
6570 16
                $this->properties = $this->getPropertiesFromPhpDoc();
6571
            }
6572
6573
            /** @var TypeCheckInterface[] $properties */
6574 1108
            $properties = $this->properties;
6575
6576
            if (
6577 1108
                $this->checkPropertiesMismatchInConstructor === true
6578
                &&
6579 1108
                \count($data) !== 0
6580
                &&
6581 1108
                \count(\array_diff_key($properties, $data)) > 0
6582
            ) {
6583 1
                throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($properties), true));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'Property mismatch - inp...eys($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...
6584
            }
6585
6586 1107
            foreach ($data as $key => &$valueInner) {
6587 944
                $this->internalSet(
6588 944
                    $key,
6589 944
                    $valueInner,
6590 944
                    $checkPropertiesInConstructor
6591
                );
6592
            }
6593
        }
6594 1176
    }
6595
6596
    /**
6597
     * sorting keys
6598
     *
6599
     * @param array      $elements
6600
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6601
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
6602
     *                              <strong>SORT_NATURAL</strong></p>
6603
     *
6604
     * @return $this
6605
     *               <p>(Mutable) Return this Arrayy object.</p>
6606
     *
6607
     * @psalm-param  array<mixed,mixed>|array<mixed|TKey,T> $elements
6608
     * @psalm-return static<TKey,T>
6609
     */
6610 18
    protected function sorterKeys(
6611
        array &$elements,
6612
        $direction = \SORT_ASC,
6613
        int $strategy = \SORT_REGULAR
6614
    ): self {
6615 18
        $direction = $this->getDirection($direction);
6616
6617
        switch ($direction) {
6618 18
            case 'desc':
6619 18
            case \SORT_DESC:
6620 6
                \krsort($elements, $strategy);
6621
6622 6
                break;
6623 13
            case 'asc':
6624 13
            case \SORT_ASC:
6625
            default:
6626 13
                \ksort($elements, $strategy);
6627
        }
6628
6629 18
        return $this;
6630
    }
6631
6632
    /**
6633
     * @param array      $elements  <p>Warning: used as reference</p>
6634
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6635
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
6636
     *                              <strong>SORT_NATURAL</strong></p>
6637
     * @param bool       $keepKeys
6638
     *
6639
     * @return $this
6640
     *               <p>(Mutable) Return this Arrayy object.</p>
6641
     *
6642
     * @psalm-param  array<mixed,mixed>|array<mixed|TKey,T> $elements
6643
     * @psalm-return static<TKey,T>
6644
     */
6645 24
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
6646
    {
6647 24
        $direction = $this->getDirection($direction);
6648
6649 24
        if (!$strategy) {
6650 24
            $strategy = \SORT_REGULAR;
6651
        }
6652
6653
        switch ($direction) {
6654 24
            case 'desc':
6655 24
            case \SORT_DESC:
6656 13
                if ($keepKeys) {
6657 9
                    \arsort($elements, $strategy);
6658
                } else {
6659 4
                    \rsort($elements, $strategy);
6660
                }
6661
6662 13
                break;
6663 11
            case 'asc':
6664 11
            case \SORT_ASC:
6665
            default:
6666 11
                if ($keepKeys) {
6667 4
                    \asort($elements, $strategy);
6668
                } else {
6669 7
                    \sort($elements, $strategy);
6670
                }
6671
        }
6672
6673 24
        return $this;
6674
    }
6675
6676
    /**
6677
     * @param array $array
6678
     *
6679
     * @return array
6680
     *
6681
     * @psalm-mutation-free
6682
     */
6683 25
    private function getArrayRecursiveHelperArrayy(array $array)
6684
    {
6685 25
        if ($array === []) {
6686
            return [];
6687
        }
6688
6689 25
        \array_walk_recursive(
6690 25
            $array,
6691
            /**
6692
             * @param array|self $item
6693
             *
6694
             * @return void
6695
             */
6696 25
            static function (&$item) {
6697 25
                if ($item instanceof self) {
6698 1
                    $item = $item->getArray();
6699
                }
6700 25
            }
6701
        );
6702
6703 25
        return $array;
6704
    }
6705
6706
    /**
6707
     * @param int|string|null $key
6708
     * @param mixed           $value
6709
     *
6710
     * @return void
6711
     */
6712 99
    private function checkType($key, $value)
6713
    {
6714
        if (
6715 99
            $key !== null
6716
            &&
6717 99
            isset($this->properties[$key]) === false
6718
            &&
6719 99
            $this->checkPropertiesMismatch === true
6720
        ) {
6721
            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...
6722
        }
6723
6724 99
        if (isset($this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES])) {
6725 88
            $this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES]->checkType($value);
6726 17
        } elseif ($key !== null && isset($this->properties[$key])) {
6727 17
            $this->properties[$key]->checkType($value);
6728
        }
6729 97
    }
6730
}
6731