Completed
Push — master ( cde795...159245 )
by Lars
05:44
created

Arrayy::__isset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/** @noinspection ReturnTypeCanBeDeclaredInspection */
4
/** @noinspection ClassReImplementsParentInterfaceInspection */
5
6
declare(strict_types=1);
7
8
namespace Arrayy;
9
10
use Arrayy\TypeCheck\TypeCheckArray;
11
use Arrayy\TypeCheck\TypeCheckInterface;
12
use Arrayy\TypeCheck\TypeCheckPhpDoc;
13
14
/**
15
 * Methods to manage arrays.
16
 *
17
 * For the full copyright and license information, please view the LICENSE
18
 * file that was distributed with this source code.
19
 *
20
 * @template TKey of array-key
21
 * @template T
22
 * @template-extends \ArrayObject<TKey,T>
23
 * @template-implements \IteratorAggregate<TKey,T>
24
 * @template-implements \ArrayAccess<TKey|null,T>
25
 */
26
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \JsonSerializable, \Countable
27
{
28
    const ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES = '!!!!Arrayy_Helper_Types_For_All_Properties!!!!';
29
30
    /**
31
     * @var array
32
     *
33
     * @psalm-var array<TKey,T>
34
     */
35
    protected $array = [];
36
37
    /**
38
     * @var \Arrayy\ArrayyRewindableGenerator|null
39
     *
40
     * @psalm-var \Arrayy\ArrayyRewindableGenerator<TKey,T>|null
41
     */
42
    protected $generator;
43
44
    /**
45
     * @var string
46
     *
47
     * @psalm-var class-string<\Arrayy\ArrayyIterator>
48
     */
49
    protected $iteratorClass = ArrayyIterator::class;
50
51
    /**
52
     * @var string
53
     */
54
    protected $pathSeparator = '.';
55
56
    /**
57
     * @var bool
58
     */
59
    protected $checkPropertyTypes = false;
60
61
    /**
62
     * @var bool
63
     */
64
    protected $checkForMissingPropertiesInConstructor = false;
65
66
    /**
67
     * @var bool
68
     */
69
    protected $checkPropertiesMismatchInConstructor = false;
70
71
    /**
72
     * @var bool
73
     */
74
    protected $checkPropertiesMismatch = true;
75
76
    /**
77
     * @var array<int|string,TypeCheckInterface>|\Arrayy\Type\TypeInterface|TypeCheckArray<int|string,TypeCheckInterface>
78
     */
79
    protected $properties = [];
80
81
    /**
82
     * Initializes
83
     *
84
     * @param mixed  $data                         <p>
85
     *                                             Should be an array or a generator, otherwise it will try
86
     *                                             to convert it into an array.
87
     *                                             </p>
88
     * @param string $iteratorClass                optional <p>
89
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
90
     *                                             need this option.
91
     *                                             </p>
92
     * @param bool   $checkPropertiesInConstructor optional <p>
93
     *                                             You need to extend the "Arrayy"-class and you need to set
94
     *                                             the $checkPropertiesMismatchInConstructor class property
95
     *                                             to
96
     *                                             true, otherwise this option didn't not work anyway.
97
     *                                             </p>
98
     *
99
     * @psalm-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
100
     */
101 1066
    public function __construct(
102
        $data = [],
103
        string $iteratorClass = ArrayyIterator::class,
104
        bool $checkPropertiesInConstructor = true
105
    ) {
106 1066
        $data = $this->fallbackForArray($data);
107
108
        // used only for serialize + unserialize, all other methods are overwritten
109 1064
        parent::__construct([], 0, $iteratorClass);
110
111 1064
        $this->setInitialValuesAndProperties($data, $checkPropertiesInConstructor);
112
113 1057
        $this->setIteratorClass($iteratorClass);
114 1057
    }
115
116
    /**
117
     * Call object as function.
118
     *
119
     * @param mixed $key
120
     *
121
     * @return mixed
122
     */
123 1
    public function __invoke($key = null)
124
    {
125 1
        if ($key !== null) {
126 1
            $this->generatorToArray();
127
128 1
            return $this->array[$key] ?? false;
129
        }
130
131
        return $this->getArray();
132
    }
133
134
    /**
135
     * Whether or not an element exists by key.
136
     *
137
     * @param mixed $key
138
     *
139
     * @return bool
140
     *              <p>True is the key/index exists, otherwise false.</p>
141
     */
142
    public function __isset($key): bool
143
    {
144
        return $this->offsetExists($key);
145
    }
146
147
    /**
148
     * Assigns a value to the specified element.
149
     *
150
     * @param mixed $key
151
     * @param mixed $value
152
     *
153
     * @return void
154
     */
155 2
    public function __set($key, $value)
156
    {
157 2
        $this->internalSet($key, $value);
158 2
    }
159
160
    /**
161
     * magic to string
162
     *
163
     * @return string
164
     */
165 15
    public function __toString(): string
166
    {
167 15
        return $this->toString();
168
    }
169
170
    /**
171
     * Unset element by key.
172
     *
173
     * @param mixed $key
174
     */
175
    public function __unset($key)
176
    {
177
        $this->internalRemove($key);
178
    }
179
180
    /**
181
     * Get a value by key.
182
     *
183
     * @param mixed $key
184
     *
185
     * @return mixed
186
     *               <p>Get a Value from the current array.</p>
187
     */
188 4
    public function &__get($key)
189
    {
190 4
        $return = $this->get($key);
191
192 4
        if (\is_array($return) === true) {
193
            return static::create($return, $this->iteratorClass, false);
194
        }
195
196 4
        return $return;
197
    }
198
199
    /**
200
     * alias: for "Arrayy->append()"
201
     *
202
     * @param mixed $value
203
     *
204
     * @return static
205
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
206
     *
207
     * @see          Arrayy::append()
208
     *
209
     * @psalm-param  T $value
210
     * @psalm-return static<TKey,T>
211
     */
212 3
    public function add($value)
213
    {
214 3
        return $this->append($value);
215
    }
216
217
    /**
218
     * Append a (key) + value to the current array.
219
     *
220
     * @param mixed $value
221
     * @param mixed $key
222
     *
223
     * @return $this
224
     *               <p>(Mutable) Return this Arrayy object, with the appended values.</p>
225
     *
226
     * @psalm-param  T $value
227
     * @psalm-return $this<TKey,T>
228
     */
229 13
    public function append($value, $key = null): self
230
    {
231 13
        $this->generatorToArray();
232
233 13
        if ($this->properties !== []) {
234 4
            $this->checkType($key, $value);
235
        }
236
237 12
        if ($key !== null) {
238
            if (
239
                isset($this->array[$key])
240
                &&
241
                \is_array($this->array[$key]) === true
242
            ) {
243
                $this->array[$key][] = $value;
244
            } else {
245
                $this->array[$key] = $value;
246
            }
247
        } else {
248 12
            $this->array[] = $value;
249
        }
250
251 12
        return $this;
252
    }
253
254
    /**
255
     * Sort the entries by value.
256
     *
257
     * @param int $sort_flags [optional] <p>
258
     *                        You may modify the behavior of the sort using the optional
259
     *                        parameter sort_flags, for details
260
     *                        see sort.
261
     *                        </p>
262
     *
263
     * @return $this
264
     *               <p>(Mutable) Return this Arrayy object.</p>
265
     *
266
     * @psalm-return $this<TKey,T>
267
     */
268 4
    public function asort(int $sort_flags = 0): self
269
    {
270 4
        $this->generatorToArray();
271
272 4
        \asort($this->array, $sort_flags);
273
274 4
        return $this;
275
    }
276
277
    /**
278
     * Counts all elements in an array, or something in an object.
279
     *
280
     * <p>
281
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
282
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
283
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
284
     * implemented and used in PHP.
285
     * </p>
286
     *
287
     * @see http://php.net/manual/en/function.count.php
288
     *
289
     * @param int $mode [optional] If the optional mode parameter is set to
290
     *                  COUNT_RECURSIVE (or 1), count
291
     *                  will recursively count the array. This is particularly useful for
292
     *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
293
     *
294
     * @return int
295
     *             <p>
296
     *             The number of elements in var, which is
297
     *             typically an array, since anything else will have one
298
     *             element.
299
     *             </p>
300
     *             <p>
301
     *             If var is not an array or an object with
302
     *             implemented Countable interface,
303
     *             1 will be returned.
304
     *             There is one exception, if var is &null;,
305
     *             0 will be returned.
306
     *             </p>
307
     *             <p>
308
     *             Caution: count may return 0 for a variable that isn't set,
309
     *             but it may also return 0 for a variable that has been initialized with an
310
     *             empty array. Use isset to test if a variable is set.
311
     *             </p>
312
     */
313 145
    public function count(int $mode = \COUNT_NORMAL): int
314
    {
315
        if (
316 145
            $this->generator
317
            &&
318 145
            $mode === \COUNT_NORMAL
319
        ) {
320 4
            return \iterator_count($this->generator);
321
        }
322
323 141
        return \count($this->getArray(), $mode);
324
    }
325
326
    /**
327
     * Exchange the array for another one.
328
     *
329
     * @param array|static $data
330
     *
331
     * @return array
332
     *
333
     * @psalm-param  array<TKey,T>|self<TKey,T> $data
334
     * @psalm-return array<TKey,T>
335
     */
336 1
    public function exchangeArray($data): array
337
    {
338 1
        $this->array = $this->fallbackForArray($data);
339
340 1
        return $this->array;
341
    }
342
343
    /**
344
     * Creates a copy of the ArrayyObject.
345
     *
346
     * @return array
347
     *
348
     * @psalm-return array<TKey,T>
349
     */
350 5
    public function getArrayCopy(): array
351
    {
352 5
        $this->generatorToArray();
353
354 5
        return $this->array;
355
    }
356
357
    /**
358
     * Returns a new iterator, thus implementing the \Iterator interface.
359
     *
360
     * @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...
361
     *                          <p>An iterator for the values in the array.</p>
362
     */
363 24
    public function getIterator(): \Iterator
364
    {
365 24
        if ($this->generator instanceof ArrayyRewindableGenerator) {
366 1
            return $this->generator;
367
        }
368
369 23
        $iterator = $this->getIteratorClass();
370
371 23
        if ($iterator === ArrayyIterator::class) {
372 23
            return new $iterator($this->getArray(), 0, static::class);
373
        }
374
375
        return new $iterator($this->getArray());
376
    }
377
378
    /**
379
     * Gets the iterator classname for the ArrayObject.
380
     *
381
     * @return string
382
     *
383
     * @psalm-return class-string
384
     */
385 23
    public function getIteratorClass(): string
386
    {
387 23
        return $this->iteratorClass;
388
    }
389
390
    /**
391
     * Sort the entries by key
392
     *
393
     * @param int $sort_flags [optional] <p>
394
     *                        You may modify the behavior of the sort using the optional
395
     *                        parameter sort_flags, for details
396
     *                        see sort.
397
     *                        </p>
398
     *
399
     * @return $this
400
     *               <p>(Mutable) Return this Arrayy object.</p>
401
     *
402
     * @psalm-return $this<TKey,T>
403
     */
404 4
    public function ksort(int $sort_flags = 0): self
405
    {
406 4
        $this->generatorToArray();
407
408 4
        \ksort($this->array, $sort_flags);
409
410 4
        return $this;
411
    }
412
413
    /**
414
     * Sort an array using a case insensitive "natural order" algorithm
415
     *
416
     * @return $this
417
     *               <p>(Mutable) Return this Arrayy object.</p>
418
     *
419
     * @psalm-return $this<TKey,T>
420
     */
421
    public function natcasesort(): self
422
    {
423
        $this->generatorToArray();
424
425
        \natcasesort($this->array);
426
427
        return $this;
428
    }
429
430
    /**
431
     * Sort entries using a "natural order" algorithm
432
     *
433
     * @return $this
434
     *               <p>(Mutable) Return this Arrayy object.</p>
435
     *
436
     * @psalm-return $this<TKey,T>
437
     */
438 1
    public function natsort(): self
439
    {
440 1
        $this->generatorToArray();
441
442 1
        \natsort($this->array);
443
444 1
        return $this;
445
    }
446
447
    /**
448
     * Whether or not an offset exists.
449
     *
450
     * @param bool|int|string $offset
451
     *
452
     * @return bool
453
     *
454
     * @noinspection PhpSillyAssignmentInspection
455
     */
456 130
    public function offsetExists($offset): bool
457
    {
458 130
        $this->generatorToArray();
459
460 130
        if ($this->array === []) {
461 5
            return false;
462
        }
463
464
        // php cast "bool"-index into "int"-index
465 125
        if ((bool) $offset === $offset) {
466 1
            $offset = (int) $offset;
467
        }
468
469
        /** @var int|string $offset - hint for phpstan */
470 125
        $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...
471
472 125
        $tmpReturn = $this->keyExists($offset);
473
474
        if (
475 125
            $tmpReturn === true
476
            ||
477
            (
478 92
                $tmpReturn === false
479
                &&
480 125
                \strpos((string) $offset, $this->pathSeparator) === false
481
            )
482
        ) {
483 123
            return $tmpReturn;
484
        }
485
486 3
        $offsetExists = false;
487
488
        if (
489 3
            $this->pathSeparator
490
            &&
491 3
            (string) $offset === $offset
492
            &&
493 3
            \strpos($offset, $this->pathSeparator) !== false
494
        ) {
495 3
            $explodedPath = \explode($this->pathSeparator, (string) $offset);
496 3
            if ($explodedPath !== false) {
497 3
                $lastOffset = \array_pop($explodedPath);
498 3
                if ($lastOffset !== null) {
499 3
                    $containerPath = \implode($this->pathSeparator, $explodedPath);
500
501 3
                    $this->callAtPath(
502 3
                        $containerPath,
503
                        static function ($container) use ($lastOffset, &$offsetExists) {
504 3
                            $offsetExists = \array_key_exists($lastOffset, $container);
505 3
                        }
506
                    );
507
                }
508
            }
509
        }
510
511 3
        return $offsetExists;
512
    }
513
514
    /**
515
     * Returns the value at specified offset.
516
     *
517
     * @param int|string $offset
518
     *
519
     * @return mixed
520
     *               <p>Will return null if the offset did not exists.</p>
521
     */
522 101
    public function offsetGet($offset)
523
    {
524 101
        return $this->offsetExists($offset) ? $this->get($offset) : null;
525
    }
526
527
    /**
528
     * Assigns a value to the specified offset + check the type.
529
     *
530
     * @param int|string|null $offset
531
     * @param mixed           $value
532
     *
533
     * @return void
534
     */
535 21
    public function offsetSet($offset, $value)
536
    {
537 21
        $this->generatorToArray();
538
539 21
        if ($offset === null) {
540 5
            if ($this->properties !== []) {
541 1
                $this->checkType(null, $value);
542
            }
543
544 4
            $this->array[] = $value;
545
        } else {
546 16
            $this->internalSet(
547 16
                $offset,
548 16
                $value,
549 16
                true
550
            );
551
        }
552 20
    }
553
554
    /**
555
     * Unset an offset.
556
     *
557
     * @param int|string $offset
558
     *
559
     * @return void
560
     */
561 12
    public function offsetUnset($offset)
562
    {
563 12
        $this->generatorToArray();
564
565 12
        if ($this->array === []) {
566 3
            return;
567
        }
568
569 10
        if ($this->keyExists($offset)) {
570 7
            unset($this->array[$offset]);
571
572 7
            return;
573
        }
574
575
        if (
576 5
            $this->pathSeparator
577
            &&
578 5
            (string) $offset === $offset
579
            &&
580 5
            \strpos($offset, $this->pathSeparator) !== false
581
        ) {
582 2
            $path = \explode($this->pathSeparator, (string) $offset);
583
584 2
            if ($path !== false) {
585 2
                $pathToUnset = \array_pop($path);
586
587 2
                $this->callAtPath(
588 2
                    \implode($this->pathSeparator, $path),
589
                    static function (&$offset) use ($pathToUnset) {
590 2
                        unset($offset[$pathToUnset]);
591 2
                    }
592
                );
593
            }
594
        }
595
596 5
        unset($this->array[$offset]);
597 5
    }
598
599
    /**
600
     * Serialize the current "Arrayy"-object.
601
     *
602
     * @return string
603
     */
604 2
    public function serialize(): string
605
    {
606 2
        $this->generatorToArray();
607
608 2
        if (\PHP_VERSION_ID < 70400) {
609 2
            return parent::serialize();
610
        }
611
612
        return \serialize($this);
613
    }
614
615
    /**
616
     * Sets the iterator classname for the current "Arrayy"-object.
617
     *
618
     * @param string $iteratorClass
619
     *
620
     * @throws \InvalidArgumentException
621
     *
622
     * @return void
623
     *
624
     * @psalm-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
625
     */
626 1057
    public function setIteratorClass($iteratorClass)
627
    {
628 1057
        if (\class_exists($iteratorClass)) {
629 1057
            $this->iteratorClass = $iteratorClass;
630
631 1057
            return;
632
        }
633
634
        if (\strpos($iteratorClass, '\\') === 0) {
635
            $iteratorClass = '\\' . $iteratorClass;
636
            if (\class_exists($iteratorClass)) {
637
                $this->iteratorClass = $iteratorClass;
638
639
                return;
640
            }
641
        }
642
643
        throw new \InvalidArgumentException('The iterator class does not exist: ' . $iteratorClass);
644
    }
645
646
    /**
647
     * Sort the entries with a user-defined comparison function and maintain key association.
648
     *
649
     * @param callable $function
650
     *
651
     * @throws \InvalidArgumentException
652
     *
653
     * @return $this
654
     *               <p>(Mutable) Return this Arrayy object.</p>
655
     *
656
     * @psalm-return $this<TKey,T>
657
     */
658 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...
659
    {
660
        if (!\is_callable($function)) {
661
            throw new \InvalidArgumentException('Passed function must be callable');
662
        }
663
664
        $this->generatorToArray();
665
666
        \uasort($this->array, $function);
667
668
        return $this;
669
    }
670
671
    /**
672
     * Sort the entries by keys using a user-defined comparison function.
673
     *
674
     * @param callable $function
675
     *
676
     * @throws \InvalidArgumentException
677
     *
678
     * @return static
679
     *                <p>(Mutable) Return this Arrayy object.</p>
680
     *
681
     * @psalm-return static<TKey,T>
682
     */
683 5
    public function uksort($function): self
684
    {
685 5
        return $this->customSortKeys($function);
686
    }
687
688
    /**
689
     * Unserialize an string and return the instance of the "Arrayy"-class.
690
     *
691
     * @param string $string
692
     *
693
     * @return $this
694
     *
695
     * @psalm-return $this<TKey,T>
696
     */
697 2
    public function unserialize($string): self
698
    {
699 2
        if (\PHP_VERSION_ID < 70400) {
700 2
            parent::unserialize($string);
701
702 2
            return $this;
703
        }
704
705
        return \unserialize($string, ['allowed_classes' => [__CLASS__, TypeCheckPhpDoc::class]]);
706
    }
707
708
    /**
709
     * Append a (key) + values to the current array.
710
     *
711
     * @param array $values
712
     * @param mixed $key
713
     *
714
     * @return $this
715
     *               <p>(Mutable) Return this Arrayy object, with the appended values.</p>
716
     *
717
     * @psalm-param  array<mixed,T> $values
718
     * @psalm-param  TKey|null $key
719
     * @psalm-return $this<TKey,T>
720
     */
721 1
    public function appendArrayValues(array $values, $key = null)
722
    {
723 1
        $this->generatorToArray();
724
725 1
        if ($key !== null) {
726
            if (
727 1
                isset($this->array[$key])
728
                &&
729 1
                \is_array($this->array[$key]) === true
730
            ) {
731 1
                foreach ($values as $value) {
732 1
                    $this->array[$key][] = $value;
733
                }
734
            } else {
735
                foreach ($values as $value) {
736 1
                    $this->array[$key] = $value;
737
                }
738
            }
739
        } else {
740
            foreach ($values as $value) {
741
                $this->array[] = $value;
742
            }
743
        }
744
745 1
        return $this;
746
    }
747
748
    /**
749
     * Add a suffix to each key.
750
     *
751
     * @param mixed $prefix
752
     *
753
     * @return static
754
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
755
     *
756
     * @psalm-return static<TKey,T>
757
     * @psalm-mutation-free
758
     */
759 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...
760
    {
761
        // init
762 10
        $result = [];
763
764 10
        foreach ($this->getGenerator() as $key => $item) {
765 9
            if ($item instanceof self) {
766
                $result[$prefix . $key] = $item->appendToEachKey($prefix);
767 9
            } elseif (\is_array($item) === true) {
768
                $result[$prefix . $key] = self::create($item, $this->iteratorClass, false)
769
                    ->appendToEachKey($prefix)
770
                    ->toArray();
771
            } else {
772 9
                $result[$prefix . $key] = $item;
773
            }
774
        }
775
776 10
        return self::create($result, $this->iteratorClass, false);
777
    }
778
779
    /**
780
     * Add a prefix to each value.
781
     *
782
     * @param mixed $prefix
783
     *
784
     * @return static
785
     *                <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
786
     *
787
     * @psalm-return static<TKey,T>
788
     * @psalm-mutation-free
789
     */
790 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...
791
    {
792
        // init
793 10
        $result = [];
794
795 10
        foreach ($this->getGenerator() as $key => $item) {
796 9
            if ($item instanceof self) {
797
                $result[$key] = $item->appendToEachValue($prefix);
798 9
            } elseif (\is_array($item) === true) {
799
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
800 9
            } elseif (\is_object($item) === true) {
801 1
                $result[$key] = $item;
802
            } else {
803 9
                $result[$key] = $prefix . $item;
804
            }
805
        }
806
807 10
        return self::create($result, $this->iteratorClass, false);
808
    }
809
810
    /**
811
     * Sort an array in reverse order and maintain index association.
812
     *
813
     * @return $this
814
     *               <p>(Mutable) Return this Arrayy object.</p>
815
     *
816
     * @psalm-return $this<TKey,T>
817
     */
818 10
    public function arsort(): self
819
    {
820 10
        $this->generatorToArray();
821
822 10
        \arsort($this->array);
823
824 10
        return $this;
825
    }
826
827
    /**
828
     * Iterate over the current array and execute a callback for each loop.
829
     *
830
     * @param \Closure $closure
831
     *
832
     * @return static
833
     *                <p>(Immutable)</p>
834
     *
835
     * @psalm-return static<TKey,T>
836
     * @psalm-mutation-free
837
     */
838 2
    public function at(\Closure $closure): self
839
    {
840 2
        $arrayy = clone $this;
841
842 2
        foreach ($arrayy->getGenerator() as $key => $value) {
843 2
            $closure($value, $key);
844
        }
845
846 2
        return static::create(
847 2
            $arrayy->toArray(),
848 2
            $this->iteratorClass,
849 2
            false
850
        );
851
    }
852
853
    /**
854
     * Returns the average value of the current array.
855
     *
856
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
857
     *
858
     * @return float|int
859
     *                   <p>The average value.</p>
860
     */
861 10
    public function average($decimals = 0)
862
    {
863 10
        $count = \count($this->getArray(), \COUNT_NORMAL);
864
865 10
        if (!$count) {
866 2
            return 0;
867
        }
868
869 8
        if ((int) $decimals !== $decimals) {
870 3
            $decimals = 0;
871
        }
872
873 8
        return \round(\array_sum($this->getArray()) / $count, $decimals);
874
    }
875
876
    /**
877
     * Changes all keys in an array.
878
     *
879
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
880
     *                  or <strong>CASE_LOWER</strong> (default)</p>
881
     *
882
     * @return static
883
     *                <p>(Immutable)</p>
884
     *
885
     * @psalm-return static<TKey,T>
886
     * @psalm-mutation-free
887
     */
888 1
    public function changeKeyCase(int $case = \CASE_LOWER): self
889
    {
890
        if (
891 1
            $case !== \CASE_LOWER
892
            &&
893 1
            $case !== \CASE_UPPER
894
        ) {
895
            $case = \CASE_LOWER;
896
        }
897
898 1
        $return = [];
899 1
        foreach ($this->getGenerator() as $key => $value) {
900 1
            if ($case === \CASE_LOWER) {
901 1
                $key = \mb_strtolower((string) $key);
902
            } else {
903 1
                $key = \mb_strtoupper((string) $key);
904
            }
905
906 1
            $return[$key] = $value;
907
        }
908
909 1
        return static::create(
910 1
            $return,
911 1
            $this->iteratorClass,
912 1
            false
913
        );
914
    }
915
916
    /**
917
     * Change the path separator of the array wrapper.
918
     *
919
     * By default, the separator is: "."
920
     *
921
     * @param string $separator <p>Separator to set.</p>
922
     *
923
     * @return $this
924
     *               <p>(Mutable) Return this Arrayy object.</p>
925
     *
926
     * @psalm-return $this<TKey,T>
927
     */
928 11
    public function changeSeparator($separator): self
929
    {
930 11
        $this->pathSeparator = $separator;
931
932 11
        return $this;
933
    }
934
935
    /**
936
     * Create a chunked version of the current array.
937
     *
938
     * @param int  $size         <p>Size of each chunk.</p>
939
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
940
     *
941
     * @return static
942
     *                <p>(Immutable) A new array of chunks from the original array.</p>
943
     *
944
     * @psalm-return static<TKey,T>
945
     * @psalm-mutation-free
946
     */
947 5
    public function chunk($size, $preserveKeys = false): self
948
    {
949 5
        return static::create(
950 5
            \array_chunk($this->getArray(), $size, $preserveKeys),
951 5
            $this->iteratorClass,
952 5
            false
953
        );
954
    }
955
956
    /**
957
     * Clean all falsy values from the current array.
958
     *
959
     * @return static
960
     *                <p>(Immutable)</p>
961
     *
962
     * @psalm-return static<TKey,T>
963
     * @psalm-mutation-free
964
     */
965 8
    public function clean(): self
966
    {
967 8
        return $this->filter(
968
            static function ($value) {
969 7
                return (bool) $value;
970 8
            }
971
        );
972
    }
973
974
    /**
975
     * WARNING!!! -> Clear the current array.
976
     *
977
     * @return $this
978
     *               <p>(Mutable) Return this Arrayy object, with an empty array.</p>
979
     *
980
     * @psalm-return $this<TKey,T>
981
     */
982 5
    public function clear(): self
983
    {
984 5
        $this->array = [];
985 5
        $this->generator = null;
986
987 5
        return $this;
988
    }
989
990
    /**
991
     * Check if an item is in the current array.
992
     *
993
     * @param float|int|string $value
994
     * @param bool             $recursive
995
     * @param bool             $strict
996
     *
997
     * @return bool
998
     */
999 23
    public function contains($value, bool $recursive = false, bool $strict = true): bool
1000
    {
1001 23
        if ($recursive === true) {
1002 18
            return $this->in_array_recursive($value, $this->getArray(), $strict);
1003
        }
1004
1005 14
        foreach ($this->getGenerator() as $valueFromArray) {
1006 11
            if ($strict) {
1007 11
                if ($value === $valueFromArray) {
1008 11
                    return true;
1009
                }
1010
            } else {
1011
                /** @noinspection NestedPositiveIfStatementsInspection */
1012
                if ($value == $valueFromArray) {
1013 7
                    return true;
1014
                }
1015
            }
1016
        }
1017
1018 7
        return false;
1019
    }
1020
1021
    /**
1022
     * Check if an (case-insensitive) string is in the current array.
1023
     *
1024
     * @param string $value
1025
     * @param bool   $recursive
1026
     *
1027
     * @return bool
1028
     */
1029 26
    public function containsCaseInsensitive($value, $recursive = false): bool
1030
    {
1031 26
        if ($recursive === true) {
1032 26
            foreach ($this->getGenerator() as $key => $valueTmp) {
1033 22
                if (\is_array($valueTmp) === true) {
1034 5
                    $return = (new self($valueTmp))->containsCaseInsensitive($value, $recursive);
1035 5
                    if ($return === true) {
1036 5
                        return $return;
1037
                    }
1038 22
                } elseif (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
1039 22
                    return true;
1040
                }
1041
            }
1042
1043 10
            return false;
1044
        }
1045
1046 13
        foreach ($this->getGenerator() as $key => $valueTmp) {
1047 11
            if (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
1048 11
                return true;
1049
            }
1050
        }
1051
1052 5
        return false;
1053
    }
1054
1055
    /**
1056
     * Check if the given key/index exists in the array.
1057
     *
1058
     * @param int|string $key <p>key/index to search for</p>
1059
     *
1060
     * @return bool
1061
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
1062
     */
1063 4
    public function containsKey($key): bool
1064
    {
1065 4
        return $this->offsetExists($key);
1066
    }
1067
1068
    /**
1069
     * Check if all given needles are present in the array as key/index.
1070
     *
1071
     * @param array $needles   <p>The keys you are searching for.</p>
1072
     * @param bool  $recursive
1073
     *
1074
     * @return bool
1075
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1076
     *
1077
     * @psalm-param array<mixed,mixed>|array<TKey> $needles
1078
     */
1079 2
    public function containsKeys(array $needles, $recursive = false): bool
1080
    {
1081 2
        if ($recursive === true) {
1082
            return
1083 2
                \count(
1084 2
                    \array_intersect(
1085 2
                        $needles,
1086 2
                        $this->keys(true)->getArray()
1087
                    ),
1088 2
                    \COUNT_RECURSIVE
1089
                )
1090
                ===
1091 2
                \count(
1092 2
                    $needles,
1093 2
                    \COUNT_RECURSIVE
1094
                );
1095
        }
1096
1097 1
        return \count(
1098 1
            \array_intersect($needles, $this->keys()->getArray()),
1099 1
            \COUNT_NORMAL
1100
        )
1101
               ===
1102 1
               \count(
1103 1
                   $needles,
1104 1
                   \COUNT_NORMAL
1105
               );
1106
    }
1107
1108
    /**
1109
     * Check if all given needles are present in the array as key/index.
1110
     *
1111
     * @param array $needles <p>The keys you are searching for.</p>
1112
     *
1113
     * @return bool
1114
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1115
     *
1116
     * @psalm-param array<mixed,mixed>|array<TKey> $needles
1117
     */
1118 1
    public function containsKeysRecursive(array $needles): bool
1119
    {
1120 1
        return $this->containsKeys($needles, true);
1121
    }
1122
1123
    /**
1124
     * alias: for "Arrayy->contains()"
1125
     *
1126
     * @param float|int|string $value
1127
     *
1128
     * @return bool
1129
     *
1130
     * @see Arrayy::contains()
1131
     */
1132 9
    public function containsValue($value): bool
1133
    {
1134 9
        return $this->contains($value);
1135
    }
1136
1137
    /**
1138
     * alias: for "Arrayy->contains($value, true)"
1139
     *
1140
     * @param float|int|string $value
1141
     *
1142
     * @return bool
1143
     *
1144
     * @see Arrayy::contains()
1145
     */
1146 18
    public function containsValueRecursive($value): bool
1147
    {
1148 18
        return $this->contains($value, true);
1149
    }
1150
1151
    /**
1152
     * Check if all given needles are present in the array.
1153
     *
1154
     * @param array $needles
1155
     *
1156
     * @return bool
1157
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
1158
     *
1159
     * @psalm-param array<mixed>|array<T> $needles
1160
     */
1161 1
    public function containsValues(array $needles): bool
1162
    {
1163 1
        return \count(\array_intersect($needles, $this->getArray()), \COUNT_NORMAL)
1164
               ===
1165 1
               \count($needles, \COUNT_NORMAL);
1166
    }
1167
1168
    /**
1169
     * Counts all the values of an array
1170
     *
1171
     * @see          http://php.net/manual/en/function.array-count-values.php
1172
     *
1173
     * @return static
1174
     *                <p>
1175
     *                (Immutable)
1176
     *                An associative Arrayy-object of values from input as
1177
     *                keys and their count as value.
1178
     *                </p>
1179
     *
1180
     * @psalm-return static<TKey,T>
1181
     * @psalm-mutation-free
1182
     */
1183 7
    public function countValues(): self
1184
    {
1185 7
        return self::create(\array_count_values($this->getArray()), $this->iteratorClass);
1186
    }
1187
1188
    /**
1189
     * Creates an Arrayy object.
1190
     *
1191
     * @param mixed  $data
1192
     * @param string $iteratorClass
1193
     * @param bool   $checkPropertiesInConstructor
1194
     *
1195
     * @return static
1196
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1197
     *
1198
     * @psalm-param  class-string<\Arrayy\ArrayyIterator> $iteratorClass
1199
     * @psalm-return static<TKey,T>
1200
     * @psalm-mutation-free
1201
     */
1202 670
    public static function create(
1203
        $data = [],
1204
        string $iteratorClass = ArrayyIterator::class,
1205
        bool $checkPropertiesInConstructor = true
1206
    ) {
1207 670
        return new static(
1208 670
            $data,
1209 670
            $iteratorClass,
1210 670
            $checkPropertiesInConstructor
1211
        );
1212
    }
1213
1214
    /**
1215
     * WARNING: Creates an Arrayy object by reference.
1216
     *
1217
     * @param array $array
1218
     *
1219
     * @return $this
1220
     *               <p>(Mutable) Return this Arrayy object.</p>
1221
     *
1222
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
1223
     * @psalm-return $this<TKey,T>
1224
     */
1225 1
    public function createByReference(array &$array = []): self
1226
    {
1227 1
        $array = $this->fallbackForArray($array);
1228
1229 1
        $this->array = &$array;
1230
1231 1
        return $this;
1232
    }
1233
1234
    /**
1235
     * Create an new instance from a callable function which will return an Generator.
1236
     *
1237
     * @param callable $generatorFunction
1238
     *
1239
     * @return static
1240
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1241
     *
1242
     * @psalm-param  callable():\Generator<TKey,T> $generatorFunction
1243
     * @psalm-return static<TKey,T>
1244
     * @psalm-mutation-free
1245
     */
1246 5
    public static function createFromGeneratorFunction(callable $generatorFunction): self
1247
    {
1248 5
        return self::create($generatorFunction);
1249
    }
1250
1251
    /**
1252
     * Create an new instance filled with a copy of values from a "Generator"-object.
1253
     *
1254
     * @param \Generator $generator
1255
     *
1256
     * @return static
1257
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1258
     *
1259
     * @psalm-param \Generator<TKey,T> $generator
1260
     * @psalm-return static<TKey,T>
1261
     * @psalm-mutation-free
1262
     */
1263 4
    public static function createFromGeneratorImmutable(\Generator $generator): self
1264
    {
1265 4
        return self::create(\iterator_to_array($generator, true));
1266
    }
1267
1268
    /**
1269
     * Create an new Arrayy object via JSON.
1270
     *
1271
     * @param string $json
1272
     *
1273
     * @return static
1274
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1275
     *
1276
     * @psalm-return static<TKey,T>
1277
     * @psalm-mutation-free
1278
     */
1279 5
    public static function createFromJson(string $json): self
1280
    {
1281 5
        return static::create(\json_decode($json, true));
1282
    }
1283
1284
    /**
1285
     * Create an new instance filled with values from an object that is iterable.
1286
     *
1287
     * @param \Traversable $object <p>iterable object</p>
1288
     *
1289
     * @return static
1290
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1291
     *
1292
     * @psalm-param \Traversable<TKey,T> $object
1293
     * @psalm-return static<TKey,T>
1294
     * @psalm-mutation-free
1295
     */
1296 4
    public static function createFromObject(\Traversable $object): self
1297
    {
1298
        // init
1299 4
        $array = self::create();
1300
1301 4
        if ($object instanceof self) {
1302 4
            $objectArray = $object->getGenerator();
1303
        } else {
1304
            $objectArray = $object;
1305
        }
1306
1307 4
        foreach ($objectArray as $key => $value) {
1308 3
            $array[$key] = $value;
1309
        }
1310
1311 4
        return $array;
1312
    }
1313
1314
    /**
1315
     * Create an new instance filled with values from an object.
1316
     *
1317
     * @param object $object
1318
     *
1319
     * @return static
1320
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1321
     *
1322
     * @psalm-return static<TKey,T>
1323
     * @psalm-mutation-free
1324
     */
1325 5
    public static function createFromObjectVars($object): self
1326
    {
1327 5
        return self::create(self::objectToArray($object));
1328
    }
1329
1330
    /**
1331
     * Create an new Arrayy object via string.
1332
     *
1333
     * @param string      $str       <p>The input string.</p>
1334
     * @param string|null $delimiter <p>The boundary string.</p>
1335
     * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1336
     *                               used.</p>
1337
     *
1338
     * @return static
1339
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1340
     *
1341
     * @psalm-return static<TKey,T>
1342
     * @psalm-mutation-free
1343
     */
1344 10
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
1345
    {
1346 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...
1347 1
            \preg_match_all($regEx, $str, $array);
1348
1349 1
            if (!empty($array)) {
1350 1
                $array = $array[0];
1351
            }
1352
        } else {
1353
            /** @noinspection NestedPositiveIfStatementsInspection */
1354 9
            if ($delimiter !== null) {
1355 7
                $array = \explode($delimiter, $str);
1356
            } else {
1357 2
                $array = [$str];
1358
            }
1359
        }
1360
1361
        // trim all string in the array
1362 10
        \array_walk(
1363 10
            $array,
1364
            static function (&$val) {
1365 10
                if ((string) $val === $val) {
1366 10
                    $val = \trim($val);
1367
                }
1368 10
            }
1369
        );
1370
1371 10
        return static::create($array);
1372
    }
1373
1374
    /**
1375
     * Create an new instance filled with a copy of values from a "Traversable"-object.
1376
     *
1377
     * @param \Traversable $traversable
1378
     *
1379
     * @return static
1380
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1381
     *
1382
     * @psalm-param \Traversable<TKey,T> $traversable
1383
     * @psalm-return static<TKey,T>
1384
     * @psalm-mutation-free
1385
     */
1386 1
    public static function createFromTraversableImmutable(\Traversable $traversable): self
1387
    {
1388 1
        return self::create(\iterator_to_array($traversable, true));
1389
    }
1390
1391
    /**
1392
     * Create an new instance containing a range of elements.
1393
     *
1394
     * @param mixed $low  <p>First value of the sequence.</p>
1395
     * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1396
     * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1397
     *
1398
     * @return static
1399
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1400
     *
1401
     * @psalm-return static<TKey,T>
1402
     * @psalm-mutation-free
1403
     */
1404 2
    public static function createWithRange($low, $high, int $step = 1): self
1405
    {
1406 2
        return static::create(\range($low, $high, $step));
1407
    }
1408
1409
    /**
1410
     * Gets the element of the array at the current internal iterator position.
1411
     *
1412
     * @return false|mixed
1413
     */
1414
    public function current()
1415
    {
1416
        return \current($this->array);
1417
    }
1418
1419
    /**
1420
     * Custom sort by index via "uksort".
1421
     *
1422
     * @see          http://php.net/manual/en/function.uksort.php
1423
     *
1424
     * @param callable $function
1425
     *
1426
     * @throws \InvalidArgumentException
1427
     *
1428
     * @return $this
1429
     *               <p>(Mutable) Return this Arrayy object.</p>
1430
     *
1431
     * @psalm-return $this<TKey,T>
1432
     */
1433 5
    public function customSortKeys(callable $function): self
1434
    {
1435 5
        $this->generatorToArray();
1436
1437 5
        \uksort($this->array, $function);
1438
1439 5
        return $this;
1440
    }
1441
1442
    /**
1443
     * Custom sort by value via "usort".
1444
     *
1445
     * @see          http://php.net/manual/en/function.usort.php
1446
     *
1447
     * @param callable $function
1448
     *
1449
     * @throws \InvalidArgumentException
1450
     *
1451
     * @return $this
1452
     *               <p>(Mutable) Return this Arrayy object.</p>
1453
     *
1454
     * @psalm-return $this<TKey,T>
1455
     */
1456 6 View Code Duplication
    public function customSortValues($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1457
    {
1458 6
        if (\is_callable($function) === false) {
1459
            throw new \InvalidArgumentException('Passed function must be callable');
1460
        }
1461
1462 6
        $this->generatorToArray();
1463
1464 6
        \usort($this->array, $function);
1465
1466 6
        return $this;
1467
    }
1468
1469
    /**
1470
     * Delete the given key or keys.
1471
     *
1472
     * @param int|int[]|string|string[] $keyOrKeys
1473
     *
1474
     * @return void
1475
     */
1476 4
    public function delete($keyOrKeys)
1477
    {
1478 4
        $keyOrKeys = (array) $keyOrKeys;
1479
1480 4
        foreach ($keyOrKeys as $key) {
1481 4
            $this->offsetUnset($key);
1482
        }
1483 4
    }
1484
1485
    /**
1486
     * Return values that are only in the current array.
1487
     *
1488
     * @param array ...$array
1489
     *
1490
     * @return static
1491
     *                <p>(Immutable)</p>
1492
     *
1493
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$array
1494
     * @psalm-return static<TKey,T>
1495
     * @psalm-mutation-free
1496
     */
1497 13
    public function diff(...$array): self
1498
    {
1499 13
        return static::create(
1500 13
            \array_diff($this->getArray(), ...$array),
1501 13
            $this->iteratorClass,
1502 13
            false
1503
        );
1504
    }
1505
1506
    /**
1507
     * Return values that are only in the current array.
1508
     *
1509
     * @param array ...$array
1510
     *
1511
     * @return static
1512
     *                <p>(Immutable)</p>
1513
     *
1514
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$array
1515
     * @psalm-return static<TKey,T>
1516
     * @psalm-mutation-free
1517
     */
1518 8
    public function diffKey(...$array): self
1519
    {
1520 8
        return static::create(
1521 8
            \array_diff_key($this->getArray(), ...$array),
1522 8
            $this->iteratorClass,
1523 8
            false
1524
        );
1525
    }
1526
1527
    /**
1528
     * Return values and Keys that are only in the current array.
1529
     *
1530
     * @param array $array
1531
     *
1532
     * @return static
1533
     *                <p>(Immutable)</p>
1534
     *
1535
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
1536
     * @psalm-return static<TKey,T>
1537
     * @psalm-mutation-free
1538
     */
1539 8
    public function diffKeyAndValue(array $array = []): self
1540
    {
1541 8
        return static::create(
1542 8
            \array_diff_assoc($this->getArray(), $array),
1543 8
            $this->iteratorClass,
1544 8
            false
1545
        );
1546
    }
1547
1548
    /**
1549
     * Return values that are only in the current multi-dimensional array.
1550
     *
1551
     * @param array      $array
1552
     * @param array|null $helperVariableForRecursion <p>(only for internal usage)</p>
1553
     *
1554
     * @return static
1555
     *                <p>(Immutable)</p>
1556
     *
1557
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
1558
     * @psalm-param  null|array<TKey,T> $helperVariableForRecursion
1559
     * @psalm-return static<TKey,T>
1560
     * @psalm-mutation-free
1561
     */
1562 1
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
1563
    {
1564
        // init
1565 1
        $result = [];
1566
1567
        if (
1568 1
            $helperVariableForRecursion !== null
1569
            &&
1570 1
            \is_array($helperVariableForRecursion) === true
1571
        ) {
1572
            $arrayForTheLoop = $helperVariableForRecursion;
1573
        } else {
1574 1
            $arrayForTheLoop = $this->getGenerator();
1575
        }
1576
1577 1
        foreach ($arrayForTheLoop as $key => $value) {
1578 1
            if ($value instanceof self) {
1579
                $value = $value->getArray();
1580
            }
1581
1582 1
            if (\array_key_exists($key, $array)) {
1583 1
                if ($value !== $array[$key]) {
1584 1
                    $result[$key] = $value;
1585
                }
1586
            } else {
1587 1
                $result[$key] = $value;
1588
            }
1589
        }
1590
1591 1
        return static::create(
1592 1
            $result,
1593 1
            $this->iteratorClass,
1594 1
            false
1595
        );
1596
    }
1597
1598
    /**
1599
     * Return values that are only in the new $array.
1600
     *
1601
     * @param array $array
1602
     *
1603
     * @return static
1604
     *                <p>(Immutable)</p>
1605
     *
1606
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
1607
     * @psalm-return static<TKey,T>
1608
     * @psalm-mutation-free
1609
     */
1610 8
    public function diffReverse(array $array = []): self
1611
    {
1612 8
        return static::create(
1613 8
            \array_diff($array, $this->getArray()),
1614 8
            $this->iteratorClass,
1615 8
            false
1616
        );
1617
    }
1618
1619
    /**
1620
     * Divide an array into two arrays. One with keys and the other with values.
1621
     *
1622
     * @return static
1623
     *                <p>(Immutable)</p>
1624
     *
1625
     * @psalm-return static<TKey,T>
1626
     * @psalm-mutation-free
1627
     */
1628 1
    public function divide(): self
1629
    {
1630 1
        return static::create(
1631
            [
1632 1
                $this->keys(),
1633 1
                $this->values(),
1634
            ],
1635 1
            $this->iteratorClass,
1636 1
            false
1637
        );
1638
    }
1639
1640
    /**
1641
     * Iterate over the current array and modify the array's value.
1642
     *
1643
     * @param \Closure $closure
1644
     *
1645
     * @return static
1646
     *                <p>(Immutable)</p>
1647
     *
1648
     * @psalm-return static<TKey,T>
1649
     * @psalm-mutation-free
1650
     */
1651 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...
1652
    {
1653
        // init
1654 5
        $array = [];
1655
1656 5
        foreach ($this->getGenerator() as $key => $value) {
1657 5
            $array[$key] = $closure($value, $key);
1658
        }
1659
1660 5
        return static::create(
1661 5
            $array,
1662 5
            $this->iteratorClass,
1663 5
            false
1664
        );
1665
    }
1666
1667
    /**
1668
     * Sets the internal iterator to the last element in the array and returns this element.
1669
     *
1670
     * @return mixed
1671
     */
1672
    public function end()
1673
    {
1674
        return \end($this->array);
1675
    }
1676
1677
    /**
1678
     * Check if a value is in the current array using a closure.
1679
     *
1680
     * @param \Closure $closure
1681
     *
1682
     * @return bool
1683
     *              <p>Returns true if the given value is found, false otherwise.</p>
1684
     */
1685 4
    public function exists(\Closure $closure): bool
1686
    {
1687
        // init
1688 4
        $isExists = false;
1689
1690 4
        foreach ($this->getGenerator() as $key => $value) {
1691 3
            if ($closure($value, $key)) {
1692 1
                $isExists = true;
1693
1694 3
                break;
1695
            }
1696
        }
1697
1698 4
        return $isExists;
1699
    }
1700
1701
    /**
1702
     * Fill the array until "$num" with "$default" values.
1703
     *
1704
     * @param int   $num
1705
     * @param mixed $default
1706
     *
1707
     * @return static
1708
     *                <p>(Immutable)</p>
1709
     *
1710
     * @psalm-return static<TKey,T>
1711
     * @psalm-mutation-free
1712
     */
1713 8
    public function fillWithDefaults(int $num, $default = null): self
1714
    {
1715 8
        if ($num < 0) {
1716 1
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1717
        }
1718
1719 7
        $this->generatorToArray();
1720
1721 7
        $tmpArray = $this->array;
1722
1723 7
        $count = \count($tmpArray);
1724
1725 7
        while ($count < $num) {
1726 4
            $tmpArray[] = $default;
1727 4
            ++$count;
1728
        }
1729
1730 7
        return static::create(
1731 7
            $tmpArray,
1732 7
            $this->iteratorClass,
1733 7
            false
1734
        );
1735
    }
1736
1737
    /**
1738
     * Find all items in an array that pass the truth test.
1739
     *
1740
     * @param \Closure|null $closure [optional] <p>
1741
     *                               The callback function to use
1742
     *                               </p>
1743
     *                               <p>
1744
     *                               If no callback is supplied, all entries of
1745
     *                               input equal to false (see
1746
     *                               converting to
1747
     *                               boolean) will be removed.
1748
     *                               </p>
1749
     * @param int           $flag    [optional] <p>
1750
     *                               Flag determining what arguments are sent to <i>callback</i>:
1751
     *                               </p><ul>
1752
     *                               <li>
1753
     *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1754
     *                               to <i>callback</i> instead of the value</span>
1755
     *                               </li>
1756
     *                               <li>
1757
     *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1758
     *                               arguments to <i>callback</i> instead of the value</span>
1759
     *                               </li>
1760
     *                               </ul>
1761
     *
1762
     * @return static
1763
     *                <p>(Immutable)</p>
1764
     *
1765
     * @psalm-param \Closure(T=,TKey=):bool|\Closure(T=):bool $closure
1766
     * @psalm-return static<TKey,T>
1767
     * @psalm-mutation-free
1768
     */
1769 12
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH)
1770
    {
1771 12
        if (!$closure) {
1772 1
            return $this->clean();
1773
        }
1774
1775 12
        return static::create(
1776 12
            \array_filter($this->getArray(), $closure, $flag),
1777 12
            $this->iteratorClass,
1778 12
            false
1779
        );
1780
    }
1781
1782
    /**
1783
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
1784
     * property within that.
1785
     *
1786
     * @param string          $property
1787
     * @param string|string[] $value
1788
     * @param string          $comparisonOp
1789
     *                                      <p>
1790
     *                                      'eq' (equals),<br />
1791
     *                                      'gt' (greater),<br />
1792
     *                                      'gte' || 'ge' (greater or equals),<br />
1793
     *                                      'lt' (less),<br />
1794
     *                                      'lte' || 'le' (less or equals),<br />
1795
     *                                      'ne' (not equals),<br />
1796
     *                                      'contains',<br />
1797
     *                                      'notContains',<br />
1798
     *                                      'newer' (via strtotime),<br />
1799
     *                                      'older' (via strtotime),<br />
1800
     *                                      </p>
1801
     *
1802
     * @return static
1803
     *                <p>(Immutable)</p>
1804
     *
1805
     * @psalm-return static<TKey,T>
1806
     * @psalm-mutation-free
1807
     */
1808 1
    public function filterBy(string $property, $value, string $comparisonOp = null): self
1809
    {
1810 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...
1811 1
            $comparisonOp = \is_array($value) === true ? 'contains' : 'eq';
1812
        }
1813
1814
        $ops = [
1815
            'eq' => static function ($item, $prop, $value): bool {
1816 1
                return $item[$prop] === $value;
1817 1
            },
1818
            'gt' => static function ($item, $prop, $value): bool {
1819
                return $item[$prop] > $value;
1820 1
            },
1821
            'ge' => static function ($item, $prop, $value): bool {
1822
                return $item[$prop] >= $value;
1823 1
            },
1824
            'gte' => static function ($item, $prop, $value): bool {
1825
                return $item[$prop] >= $value;
1826 1
            },
1827
            'lt' => static function ($item, $prop, $value): bool {
1828 1
                return $item[$prop] < $value;
1829 1
            },
1830
            'le' => static function ($item, $prop, $value): bool {
1831
                return $item[$prop] <= $value;
1832 1
            },
1833
            'lte' => static function ($item, $prop, $value): bool {
1834
                return $item[$prop] <= $value;
1835 1
            },
1836
            'ne' => static function ($item, $prop, $value): bool {
1837
                return $item[$prop] !== $value;
1838 1
            },
1839
            'contains' => static function ($item, $prop, $value): bool {
1840 1
                return \in_array($item[$prop], (array) $value, true);
1841 1
            },
1842
            'notContains' => static function ($item, $prop, $value): bool {
1843
                return !\in_array($item[$prop], (array) $value, true);
1844 1
            },
1845
            'newer' => static function ($item, $prop, $value): bool {
1846
                return \strtotime($item[$prop]) > \strtotime($value);
1847 1
            },
1848
            'older' => static function ($item, $prop, $value): bool {
1849
                return \strtotime($item[$prop]) < \strtotime($value);
1850 1
            },
1851
        ];
1852
1853 1
        $result = \array_values(
1854 1
            \array_filter(
1855 1
                $this->getArray(),
1856
                static function ($item) use (
1857 1
                    $property,
1858 1
                    $value,
1859 1
                    $ops,
1860 1
                    $comparisonOp
1861
                ) {
1862 1
                    $item = (array) $item;
1863 1
                    $itemArrayy = static::create($item);
1864 1
                    $item[$property] = $itemArrayy->get($property, []);
1865
1866 1
                    return $ops[$comparisonOp]($item, $property, $value);
1867 1
                }
1868
            )
1869
        );
1870
1871 1
        return static::create(
1872 1
            $result,
1873 1
            $this->iteratorClass,
1874 1
            false
1875
        );
1876
    }
1877
1878
    /**
1879
     * Find the first item in an array that passes the truth test,
1880
     *  otherwise return false
1881
     *
1882
     * @param \Closure $closure
1883
     *
1884
     * @return false|mixed
1885
     *                     <p>Return false if we did not find the value.</p>
1886
     */
1887 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...
1888
    {
1889 8
        foreach ($this->getGenerator() as $key => $value) {
1890 6
            if ($closure($value, $key)) {
1891 6
                return $value;
1892
            }
1893
        }
1894
1895 3
        return false;
1896
    }
1897
1898
    /**
1899
     * find by ...
1900
     *
1901
     * @param string          $property
1902
     * @param string|string[] $value
1903
     * @param string          $comparisonOp
1904
     *
1905
     * @return static
1906
     *                <p>(Immutable)</p>
1907
     *
1908
     * @psalm-return static<TKey,T>
1909
     * @psalm-mutation-free
1910
     */
1911 1
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
1912
    {
1913 1
        return $this->filterBy($property, $value, $comparisonOp);
1914
    }
1915
1916
    /**
1917
     * Get the first value from the current array.
1918
     *
1919
     * @return mixed
1920
     *               <p>Return null if there wasn't a element.</p>
1921
     */
1922 21
    public function first()
1923
    {
1924 21
        $key_first = $this->firstKey();
1925 21
        if ($key_first === null) {
1926 3
            return null;
1927
        }
1928
1929 18
        return $this->get($key_first);
1930
    }
1931
1932
    /**
1933
     * Get the first key from the current array.
1934
     *
1935
     * @return mixed
1936
     *               <p>Return null if there wasn't a element.</p>
1937
     */
1938 28
    public function firstKey()
1939
    {
1940 28
        $this->generatorToArray();
1941
1942 28
        return \array_key_first($this->array);
1943
    }
1944
1945
    /**
1946
     * Get the first value(s) from the current array.
1947
     * And will return an empty array if there was no first entry.
1948
     *
1949
     * @param int|null $number <p>How many values you will take?</p>
1950
     *
1951
     * @return static
1952
     *                <p>(Immutable)</p>
1953
     *
1954
     * @psalm-return static<TKey,T>
1955
     * @psalm-mutation-free
1956
     */
1957 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...
1958
    {
1959 37
        $arrayTmp = $this->getArray();
1960
1961 37
        if ($number === null) {
1962 14
            $array = (array) \array_shift($arrayTmp);
1963
        } else {
1964 23
            $number = (int) $number;
1965 23
            $array = \array_splice($arrayTmp, 0, $number);
1966
        }
1967
1968 37
        return static::create(
1969 37
            $array,
1970 37
            $this->iteratorClass,
1971 37
            false
1972
        );
1973
    }
1974
1975
    /**
1976
     * Get the first value(s) from the current array.
1977
     * And will return an empty array if there was no first entry.
1978
     *
1979
     * @param int|null $number <p>How many values you will take?</p>
1980
     *
1981
     * @return static
1982
     *                <p>(Immutable)</p>
1983
     *
1984
     * @psalm-return static<TKey,T>
1985
     * @psalm-mutation-free
1986
     */
1987 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...
1988
    {
1989 3
        $arrayTmp = $this->keys()->getArray();
1990
1991 3
        if ($number === null) {
1992
            $array = (array) \array_shift($arrayTmp);
1993
        } else {
1994 3
            $number = (int) $number;
1995 3
            $array = \array_splice($arrayTmp, 0, $number);
1996
        }
1997
1998 3
        return static::create(
1999 3
            $array,
2000 3
            $this->iteratorClass,
2001 3
            false
2002
        );
2003
    }
2004
2005
    /**
2006
     * Get and rmove the first value(s) from the current array.
2007
     * And will return an empty array if there was no first entry.
2008
     *
2009
     * @param int|null $number <p>How many values you will take?</p>
2010
     *
2011
     * @return $this
2012
     *               <p>(Mutable)</p>
2013
     *
2014
     * @psalm-return $this<TKey,T>
2015
     */
2016 34
    public function firstsMutable(int $number = null): self
2017
    {
2018 34
        $this->generatorToArray();
2019
2020 34
        if ($number === null) {
2021 19
            $this->array = (array) \array_shift($this->array);
2022
        } else {
2023 15
            $number = (int) $number;
2024 15
            $this->array = \array_splice($this->array, 0, $number);
2025
        }
2026
2027 34
        return $this;
2028
    }
2029
2030
    /**
2031
     * Exchanges all keys with their associated values in an array.
2032
     *
2033
     * @return static
2034
     *                <p>(Immutable)</p>
2035
     *
2036
     * @psalm-return static<TKey,T>
2037
     * @psalm-mutation-free
2038
     */
2039 1
    public function flip(): self
2040
    {
2041 1
        return static::create(
2042 1
            \array_flip($this->getArray()),
2043 1
            $this->iteratorClass,
2044 1
            false
2045
        );
2046
    }
2047
2048
    /**
2049
     * Get a value from an array (optional using dot-notation).
2050
     *
2051
     * @param mixed $key      <p>The key to look for.</p>
2052
     * @param mixed $fallback <p>Value to fallback to.</p>
2053
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
2054
     *                        class.</p>
2055
     *
2056
     * @return mixed|static
2057
     *
2058
     * @psalm-param array<mixed,mixed>|array<TKey,T> $array
2059
     */
2060 172
    public function get($key, $fallback = null, array $array = null)
2061
    {
2062 172
        if ($array !== null) {
2063 4
            $usedArray = $array;
2064
        } else {
2065 169
            $this->generatorToArray();
2066
2067 169
            $usedArray = $this->array;
2068
        }
2069
2070 172
        if ($key === null) {
2071 1
            return static::create(
2072 1
                $usedArray,
2073 1
                $this->iteratorClass,
2074 1
                false
2075
            );
2076
        }
2077
2078
        // php cast "bool"-index into "int"-index
2079 172
        if ((bool) $key === $key) {
2080 3
            $key = (int) $key;
2081
        }
2082
2083 172
        if (\array_key_exists($key, $usedArray) === true) {
2084 162
            if (\is_array($usedArray[$key]) === true) {
2085 11
                return static::create(
2086 11
                    $usedArray[$key],
2087 11
                    $this->iteratorClass,
2088 11
                    false
2089
                );
2090
            }
2091
2092 154
            return $usedArray[$key];
2093
        }
2094
2095
        // crawl through array, get key according to object or not
2096 24
        $usePath = false;
2097
        if (
2098 24
            $this->pathSeparator
2099
            &&
2100 24
            (string) $key === $key
2101
            &&
2102 24
            \strpos($key, $this->pathSeparator) !== false
2103
        ) {
2104 7
            $segments = \explode($this->pathSeparator, (string) $key);
2105 7
            if ($segments !== false) {
2106 7
                $usePath = true;
2107
2108 7
                foreach ($segments as $segment) {
2109
                    if (
2110
                        (
2111 7
                            \is_array($usedArray) === true
2112
                            ||
2113 7
                            $usedArray instanceof \ArrayAccess
2114
                        )
2115
                        &&
2116 7
                        isset($usedArray[$segment])
2117
                    ) {
2118 7
                        $usedArray = $usedArray[$segment];
2119
2120 7
                        continue;
2121
                    }
2122
2123
                    if (
2124 6
                        \is_object($usedArray) === true
2125
                        &&
2126 6
                        \property_exists($usedArray, $segment)
2127
                    ) {
2128 1
                        $usedArray = $usedArray->{$segment};
2129
2130 1
                        continue;
2131
                    }
2132
2133 5
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
2134
                }
2135
            }
2136
        }
2137
2138 24
        if (!$usePath && !isset($usedArray[$key])) {
2139 17
            return $fallback instanceof \Closure ? $fallback() : $fallback;
2140
        }
2141
2142 7
        if (\is_array($usedArray) === true) {
2143 1
            return static::create(
2144 1
                $usedArray,
2145 1
                $this->iteratorClass,
2146 1
                false
2147
            );
2148
        }
2149
2150 7
        return $usedArray;
2151
    }
2152
2153
    /**
2154
     * alias: for "Arrayy->getArray()"
2155
     *
2156
     * @return array
2157
     *
2158
     * @see          Arrayy::getArray()
2159
     *
2160
     * @psalm-return array<mixed,mixed>|array<TKey,T>
2161
     */
2162 1
    public function getAll(): array
2163
    {
2164 1
        return $this->getArray();
2165
    }
2166
2167
    /**
2168
     * Get the current array from the "Arrayy"-object.
2169
     *
2170
     * @param bool $convertAllArrayyElements
2171
     *
2172
     * @return array
2173
     *
2174
     * @psalm-return array<mixed,mixed>|array<TKey,T>
2175
     */
2176 859
    public function getArray($convertAllArrayyElements = false): array
2177
    {
2178
        // init
2179 859
        $array = [];
2180
2181 859
        if ($convertAllArrayyElements) {
2182 1
            foreach ($this->getGenerator() as $key => $value) {
2183 1
                if ($value instanceof self) {
2184 1
                    $value = $value->getArray(true);
2185
                }
2186
2187 1
                $array[$key] = $value;
2188
            }
2189
        } else {
2190 859
            foreach ($this->getGenerator() as $key => $value) {
2191 752
                $array[$key] = $value;
2192
            }
2193
        }
2194
2195 859
        return $array;
2196
    }
2197
2198
    /**
2199
     * Returns the values from a single column of the input array, identified by
2200
     * the $columnKey, can be used to extract data-columns from multi-arrays.
2201
     *
2202
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
2203
     * array by the values from the $indexKey column in the input array.
2204
     *
2205
     * @param mixed $columnKey
2206
     * @param mixed $indexKey
2207
     *
2208
     * @return static
2209
     *                <p>(Immutable)</p>
2210
     *
2211
     * @psalm-return static<TKey,T>
2212
     * @psalm-mutation-free
2213
     */
2214 1
    public function getColumn($columnKey = null, $indexKey = null): self
2215
    {
2216 1
        return static::create(
2217 1
            \array_column($this->getArray(), $columnKey, $indexKey),
2218 1
            $this->iteratorClass,
2219 1
            false
2220
        );
2221
    }
2222
2223
    /**
2224
     * Get the current array from the "Arrayy"-object as generator.
2225
     *
2226
     * @return \Generator
2227
     *
2228
     * @psalm-return \Generator<mixed,T>|\Generator<TKey,T>
2229
     */
2230 942
    public function getGenerator(): \Generator
2231
    {
2232 942
        if ($this->generator instanceof ArrayyRewindableGenerator) {
2233 40
            yield from $this->generator;
2234
        }
2235
2236 942
        yield from $this->array;
2237 898
    }
2238
2239
    /**
2240
     * alias: for "Arrayy->keys()"
2241
     *
2242
     * @return static
2243
     *                <p>(Immutable)</p>
2244
     *
2245
     * @see          Arrayy::keys()
2246
     *
2247
     * @psalm-return static<TKey,T>
2248
     * @psalm-mutation-free
2249
     */
2250 2
    public function getKeys()
2251
    {
2252 2
        return $this->keys();
2253
    }
2254
2255
    /**
2256
     * Get the current array from the "Arrayy"-object as object.
2257
     *
2258
     * @return \stdClass
2259
     */
2260 4
    public function getObject(): \stdClass
2261
    {
2262 4
        return self::arrayToObject($this->getArray());
2263
    }
2264
2265
    /**
2266
     * alias: for "Arrayy->randomImmutable()"
2267
     *
2268
     * @return static
2269
     *                <p>(Immutable)</p>
2270
     *
2271
     * @see          Arrayy::randomImmutable()
2272
     *
2273
     * @psalm-return static<TKey,T>
2274
     * @psalm-mutation-free
2275
     */
2276 4
    public function getRandom(): self
2277
    {
2278 4
        return $this->randomImmutable();
2279
    }
2280
2281
    /**
2282
     * alias: for "Arrayy->randomKey()"
2283
     *
2284
     * @return mixed
2285
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2286
     *
2287
     * @see Arrayy::randomKey()
2288
     */
2289 3
    public function getRandomKey()
2290
    {
2291 3
        return $this->randomKey();
2292
    }
2293
2294
    /**
2295
     * alias: for "Arrayy->randomKeys()"
2296
     *
2297
     * @param int $number
2298
     *
2299
     * @return static
2300
     *                <p>(Immutable)</p>
2301
     *
2302
     * @see          Arrayy::randomKeys()
2303
     *
2304
     * @psalm-return static<TKey,T>
2305
     * @psalm-mutation-free
2306
     */
2307 8
    public function getRandomKeys(int $number): self
2308
    {
2309 8
        return $this->randomKeys($number);
2310
    }
2311
2312
    /**
2313
     * alias: for "Arrayy->randomValue()"
2314
     *
2315
     * @return mixed
2316
     *               <p>Get a random value or null if there wasn't a value.</p>
2317
     *
2318
     * @see Arrayy::randomValue()
2319
     */
2320 3
    public function getRandomValue()
2321
    {
2322 3
        return $this->randomValue();
2323
    }
2324
2325
    /**
2326
     * alias: for "Arrayy->randomValues()"
2327
     *
2328
     * @param int $number
2329
     *
2330
     * @return static
2331
     *                <p>(Immutable)</p>
2332
     *
2333
     * @see          Arrayy::randomValues()
2334
     *
2335
     * @psalm-return static<TKey,T>
2336
     * @psalm-mutation-free
2337
     */
2338 6
    public function getRandomValues(int $number): self
2339
    {
2340 6
        return $this->randomValues($number);
2341
    }
2342
2343
    /**
2344
     * Gets all values.
2345
     *
2346
     * @return static
2347
     *                <p>The values of all elements in this array, in the order they
2348
     *                appear in the array.</p>
2349
     *
2350
     * @psalm-return static<TKey,T>
2351
     */
2352 4
    public function getValues()
2353
    {
2354 4
        $this->generatorToArray();
2355
2356 4
        return static::create(
2357 4
            \array_values($this->array),
2358 4
            $this->iteratorClass,
2359 4
            false
2360
        );
2361
    }
2362
2363
    /**
2364
     * Gets all values via Generator.
2365
     *
2366
     * @return \Generator
2367
     *                    <p>The values of all elements in this array, in the order they
2368
     *                    appear in the array as Generator.</p>
2369
     *
2370
     * @psalm-return \Generator<TKey,T>
2371
     */
2372 4
    public function getValuesYield(): \Generator
2373
    {
2374 4
        yield from $this->getGenerator();
2375 4
    }
2376
2377
    /**
2378
     * Group values from a array according to the results of a closure.
2379
     *
2380
     * @param callable|string $grouper  <p>A callable function name.</p>
2381
     * @param bool            $saveKeys
2382
     *
2383
     * @return static
2384
     *                <p>(Immutable)</p>
2385
     *
2386
     * @psalm-return static<TKey,T>
2387
     * @psalm-mutation-free
2388
     */
2389 4
    public function group($grouper, bool $saveKeys = false): self
2390
    {
2391
        // init
2392 4
        $result = [];
2393
2394
        // Iterate over values, group by property/results from closure.
2395 4
        foreach ($this->getGenerator() as $key => $value) {
2396 4
            if (\is_callable($grouper) === true) {
2397 3
                $groupKey = $grouper($value, $key);
2398
            } else {
2399 1
                $groupKey = $this->get($grouper);
2400
            }
2401
2402 4
            $newValue = $this->get($groupKey, null, $result);
2403
2404 4
            if ($groupKey instanceof self) {
2405
                $groupKey = $groupKey->getArray();
2406
            }
2407
2408 4
            if ($newValue instanceof self) {
2409 4
                $newValue = $newValue->getArray();
2410
            }
2411
2412
            // Add to results.
2413 4
            if ($groupKey !== null) {
2414 3
                if ($saveKeys) {
2415 2
                    $result[$groupKey] = $newValue;
2416 2
                    $result[$groupKey][$key] = $value;
2417
                } else {
2418 1
                    $result[$groupKey] = $newValue;
2419 4
                    $result[$groupKey][] = $value;
2420
                }
2421
            }
2422
        }
2423
2424 4
        return static::create(
2425 4
            $result,
2426 4
            $this->iteratorClass,
2427 4
            false
2428
        );
2429
    }
2430
2431
    /**
2432
     * Check if an array has a given key.
2433
     *
2434
     * @param mixed $key
2435
     *
2436
     * @return bool
2437
     */
2438 23
    public function has($key): bool
2439
    {
2440 23
        static $UN_FOUND = null;
2441
2442 23
        if ($UN_FOUND === null) {
2443
            // Generate unique string to use as marker.
2444 1
            $UN_FOUND = \uniqid('arrayy', true);
2445
        }
2446
2447 23
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2448
    }
2449
2450
    /**
2451
     * Check if an array has a given value.
2452
     *
2453
     * INFO: if you need to search recursive please use ```contains()```
2454
     *
2455
     * @param mixed $value
2456
     *
2457
     * @return bool
2458
     */
2459 1
    public function hasValue($value): bool
2460
    {
2461 1
        return $this->contains($value);
2462
    }
2463
2464
    /**
2465
     * Implodes the values of this array.
2466
     *
2467
     * @param string $glue
2468
     *
2469
     * @return string
2470
     */
2471 28
    public function implode(string $glue = ''): string
2472
    {
2473 28
        return $this->implode_recursive($glue, $this->getArray(), false);
2474
    }
2475
2476
    /**
2477
     * Implodes the keys of this array.
2478
     *
2479
     * @param string $glue
2480
     *
2481
     * @return string
2482
     */
2483 8
    public function implodeKeys(string $glue = ''): string
2484
    {
2485 8
        return $this->implode_recursive($glue, $this->getArray(), true);
2486
    }
2487
2488
    /**
2489
     * Given a list and an iterate-function that returns
2490
     * a key for each element in the list (or a property name),
2491
     * returns an object with an index of each item.
2492
     *
2493
     * @param mixed $key
2494
     *
2495
     * @return static
2496
     *                <p>(Immutable)</p>
2497
     *
2498
     * @psalm-return static<TKey,T>
2499
     * @psalm-mutation-free
2500
     */
2501 4
    public function indexBy($key): self
2502
    {
2503
        // init
2504 4
        $results = [];
2505
2506 4
        foreach ($this->getGenerator() as $a) {
2507 4
            if (\array_key_exists($key, $a) === true) {
2508 4
                $results[$a[$key]] = $a;
2509
            }
2510
        }
2511
2512 4
        return static::create(
2513 4
            $results,
2514 4
            $this->iteratorClass,
2515 4
            false
2516
        );
2517
    }
2518
2519
    /**
2520
     * alias: for "Arrayy->searchIndex()"
2521
     *
2522
     * @param mixed $value <p>The value to search for.</p>
2523
     *
2524
     * @return false|mixed
2525
     *
2526
     * @see Arrayy::searchIndex()
2527
     */
2528 4
    public function indexOf($value)
2529
    {
2530 4
        return $this->searchIndex($value);
2531
    }
2532
2533
    /**
2534
     * Get everything but the last..$to items.
2535
     *
2536
     * @param int $to
2537
     *
2538
     * @return static
2539
     *                <p>(Immutable)</p>
2540
     *
2541
     * @psalm-return static<TKey,T>
2542
     * @psalm-mutation-free
2543
     */
2544 12
    public function initial(int $to = 1): self
2545
    {
2546 12
        return $this->firstsImmutable(\count($this->getArray(), \COUNT_NORMAL) - $to);
2547
    }
2548
2549
    /**
2550
     * Return an array with all elements found in input array.
2551
     *
2552
     * @param array $search
2553
     * @param bool  $keepKeys
2554
     *
2555
     * @return static
2556
     *                <p>(Immutable)</p>
2557
     *
2558
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $search
2559
     * @psalm-return static<TKey,T>
2560
     * @psalm-mutation-free
2561
     */
2562 4
    public function intersection(array $search, bool $keepKeys = false): self
2563
    {
2564 4
        if ($keepKeys) {
2565 1
            return static::create(
2566 1
                \array_uintersect(
2567 1
                    $this->getArray(),
2568 1
                    $search,
2569
                    static function ($a, $b) {
2570 1
                        return $a === $b ? 0 : -1;
2571 1
                    }
2572
                ),
2573 1
                $this->iteratorClass,
2574 1
                false
2575
            );
2576
        }
2577
2578 3
        return static::create(
2579 3
            \array_values(\array_intersect($this->getArray(), $search)),
2580 3
            $this->iteratorClass,
2581 3
            false
2582
        );
2583
    }
2584
2585
    /**
2586
     * Return an array with all elements found in input array.
2587
     *
2588
     * @param array ...$array
2589
     *
2590
     * @return static
2591
     *                <p>(Immutable)</p>
2592
     *
2593
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$array
2594
     * @psalm-return static<TKey,T>
2595
     * @psalm-mutation-free
2596
     */
2597 1
    public function intersectionMulti(...$array): self
2598
    {
2599 1
        return static::create(
2600 1
            \array_values(\array_intersect($this->getArray(), ...$array)),
2601 1
            $this->iteratorClass,
2602 1
            false
2603
        );
2604
    }
2605
2606
    /**
2607
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
2608
     *
2609
     * @param array $search
2610
     *
2611
     * @return bool
2612
     *
2613
     * @psalm-param array<mixed,mixed>|array<TKey,T> $search
2614
     */
2615 1
    public function intersects(array $search): bool
2616
    {
2617 1
        return $this->intersection($search)->count() > 0;
2618
    }
2619
2620
    /**
2621
     * Invoke a function on all of an array's values.
2622
     *
2623
     * @param callable $callable
2624
     * @param mixed    $arguments
2625
     *
2626
     * @return static
2627
     *                <p>(Immutable)</p>
2628
     *
2629
     * @psalm-param  callable(T=,mixed):mixed $callable
2630
     * @psalm-return static<TKey,T>
2631
     * @psalm-mutation-free
2632
     */
2633 1
    public function invoke($callable, $arguments = []): self
2634
    {
2635
        // If one argument given for each iteration, create an array for it.
2636 1
        if (\is_array($arguments) === false) {
2637 1
            $arguments = \array_fill(
2638 1
                0,
2639 1
                $this->count(),
2640 1
                $arguments
2641
            );
2642
        }
2643
2644
        // If the callable has arguments, pass them.
2645 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...
2646 1
            $array = \array_map($callable, $this->getArray(), $arguments);
2647
        } else {
2648 1
            $array = $this->map($callable);
2649
        }
2650
2651 1
        return static::create(
2652 1
            $array,
2653 1
            $this->iteratorClass,
2654 1
            false
2655
        );
2656
    }
2657
2658
    /**
2659
     * Check whether array is associative or not.
2660
     *
2661
     * @param bool $recursive
2662
     *
2663
     * @return bool
2664
     *              <p>Returns true if associative, false otherwise.</p>
2665
     */
2666 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...
2667
    {
2668 15
        if ($this->isEmpty()) {
2669 3
            return false;
2670
        }
2671
2672 13
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2673 13
            if ((string) $key !== $key) {
2674 13
                return false;
2675
            }
2676
        }
2677
2678 3
        return true;
2679
    }
2680
2681
    /**
2682
     * Check if a given key or keys are empty.
2683
     *
2684
     * @param int|int[]|string|string[]|null $keys
2685
     *
2686
     * @return bool
2687
     *              <p>Returns true if empty, false otherwise.</p>
2688
     */
2689 38
    public function isEmpty($keys = null): bool
2690
    {
2691 38
        if ($this->generator) {
2692
            return $this->getArray() === [];
2693
        }
2694
2695 38
        if ($keys === null) {
2696 38
            return $this->array === [];
2697
        }
2698
2699
        foreach ((array) $keys as $key) {
2700
            if (!empty($this->get($key))) {
2701
                return false;
2702
            }
2703
        }
2704
2705
        return true;
2706
    }
2707
2708
    /**
2709
     * Check if the current array is equal to the given "$array" or not.
2710
     *
2711
     * @param array $array
2712
     *
2713
     * @return bool
2714
     *
2715
     * @psalm-param array<mixed,mixed> $array
2716
     */
2717 1
    public function isEqual(array $array): bool
2718
    {
2719 1
        return $this->getArray() === $array;
2720
    }
2721
2722
    /**
2723
     * Check if the current array is a multi-array.
2724
     *
2725
     * @return bool
2726
     */
2727 22
    public function isMultiArray(): bool
2728
    {
2729
        return !(
2730 22
            \count($this->getArray(), \COUNT_NORMAL)
2731
            ===
2732 22
            \count($this->getArray(), \COUNT_RECURSIVE)
2733
        );
2734
    }
2735
2736
    /**
2737
     * Check whether array is numeric or not.
2738
     *
2739
     * @return bool
2740
     *              <p>Returns true if numeric, false otherwise.</p>
2741
     */
2742 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...
2743
    {
2744 5
        if ($this->isEmpty()) {
2745 2
            return false;
2746
        }
2747
2748 4
        foreach ($this->keys()->getGenerator() as $key) {
2749 4
            if ((int) $key !== $key) {
2750 4
                return false;
2751
            }
2752
        }
2753
2754 2
        return true;
2755
    }
2756
2757
    /**
2758
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2759
     *
2760
     * @param bool $recursive
2761
     *
2762
     * @return bool
2763
     */
2764 9
    public function isSequential(bool $recursive = false): bool
2765
    {
2766
2767
        // recursive
2768
2769 9
        if ($recursive === true) {
2770
            return $this->array_keys_recursive($this->getArray())
2771
                   ===
2772
                   \range(0, \count($this->getArray(), \COUNT_RECURSIVE) - 1);
2773
        }
2774
2775
        // non recursive
2776
2777 9
        return \array_keys($this->getArray())
2778
               ===
2779 9
               \range(0, \count($this->getArray(), \COUNT_NORMAL) - 1);
2780
    }
2781
2782
    /**
2783
     * @return array
2784
     *
2785
     * @psalm-return array<TKey,T>
2786
     */
2787
    public function jsonSerialize(): array
2788
    {
2789
        return $this->getArray();
2790
    }
2791
2792
    /**
2793
     * Gets the key/index of the element at the current internal iterator position.
2794
     *
2795
     * @return int|string|null
2796
     */
2797
    public function key()
2798
    {
2799
        return \key($this->array);
2800
    }
2801
2802
    /**
2803
     * Checks if the given key exists in the provided array.
2804
     *
2805
     * INFO: This method only use "array_key_exists()" if you want to use "dot"-notation,
2806
     *       then you need to use "Arrayy->offsetExists()".
2807
     *
2808
     * @param int|string $key the key to look for
2809
     *
2810
     * @return bool
2811
     */
2812 127
    public function keyExists($key): bool
2813
    {
2814 127
        return \array_key_exists($key, $this->array);
2815
    }
2816
2817
    /**
2818
     * Get all keys from the current array.
2819
     *
2820
     * @param bool       $recursive     [optional] <p>
2821
     *                                  Get all keys, also from all sub-arrays from an multi-dimensional array.
2822
     *                                  </p>
2823
     * @param mixed|null $search_values [optional] <p>
2824
     *                                  If specified, then only keys containing these values are returned.
2825
     *                                  </p>
2826
     * @param bool       $strict        [optional] <p>
2827
     *                                  Determines if strict comparison (===) should be used during the search.
2828
     *                                  </p>
2829
     *
2830
     * @return static
2831
     *                <p>(Immutable) An array of all the keys in input.</p>
2832
     *
2833
     * @psalm-return static<TKey,T>
2834
     * @psalm-mutation-free
2835
     */
2836 29
    public function keys(
2837
        bool $recursive = false,
2838
        $search_values = null,
2839
        bool $strict = true
2840
    ): self {
2841
2842
        // recursive
2843
2844 29
        if ($recursive === true) {
2845 4
            $array = $this->array_keys_recursive(
2846 4
                null,
2847 4
                $search_values,
2848 4
                $strict
2849
            );
2850
2851 4
            return static::create(
2852 4
                $array,
2853 4
                $this->iteratorClass,
2854 4
                false
2855
            );
2856
        }
2857
2858
        // non recursive
2859
2860 28
        if ($search_values === null) {
2861
            $arrayFunction = function (): \Generator {
2862 28
                foreach ($this->getGenerator() as $key => $value) {
2863 26
                    yield $key;
2864
                }
2865 28
            };
2866
        } else {
2867
            $arrayFunction = function () use ($search_values, $strict): \Generator {
2868 1
                $is_array_tmp = \is_array($search_values);
2869
2870 1
                foreach ($this->getGenerator() as $key => $value) {
2871 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...
2872
                        (
2873 1
                            $is_array_tmp === false
2874
                            &&
2875 1
                            $strict === true
2876
                            &&
2877 1
                            $search_values === $value
2878
                        )
2879
                        ||
2880
                        (
2881 1
                            $is_array_tmp === false
2882
                            &&
2883 1
                            $strict === false
2884
                            &&
2885 1
                            $search_values == $value
2886
                        )
2887
                        ||
2888
                        (
2889 1
                            $is_array_tmp === true
2890
                            &&
2891 1
                            \in_array($value, $search_values, $strict)
2892
                        )
2893
                    ) {
2894 1
                        yield $key;
2895
                    }
2896
                }
2897 1
            };
2898
        }
2899
2900 28
        return static::create(
2901 28
            $arrayFunction,
2902 28
            $this->iteratorClass,
2903 28
            false
2904
        );
2905
    }
2906
2907
    /**
2908
     * Sort an array by key in reverse order.
2909
     *
2910
     * @param int $sort_flags [optional] <p>
2911
     *                        You may modify the behavior of the sort using the optional
2912
     *                        parameter sort_flags, for details
2913
     *                        see sort.
2914
     *                        </p>
2915
     *
2916
     * @return $this
2917
     *               <p>(Mutable) Return this Arrayy object.</p>
2918
     *
2919
     * @psalm-return $this<TKey,T>
2920
     */
2921 4
    public function krsort(int $sort_flags = 0): self
2922
    {
2923 4
        $this->generatorToArray();
2924
2925 4
        \krsort($this->array, $sort_flags);
2926
2927 4
        return $this;
2928
    }
2929
2930
    /**
2931
     * Get the last value from the current array.
2932
     *
2933
     * @return mixed
2934
     *               <p>Return null if there wasn't a element.</p>
2935
     */
2936 17
    public function last()
2937
    {
2938 17
        $key_last = $this->lastKey();
2939 17
        if ($key_last === null) {
2940 2
            return null;
2941
        }
2942
2943 15
        return $this->get($key_last);
2944
    }
2945
2946
    /**
2947
     * Get the last key from the current array.
2948
     *
2949
     * @return mixed
2950
     *               <p>Return null if there wasn't a element.</p>
2951
     */
2952 21
    public function lastKey()
2953
    {
2954 21
        $this->generatorToArray();
2955
2956 21
        return \array_key_last($this->array);
2957
    }
2958
2959
    /**
2960
     * Get the last value(s) from the current array.
2961
     *
2962
     * @param int|null $number
2963
     *
2964
     * @return static
2965
     *                <p>(Immutable)</p>
2966
     *
2967
     * @psalm-return static<TKey,T>
2968
     * @psalm-mutation-free
2969
     */
2970 13
    public function lastsImmutable(int $number = null): self
2971
    {
2972 13
        if ($this->isEmpty()) {
2973 1
            return static::create(
2974 1
                [],
2975 1
                $this->iteratorClass,
2976 1
                false
2977
            );
2978
        }
2979
2980 12
        if ($number === null) {
2981 8
            $poppedValue = $this->last();
2982
2983 8
            if ($poppedValue === null) {
2984 1
                $poppedValue = [$poppedValue];
2985
            } else {
2986 7
                $poppedValue = (array) $poppedValue;
2987
            }
2988
2989 8
            $arrayy = static::create(
2990 8
                $poppedValue,
2991 8
                $this->iteratorClass,
2992 8
                false
2993
            );
2994
        } else {
2995 4
            $number = (int) $number;
2996 4
            $arrayy = $this->rest(-$number);
2997
        }
2998
2999 12
        return $arrayy;
3000
    }
3001
3002
    /**
3003
     * Get the last value(s) from the current array.
3004
     *
3005
     * @param int|null $number
3006
     *
3007
     * @return $this
3008
     *               <p>(Mutable)</p>
3009
     *
3010
     * @psalm-return $this<TKey,T>
3011
     */
3012 13
    public function lastsMutable(int $number = null): self
3013
    {
3014 13
        if ($this->isEmpty()) {
3015 1
            return $this;
3016
        }
3017
3018 12
        if ($number === null) {
3019 8
            $poppedValue = $this->last();
3020
3021 8
            if ($poppedValue === null) {
3022 1
                $poppedValue = [$poppedValue];
3023
            } else {
3024 7
                $poppedValue = (array) $poppedValue;
3025
            }
3026
3027 8
            $this->array = static::create(
3028 8
                $poppedValue,
3029 8
                $this->iteratorClass,
3030 8
                false
3031 8
            )->getArray();
3032
        } else {
3033 4
            $number = (int) $number;
3034 4
            $this->array = $this->rest(-$number)->getArray();
3035
        }
3036
3037 12
        $this->generator = null;
3038
3039 12
        return $this;
3040
    }
3041
3042
    /**
3043
     * Count the values from the current array.
3044
     *
3045
     * alias: for "Arrayy->count()"
3046
     *
3047
     * @param int $mode
3048
     *
3049
     * @return int
3050
     *
3051
     * @see Arrayy::count()
3052
     */
3053 20
    public function length(int $mode = \COUNT_NORMAL): int
3054
    {
3055 20
        return $this->count($mode);
3056
    }
3057
3058
    /**
3059
     * Apply the given function to the every element of the array,
3060
     * collecting the results.
3061
     *
3062
     * @param callable $callable
3063
     * @param bool     $useKeyAsSecondParameter
3064
     * @param mixed    ...$arguments
3065
     *
3066
     * @return static
3067
     *                <p>(Immutable) Arrayy object with modified elements.</p>
3068
     *
3069
     * @psalm-param  callable(T=,TKey=,mixed):mixed|callable(T=,mixed):mixed $callable
3070
     * @psalm-return static<TKey,T>
3071
     * @psalm-mutation-free
3072
     */
3073 5
    public function map(callable $callable, bool $useKeyAsSecondParameter = false, ...$arguments)
3074
    {
3075 5
        $useArguments = \func_num_args() > 2;
3076
3077 5
        return static::create(
3078
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
3079 5
                foreach ($this->getGenerator() as $key => $value) {
3080 4
                    if ($useArguments) {
3081 3
                        if ($useKeyAsSecondParameter) {
3082
                            yield $key => $callable($value, $key, ...$arguments);
3083
                        } else {
3084 3
                            yield $key => $callable($value, ...$arguments);
3085
                        }
3086
                    } else {
3087
                        /** @noinspection NestedPositiveIfStatementsInspection */
3088 4
                        if ($useKeyAsSecondParameter) {
3089
                            yield $key => $callable($value, $key);
3090
                        } else {
3091 4
                            yield $key => $callable($value);
3092
                        }
3093
                    }
3094
                }
3095 5
            },
3096 5
            $this->iteratorClass,
3097 5
            false
3098
        );
3099
    }
3100
3101
    /**
3102
     * Check if all items in current array match a truth test.
3103
     *
3104
     * @param \Closure $closure
3105
     *
3106
     * @return bool
3107
     */
3108 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...
3109
    {
3110 15
        if ($this->count() === 0) {
3111 2
            return false;
3112
        }
3113
3114 13
        foreach ($this->getGenerator() as $key => $value) {
3115 13
            $value = $closure($value, $key);
3116
3117 13
            if ($value === false) {
3118 13
                return false;
3119
            }
3120
        }
3121
3122 7
        return true;
3123
    }
3124
3125
    /**
3126
     * Check if any item in the current array matches a truth test.
3127
     *
3128
     * @param \Closure $closure
3129
     *
3130
     * @return bool
3131
     */
3132 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...
3133
    {
3134 14
        if ($this->count() === 0) {
3135 2
            return false;
3136
        }
3137
3138 12
        foreach ($this->getGenerator() as $key => $value) {
3139 12
            $value = $closure($value, $key);
3140
3141 12
            if ($value === true) {
3142 12
                return true;
3143
            }
3144
        }
3145
3146 4
        return false;
3147
    }
3148
3149
    /**
3150
     * Get the max value from an array.
3151
     *
3152
     * @return mixed
3153
     */
3154 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...
3155
    {
3156 10
        if ($this->count() === 0) {
3157 1
            return false;
3158
        }
3159
3160 9
        $max = false;
3161 9
        foreach ($this->getGenerator() as $value) {
3162
            if (
3163 9
                $max === false
3164
                ||
3165 9
                $value > $max
3166
            ) {
3167 9
                $max = $value;
3168
            }
3169
        }
3170
3171 9
        return $max;
3172
    }
3173
3174
    /**
3175
     * Merge the new $array into the current array.
3176
     *
3177
     * - keep key,value from the current array, also if the index is in the new $array
3178
     *
3179
     * @param array $array
3180
     * @param bool  $recursive
3181
     *
3182
     * @return static
3183
     *                <p>(Immutable)</p>
3184
     *
3185
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3186
     * @psalm-return static<TKey,T>
3187
     * @psalm-mutation-free
3188
     */
3189 25 View Code Duplication
    public function mergeAppendKeepIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3190
    {
3191 25
        if ($recursive === true) {
3192 4
            $result = \array_replace_recursive($this->getArray(), $array);
3193
        } else {
3194 21
            $result = \array_replace($this->getArray(), $array);
3195
        }
3196
3197 25
        return static::create(
3198 25
            $result,
3199 25
            $this->iteratorClass,
3200 25
            false
3201
        );
3202
    }
3203
3204
    /**
3205
     * Merge the new $array into the current array.
3206
     *
3207
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
3208
     * - create new indexes
3209
     *
3210
     * @param array $array
3211
     * @param bool  $recursive
3212
     *
3213
     * @return static
3214
     *                <p>(Immutable)</p>
3215
     *
3216
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3217
     * @psalm-return static<TKey,T>
3218
     * @psalm-mutation-free
3219
     */
3220 16 View Code Duplication
    public function mergeAppendNewIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3221
    {
3222 16
        if ($recursive === true) {
3223 4
            $result = \array_merge_recursive($this->getArray(), $array);
3224
        } else {
3225 12
            $result = \array_merge($this->getArray(), $array);
3226
        }
3227
3228 16
        return static::create(
3229 16
            $result,
3230 16
            $this->iteratorClass,
3231 16
            false
3232
        );
3233
    }
3234
3235
    /**
3236
     * Merge the the current array into the $array.
3237
     *
3238
     * - use key,value from the new $array, also if the index is in the current array
3239
     *
3240
     * @param array $array
3241
     * @param bool  $recursive
3242
     *
3243
     * @return static
3244
     *                <p>(Immutable)</p>
3245
     *
3246
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3247
     * @psalm-return static<TKey,T>
3248
     * @psalm-mutation-free
3249
     */
3250 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...
3251
    {
3252 16
        if ($recursive === true) {
3253 4
            $result = \array_replace_recursive($array, $this->getArray());
3254
        } else {
3255 12
            $result = \array_replace($array, $this->getArray());
3256
        }
3257
3258 16
        return static::create(
3259 16
            $result,
3260 16
            $this->iteratorClass,
3261 16
            false
3262
        );
3263
    }
3264
3265
    /**
3266
     * Merge the current array into the new $array.
3267
     *
3268
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
3269
     * - create new indexes
3270
     *
3271
     * @param array $array
3272
     * @param bool  $recursive
3273
     *
3274
     * @return static
3275
     *                <p>(Immutable)</p>
3276
     *
3277
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3278
     * @psalm-return static<TKey,T>
3279
     * @psalm-mutation-free
3280
     */
3281 17 View Code Duplication
    public function mergePrependNewIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3282
    {
3283 17
        if ($recursive === true) {
3284 4
            $result = \array_merge_recursive($array, $this->getArray());
3285
        } else {
3286 13
            $result = \array_merge($array, $this->getArray());
3287
        }
3288
3289 17
        return static::create(
3290 17
            $result,
3291 17
            $this->iteratorClass,
3292 17
            false
3293
        );
3294
    }
3295
3296
    /**
3297
     * @return ArrayyMeta|static
3298
     */
3299 15
    public static function meta()
3300
    {
3301 15
        return (new ArrayyMeta())->getMetaObject(static::class);
3302
    }
3303
3304
    /**
3305
     * Get the min value from an array.
3306
     *
3307
     * @return mixed
3308
     */
3309 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...
3310
    {
3311 10
        if ($this->count() === 0) {
3312 1
            return false;
3313
        }
3314
3315 9
        $min = false;
3316 9
        foreach ($this->getGenerator() as $value) {
3317
            if (
3318 9
                $min === false
3319
                ||
3320 9
                $value < $min
3321
            ) {
3322 9
                $min = $value;
3323
            }
3324
        }
3325
3326 9
        return $min;
3327
    }
3328
3329
    /**
3330
     * Get the most used value from the array.
3331
     *
3332
     * @return mixed
3333
     *               <p>Return null if there wasn't a element.</p>
3334
     */
3335 3
    public function mostUsedValue()
3336
    {
3337 3
        return $this->countValues()->arsort()->firstKey();
3338
    }
3339
3340
    /**
3341
     * Get the most used value from the array.
3342
     *
3343
     * @param int|null $number <p>How many values you will take?</p>
3344
     *
3345
     * @return static
3346
     *                <p>(Immutable)</p>
3347
     *
3348
     * @psalm-return static<TKey,T>
3349
     * @psalm-mutation-free
3350
     */
3351 3
    public function mostUsedValues(int $number = null): self
3352
    {
3353 3
        return $this->countValues()->arsort()->firstsKeys($number);
3354
    }
3355
3356
    /**
3357
     * Move an array element to a new index.
3358
     *
3359
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
3360
     *
3361
     * @param int|string $from
3362
     * @param int        $to
3363
     *
3364
     * @return static
3365
     *                <p>(Immutable)</p>
3366
     *
3367
     * @psalm-return static<TKey,T>
3368
     * @psalm-mutation-free
3369
     */
3370 1
    public function moveElement($from, $to): self
3371
    {
3372 1
        $array = $this->getArray();
3373
3374 1
        if ((int) $from === $from) {
3375 1
            $tmp = \array_splice($array, $from, 1);
3376 1
            \array_splice($array, (int) $to, 0, $tmp);
3377 1
            $output = $array;
3378 1
        } elseif ((string) $from === $from) {
3379 1
            $indexToMove = \array_search($from, \array_keys($array), true);
3380 1
            $itemToMove = $array[$from];
3381 1
            if ($indexToMove !== false) {
3382 1
                \array_splice($array, $indexToMove, 1);
3383
            }
3384 1
            $i = 0;
3385 1
            $output = [];
3386 1
            foreach ($array as $key => $item) {
3387 1
                if ($i === $to) {
3388 1
                    $output[$from] = $itemToMove;
3389
                }
3390 1
                $output[$key] = $item;
3391 1
                ++$i;
3392
            }
3393
        } else {
3394
            $output = [];
3395
        }
3396
3397 1
        return static::create(
3398 1
            $output,
3399 1
            $this->iteratorClass,
3400 1
            false
3401
        );
3402
    }
3403
3404
    /**
3405
     * Move an array element to the first place.
3406
     *
3407
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3408
     *       loss the keys of an indexed array.
3409
     *
3410
     * @param int|string $key
3411
     *
3412
     * @return static
3413
     *                <p>(Immutable)</p>
3414
     *
3415
     * @psalm-return static<TKey,T>
3416
     * @psalm-mutation-free
3417
     */
3418 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...
3419
    {
3420 1
        $array = $this->getArray();
3421
3422 1
        if ($this->offsetExists($key)) {
3423 1
            $tmpValue = $this->get($key);
3424 1
            unset($array[$key]);
3425 1
            $array = [$key => $tmpValue] + $array;
3426
        }
3427
3428 1
        return static::create(
3429 1
            $array,
3430 1
            $this->iteratorClass,
3431 1
            false
3432
        );
3433
    }
3434
3435
    /**
3436
     * Move an array element to the last place.
3437
     *
3438
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3439
     *       loss the keys of an indexed array.
3440
     *
3441
     * @param int|string $key
3442
     *
3443
     * @return static
3444
     *                <p>(Immutable)</p>
3445
     *
3446
     * @psalm-return static<TKey,T>
3447
     * @psalm-mutation-free
3448
     */
3449 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...
3450
    {
3451 1
        $array = $this->getArray();
3452
3453 1
        if ($this->offsetExists($key)) {
3454 1
            $tmpValue = $this->get($key);
3455 1
            unset($array[$key]);
3456 1
            $array += [$key => $tmpValue];
3457
        }
3458
3459 1
        return static::create(
3460 1
            $array,
3461 1
            $this->iteratorClass,
3462 1
            false
3463
        );
3464
    }
3465
3466
    /**
3467
     * Moves the internal iterator position to the next element and returns this element.
3468
     *
3469
     * @return mixed
3470
     */
3471
    public function next()
3472
    {
3473
        return \next($this->array);
3474
    }
3475
3476
    /**
3477
     * Get the next nth keys and values from the array.
3478
     *
3479
     * @param int $step
3480
     * @param int $offset
3481
     *
3482
     * @return static
3483
     *                <p>(Immutable)</p>
3484
     *
3485
     * @psalm-return static<TKey,T>
3486
     * @psalm-mutation-free
3487
     */
3488 1
    public function nth(int $step, int $offset = 0): self
3489
    {
3490
        $arrayFunction = function () use ($step, $offset): \Generator {
3491 1
            $position = 0;
3492 1
            foreach ($this->getGenerator() as $key => $value) {
3493 1
                if ($position++ % $step !== $offset) {
3494 1
                    continue;
3495
                }
3496
3497 1
                yield $key => $value;
3498
            }
3499 1
        };
3500
3501 1
        return static::create(
3502 1
            $arrayFunction,
3503 1
            $this->iteratorClass,
3504 1
            false
3505
        );
3506
    }
3507
3508
    /**
3509
     * Get a subset of the items from the given array.
3510
     *
3511
     * @param mixed[] $keys
3512
     *
3513
     * @return static
3514
     *                <p>(Immutable)</p>
3515
     *
3516
     * @psalm-return static<TKey,T>
3517
     * @psalm-mutation-free
3518
     */
3519 1
    public function only(array $keys): self
3520
    {
3521 1
        $array = $this->getArray();
3522
3523 1
        return static::create(
3524 1
            \array_intersect_key($array, \array_flip($keys)),
3525 1
            $this->iteratorClass,
3526 1
            false
3527
        );
3528
    }
3529
3530
    /**
3531
     * Pad array to the specified size with a given value.
3532
     *
3533
     * @param int   $size  <p>Size of the result array.</p>
3534
     * @param mixed $value <p>Empty value by default.</p>
3535
     *
3536
     * @return static
3537
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
3538
     *
3539
     * @psalm-return static<TKey,T>
3540
     * @psalm-mutation-free
3541
     */
3542 5
    public function pad(int $size, $value): self
3543
    {
3544 5
        return static::create(
3545 5
            \array_pad($this->getArray(), $size, $value),
3546 5
            $this->iteratorClass,
3547 5
            false
3548
        );
3549
    }
3550
3551
    /**
3552
     * Partitions this array in two array according to a predicate.
3553
     * Keys are preserved in the resulting array.
3554
     *
3555
     * @param \Closure $closure
3556
     *                          <p>The predicate on which to partition.</p>
3557
     *
3558
     * @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...
3559
     *                    <p>An array with two elements. The first element contains the array
3560
     *                    of elements where the predicate returned TRUE, the second element
3561
     *                    contains the array of elements where the predicate returned FALSE.</p>
3562
     *
3563
     * @psalm-return array<int, static<mixed,T>>
3564
     */
3565 1
    public function partition(\Closure $closure): array
3566
    {
3567
        // init
3568 1
        $matches = [];
3569 1
        $noMatches = [];
3570
3571 1
        foreach ($this->array as $key => $value) {
3572 1
            if ($closure($value, $key)) {
3573 1
                $matches[$key] = $value;
3574
            } else {
3575 1
                $noMatches[$key] = $value;
3576
            }
3577
        }
3578
3579 1
        return [self::create($matches), self::create($noMatches)];
3580
    }
3581
3582
    /**
3583
     * Pop a specified value off the end of the current array.
3584
     *
3585
     * @return mixed
3586
     *               <p>(Mutable) The popped element from the current array.</p>
3587
     */
3588 5
    public function pop()
3589
    {
3590 5
        $this->generatorToArray();
3591
3592 5
        return \array_pop($this->array);
3593
    }
3594
3595
    /**
3596
     * Prepend a (key) + value to the current array.
3597
     *
3598
     * @param mixed $value
3599
     * @param mixed $key
3600
     *
3601
     * @return $this
3602
     *               <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
3603
     *
3604
     * @psalm-return $this<TKey,T>
3605
     */
3606 11
    public function prepend($value, $key = null)
3607
    {
3608 11
        $this->generatorToArray();
3609
3610 11
        if ($this->properties !== []) {
3611 3
            $this->checkType($key, $value);
3612
        }
3613
3614 9
        if ($key === null) {
3615 8
            \array_unshift($this->array, $value);
3616
        } else {
3617 2
            $this->array = [$key => $value] + $this->array;
3618
        }
3619
3620 9
        return $this;
3621
    }
3622
3623
    /**
3624
     * Add a suffix to each key.
3625
     *
3626
     * @param mixed $suffix
3627
     *
3628
     * @return static
3629
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
3630
     *
3631
     * @psalm-return static<TKey,T>
3632
     * @psalm-mutation-free
3633
     */
3634 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...
3635
    {
3636
        // init
3637 10
        $result = [];
3638
3639 10
        foreach ($this->getGenerator() as $key => $item) {
3640 9
            if ($item instanceof self) {
3641
                $result[$key] = $item->prependToEachKey($suffix);
3642 9
            } elseif (\is_array($item) === true) {
3643
                $result[$key] = self::create(
3644
                    $item,
3645
                    $this->iteratorClass,
3646
                    false
3647
                )->prependToEachKey($suffix)
3648
                    ->toArray();
3649
            } else {
3650 9
                $result[$key . $suffix] = $item;
3651
            }
3652
        }
3653
3654 10
        return self::create(
3655 10
            $result,
3656 10
            $this->iteratorClass,
3657 10
            false
3658
        );
3659
    }
3660
3661
    /**
3662
     * Add a suffix to each value.
3663
     *
3664
     * @param mixed $suffix
3665
     *
3666
     * @return static
3667
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
3668
     *
3669
     * @psalm-return static<TKey,T>
3670
     * @psalm-mutation-free
3671
     */
3672 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...
3673
    {
3674
        // init
3675 10
        $result = [];
3676
3677 10
        foreach ($this->getGenerator() as $key => $item) {
3678 9
            if ($item instanceof self) {
3679
                $result[$key] = $item->prependToEachValue($suffix);
3680 9
            } elseif (\is_array($item) === true) {
3681
                $result[$key] = self::create(
3682
                    $item,
3683
                    $this->iteratorClass,
3684
                    false
3685
                )->prependToEachValue($suffix)
3686
                    ->toArray();
3687 9
            } elseif (\is_object($item) === true) {
3688 1
                $result[$key] = $item;
3689
            } else {
3690 9
                $result[$key] = $item . $suffix;
3691
            }
3692
        }
3693
3694 10
        return self::create(
3695 10
            $result,
3696 10
            $this->iteratorClass,
3697 10
            false
3698
        );
3699
    }
3700
3701
    /**
3702
     * Return the value of a given key and
3703
     * delete the key.
3704
     *
3705
     * @param int|int[]|string|string[]|null $keyOrKeys
3706
     * @param mixed                          $fallback
3707
     *
3708
     * @return mixed
3709
     */
3710 1
    public function pull($keyOrKeys = null, $fallback = null)
3711
    {
3712 1
        if ($keyOrKeys === null) {
3713
            $array = $this->getArray();
3714
            $this->clear();
3715
3716
            return $array;
3717
        }
3718
3719 1
        if (\is_array($keyOrKeys) === true) {
3720 1
            $valueOrValues = [];
3721 1
            foreach ($keyOrKeys as $key) {
3722 1
                $valueOrValues[] = $this->get($key, $fallback);
3723 1
                $this->offsetUnset($key);
3724
            }
3725
        } else {
3726 1
            $valueOrValues = $this->get($keyOrKeys, $fallback);
3727 1
            $this->offsetUnset($keyOrKeys);
3728
        }
3729
3730 1
        return $valueOrValues;
3731
    }
3732
3733
    /**
3734
     * Push one or more values onto the end of array at once.
3735
     *
3736
     * @param array ...$args
3737
     *
3738
     * @return $this
3739
     *               <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
3740
     *
3741
     * @noinspection ReturnTypeCanBeDeclaredInspection
3742
     *
3743
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$args
3744
     * @psalm-return $this<TKey,T>
3745
     */
3746 5
    public function push(...$args)
3747
    {
3748 5
        $this->generatorToArray();
3749
3750
        if (
3751 5
            $this->checkPropertyTypes
3752
            &&
3753 5
            $this->properties !== []
3754
        ) {
3755 1
            foreach ($args as $key => $value) {
3756 1
                $this->checkType($key, $value);
3757
            }
3758
        }
3759
3760 5
        \array_push(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_push() as the parameter $array expects a reference.
Loading history...
3761
3762 5
        return $this;
3763
    }
3764
3765
    /**
3766
     * Get a random value from the current array.
3767
     *
3768
     * @param int|null $number <p>How many values you will take?</p>
3769
     *
3770
     * @return static
3771
     *                <p>(Immutable)</p>
3772
     *
3773
     * @psalm-return static<TKey,T>
3774
     * @psalm-mutation-free
3775
     */
3776 19
    public function randomImmutable(int $number = null): self
3777
    {
3778 19
        $this->generatorToArray();
3779
3780 19
        if ($this->count() === 0) {
3781 1
            return static::create(
3782 1
                [],
3783 1
                $this->iteratorClass,
3784 1
                false
3785
            );
3786
        }
3787
3788 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...
3789
            /** @noinspection NonSecureArrayRandUsageInspection */
3790 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3791
3792 13
            return static::create(
3793 13
                $arrayRandValue,
3794 13
                $this->iteratorClass,
3795 13
                false
3796
            );
3797
        }
3798
3799 6
        $arrayTmp = $this->array;
3800
        /** @noinspection NonSecureShuffleUsageInspection */
3801 6
        \shuffle($arrayTmp);
3802
3803 6
        return static::create(
3804 6
            $arrayTmp,
3805 6
            $this->iteratorClass,
3806 6
            false
3807 6
        )->firstsImmutable($number);
3808
    }
3809
3810
    /**
3811
     * Pick a random key/index from the keys of this array.
3812
     *
3813
     * @throws \RangeException If array is empty
3814
     *
3815
     * @return mixed
3816
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
3817
     */
3818 4
    public function randomKey()
3819
    {
3820 4
        $result = $this->randomKeys(1);
3821
3822 4
        if (!isset($result[0])) {
3823
            $result[0] = null;
3824
        }
3825
3826 4
        return $result[0];
3827
    }
3828
3829
    /**
3830
     * Pick a given number of random keys/indexes out of this array.
3831
     *
3832
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
3833
     *
3834
     * @throws \RangeException If array is empty
3835
     *
3836
     * @return static
3837
     *                <p>(Immutable)</p>
3838
     *
3839
     * @psalm-return static<TKey,T>
3840
     * @psalm-mutation-free
3841
     */
3842 13
    public function randomKeys(int $number): self
3843
    {
3844 13
        $this->generatorToArray();
3845
3846 13
        $count = $this->count();
3847
3848
        if (
3849 13
            $number === 0
3850
            ||
3851 13
            $number > $count
3852
        ) {
3853 2
            throw new \RangeException(
3854 2
                \sprintf(
3855 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
3856 2
                    $number,
3857 2
                    $count
3858
                )
3859
            );
3860
        }
3861
3862 11
        $result = (array) \array_rand($this->array, $number);
3863
3864 11
        return static::create(
3865 11
            $result,
3866 11
            $this->iteratorClass,
3867 11
            false
3868
        );
3869
    }
3870
3871
    /**
3872
     * Get a random value from the current array.
3873
     *
3874
     * @param int|null $number <p>How many values you will take?</p>
3875
     *
3876
     * @return $this
3877
     *               <p>(Mutable) Return this Arrayy object.</p>
3878
     *
3879
     * @psalm-return $this<TKey,T>
3880
     */
3881 17
    public function randomMutable(int $number = null): self
3882
    {
3883 17
        $this->generatorToArray();
3884
3885 17
        if ($this->count() === 0) {
3886
            return static::create(
3887
                [],
3888
                $this->iteratorClass,
3889
                false
3890
            );
3891
        }
3892
3893 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...
3894
            /** @noinspection NonSecureArrayRandUsageInspection */
3895 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3896 7
            $this->array = $arrayRandValue;
3897
3898 7
            return $this;
3899
        }
3900
3901
        /** @noinspection NonSecureShuffleUsageInspection */
3902 11
        \shuffle($this->array);
3903
3904 11
        return $this->firstsMutable($number);
3905
    }
3906
3907
    /**
3908
     * Pick a random value from the values of this array.
3909
     *
3910
     * @return mixed
3911
     *               <p>Get a random value or null if there wasn't a value.</p>
3912
     */
3913 4
    public function randomValue()
3914
    {
3915 4
        $result = $this->randomImmutable();
3916
3917 4
        if (!isset($result[0])) {
3918
            $result[0] = null;
3919
        }
3920
3921 4
        return $result[0];
3922
    }
3923
3924
    /**
3925
     * Pick a given number of random values out of this array.
3926
     *
3927
     * @param int $number
3928
     *
3929
     * @return static
3930
     *                <p>(Mutable)</p>
3931
     *
3932
     * @psalm-return static<TKey,T>
3933
     */
3934 7
    public function randomValues(int $number): self
3935
    {
3936 7
        return $this->randomMutable($number);
3937
    }
3938
3939
    /**
3940
     * Get a random value from an array, with the ability to skew the results.
3941
     *
3942
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3943
     *
3944
     * @param array    $array
3945
     * @param int|null $number <p>How many values you will take?</p>
3946
     *
3947
     * @return static
3948
     *                <p>(Immutable)</p>
3949
     *
3950
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
3951
     * @psalm-return static<TKey,T>
3952
     * @psalm-mutation-free
3953
     */
3954 9
    public function randomWeighted(array $array, int $number = null): self
3955
    {
3956
        // init
3957 9
        $options = [];
3958
3959 9
        foreach ($array as $option => $weight) {
3960 9
            if ($this->searchIndex($option) !== false) {
3961 9
                for ($i = 0; $i < $weight; ++$i) {
3962 1
                    $options[] = $option;
3963
                }
3964
            }
3965
        }
3966
3967 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3968
    }
3969
3970
    /**
3971
     * Reduce the current array via callable e.g. anonymous-function.
3972
     *
3973
     * @param callable $callable
3974
     * @param mixed    $init
3975
     *
3976
     * @return static
3977
     *                <p>(Immutable)</p>
3978
     *
3979
     * @psalm-return static<TKey,T>
3980
     * @psalm-mutation-free
3981
     */
3982 18
    public function reduce($callable, $init = []): self
3983
    {
3984 18
        if ($this->generator) {
3985 1
            $result = $init;
3986
3987 1
            foreach ($this->getGenerator() as $value) {
3988 1
                $result = $callable($result, $value);
3989
            }
3990
3991 1
            return static::create(
3992 1
                $result,
3993 1
                $this->iteratorClass,
3994 1
                false
3995
            );
3996
        }
3997
3998 18
        $result = \array_reduce($this->array, $callable, $init);
3999
4000 18
        if ($result === null) {
4001
            $this->array = [];
4002
        } else {
4003 18
            $this->array = (array) $result;
4004
        }
4005
4006 18
        return static::create(
4007 18
            $this->array,
4008 18
            $this->iteratorClass,
4009 18
            false
4010
        );
4011
    }
4012
4013
    /**
4014
     * @param bool $unique
4015
     *
4016
     * @return static
4017
     *                <p>(Immutable)</p>
4018
     *
4019
     * @psalm-return static<TKey,T>
4020
     * @psalm-mutation-free
4021
     */
4022 14
    public function reduce_dimension(bool $unique = true): self
4023
    {
4024
        // init
4025 14
        $result = [];
4026
4027 14
        foreach ($this->getGenerator() as $val) {
4028 12
            if (\is_array($val) === true) {
4029 5
                $result[] = (new static($val))->reduce_dimension($unique)->getArray();
4030
            } else {
4031 12
                $result[] = [$val];
4032
            }
4033
        }
4034
4035 14
        $result = $result === [] ? [] : \array_merge(...$result);
4036
4037 14
        $resultArrayy = new static($result);
4038
4039 14
        return $unique ? $resultArrayy->unique() : $resultArrayy;
4040
    }
4041
4042
    /**
4043
     * Create a numerically re-indexed Arrayy object.
4044
     *
4045
     * @return $this
4046
     *               <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
4047
     *
4048
     * @psalm-return $this<TKey,T>
4049
     */
4050 9
    public function reindex(): self
4051
    {
4052 9
        $this->generatorToArray();
4053
4054 9
        $this->array = \array_values($this->array);
4055
4056 9
        return $this;
4057
    }
4058
4059
    /**
4060
     * Return all items that fail the truth test.
4061
     *
4062
     * @param \Closure $closure
4063
     *
4064
     * @return static
4065
     *                <p>(Immutable)</p>
4066
     *
4067
     * @psalm-return static<TKey,T>
4068
     * @psalm-mutation-free
4069
     */
4070 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...
4071
    {
4072
        // init
4073 1
        $filtered = [];
4074
4075 1
        foreach ($this->getGenerator() as $key => $value) {
4076 1
            if (!$closure($value, $key)) {
4077 1
                $filtered[$key] = $value;
4078
            }
4079
        }
4080
4081 1
        return static::create(
4082 1
            $filtered,
4083 1
            $this->iteratorClass,
4084 1
            false
4085
        );
4086
    }
4087
4088
    /**
4089
     * Remove a value from the current array (optional using dot-notation).
4090
     *
4091
     * @param mixed $key
4092
     *
4093
     * @return static
4094
     *                <p>(Mutable)</p>
4095
     *
4096
     * @psalm-param  TKey $key
4097
     * @psalm-return static<TKey,T>
4098
     */
4099 18
    public function remove($key)
4100
    {
4101
        // recursive call
4102 18
        if (\is_array($key) === true) {
4103
            foreach ($key as $k) {
4104
                $this->internalRemove($k);
4105
            }
4106
4107
            return static::create(
4108
                $this->getArray(),
4109
                $this->iteratorClass,
4110
                false
4111
            );
4112
        }
4113
4114 18
        $this->internalRemove($key);
4115
4116 18
        return static::create(
4117 18
            $this->getArray(),
4118 18
            $this->iteratorClass,
4119 18
            false
4120
        );
4121
    }
4122
4123
    /**
4124
     * alias: for "Arrayy->removeValue()"
4125
     *
4126
     * @param mixed $element
4127
     *
4128
     * @return static
4129
     *                <p>(Immutable)</p>
4130
     *
4131
     * @psalm-param  T $element
4132
     * @psalm-return static<TKey,T>
4133
     * @psalm-mutation-free
4134
     */
4135 8
    public function removeElement($element)
4136
    {
4137 8
        return $this->removeValue($element);
4138
    }
4139
4140
    /**
4141
     * Remove the first value from the current array.
4142
     *
4143
     * @return static
4144
     *                <p>(Immutable)</p>
4145
     *
4146
     * @psalm-return static<TKey,T>
4147
     * @psalm-mutation-free
4148
     */
4149 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...
4150
    {
4151 7
        $tmpArray = $this->getArray();
4152
4153 7
        \array_shift($tmpArray);
4154
4155 7
        return static::create(
4156 7
            $tmpArray,
4157 7
            $this->iteratorClass,
4158 7
            false
4159
        );
4160
    }
4161
4162
    /**
4163
     * Remove the last value from the current array.
4164
     *
4165
     * @return static
4166
     *                <p>(Immutable)</p>
4167
     *
4168
     * @psalm-return static<TKey,T>
4169
     * @psalm-mutation-free
4170
     */
4171 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...
4172
    {
4173 7
        $tmpArray = $this->getArray();
4174
4175 7
        \array_pop($tmpArray);
4176
4177 7
        return static::create(
4178 7
            $tmpArray,
4179 7
            $this->iteratorClass,
4180 7
            false
4181
        );
4182
    }
4183
4184
    /**
4185
     * Removes a particular value from an array (numeric or associative).
4186
     *
4187
     * @param mixed $value
4188
     *
4189
     * @return static
4190
     *                <p>(Immutable)</p>
4191
     *
4192
     * @psalm-param  T $value
4193
     * @psalm-return static<TKey,T>
4194
     * @psalm-mutation-free
4195
     */
4196 8
    public function removeValue($value): self
4197
    {
4198 8
        $this->generatorToArray();
4199
4200
        // init
4201 8
        $isSequentialArray = $this->isSequential();
4202
4203 8
        foreach ($this->array as $key => $item) {
4204 7
            if ($item === $value) {
4205 7
                unset($this->array[$key]);
4206
            }
4207
        }
4208
4209 8
        if ($isSequentialArray) {
4210 6
            $this->array = \array_values($this->array);
4211
        }
4212
4213 8
        return static::create(
4214 8
            $this->array,
4215 8
            $this->iteratorClass,
4216 8
            false
4217
        );
4218
    }
4219
4220
    /**
4221
     * Generate array of repeated arrays.
4222
     *
4223
     * @param int $times <p>How many times has to be repeated.</p>
4224
     *
4225
     * @return static
4226
     *                <p>(Immutable)</p>
4227
     *
4228
     * @psalm-return static<TKey,T>
4229
     * @psalm-mutation-free
4230
     */
4231 1
    public function repeat($times): self
4232
    {
4233 1
        if ($times === 0) {
4234 1
            return static::create([], $this->iteratorClass);
4235
        }
4236
4237 1
        return static::create(
4238 1
            \array_fill(0, (int) $times, $this->getArray()),
4239 1
            $this->iteratorClass,
4240 1
            false
4241
        );
4242
    }
4243
4244
    /**
4245
     * Replace a key with a new key/value pair.
4246
     *
4247
     * @param mixed $replace
4248
     * @param mixed $key
4249
     * @param mixed $value
4250
     *
4251
     * @return static
4252
     *                <p>(Immutable)</p>
4253
     *
4254
     * @psalm-return static<TKey,T>
4255
     * @psalm-mutation-free
4256
     */
4257 2
    public function replace($replace, $key, $value): self
4258
    {
4259 2
        $that = clone $this;
4260
4261 2
        return $that->remove($replace)
4262 2
            ->set($key, $value);
4263
    }
4264
4265
    /**
4266
     * Create an array using the current array as values and the other array as keys.
4267
     *
4268
     * @param array $keys <p>An array of keys.</p>
4269
     *
4270
     * @return static
4271
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
4272
     *
4273
     * @psalm-param  array<mixed,mixed>|array<mixed,TKey> $keys
4274
     * @psalm-return static<TKey,T>
4275
     * @psalm-mutation-free
4276
     */
4277 2
    public function replaceAllKeys(array $keys): self
4278
    {
4279 2
        return static::create(
4280 2
            \array_combine($keys, $this->getArray()),
4281 2
            $this->iteratorClass,
4282 2
            false
4283
        );
4284
    }
4285
4286
    /**
4287
     * Create an array using the current array as keys and the other array as values.
4288
     *
4289
     * @param array $array <p>An array o values.</p>
4290
     *
4291
     * @return static
4292
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
4293
     *
4294
     * @psalm-param  array<mixed,T> $array
4295
     * @psalm-return static<TKey,T>
4296
     * @psalm-mutation-free
4297
     */
4298 2
    public function replaceAllValues(array $array): self
4299
    {
4300 2
        return static::create(
4301 2
            \array_combine($this->array, $array),
4302 2
            $this->iteratorClass,
4303 2
            false
4304
        );
4305
    }
4306
4307
    /**
4308
     * Replace the keys in an array with another set.
4309
     *
4310
     * @param array $keys <p>An array of keys matching the array's size</p>
4311
     *
4312
     * @return static
4313
     *                <p>(Immutable)</p>
4314
     *
4315
     * @psalm-param  array<mixed,mixed>|array<mixed,TKey> $keys
4316
     * @psalm-return static<TKey,T>
4317
     * @psalm-mutation-free
4318
     */
4319 1
    public function replaceKeys(array $keys): self
4320
    {
4321 1
        $values = \array_values($this->getArray());
4322 1
        $result = \array_combine($keys, $values);
4323
4324 1
        return static::create(
4325 1
            $result,
4326 1
            $this->iteratorClass,
4327 1
            false
4328
        );
4329
    }
4330
4331
    /**
4332
     * Replace the first matched value in an array.
4333
     *
4334
     * @param mixed $search      <p>The value to replace.</p>
4335
     * @param mixed $replacement <p>The value to replace.</p>
4336
     *
4337
     * @return static
4338
     *                <p>(Immutable)</p>
4339
     *
4340
     * @psalm-return static<TKey,T>
4341
     * @psalm-mutation-free
4342
     */
4343 3
    public function replaceOneValue($search, $replacement = ''): self
4344
    {
4345 3
        $array = $this->getArray();
4346 3
        $key = \array_search($search, $array, true);
4347
4348 3
        if ($key !== false) {
4349 3
            $array[$key] = $replacement;
4350
        }
4351
4352 3
        return static::create(
4353 3
            $array,
4354 3
            $this->iteratorClass,
4355 3
            false
4356
        );
4357
    }
4358
4359
    /**
4360
     * Replace values in the current array.
4361
     *
4362
     * @param mixed $search      <p>The value to replace.</p>
4363
     * @param mixed $replacement <p>What to replace it with.</p>
4364
     *
4365
     * @return static
4366
     *                <p>(Immutable)</p>
4367
     *
4368
     * @psalm-return static<TKey,T>
4369
     * @psalm-mutation-free
4370
     */
4371 1
    public function replaceValues($search, $replacement = ''): self
4372
    {
4373 1
        return $this->each(
4374
            static function ($value) use ($search, $replacement) {
4375 1
                return \str_replace($search, $replacement, $value);
4376 1
            }
4377
        );
4378
    }
4379
4380
    /**
4381
     * Get the last elements from index $from until the end of this array.
4382
     *
4383
     * @param int $from
4384
     *
4385
     * @return static
4386
     *                <p>(Immutable)</p>
4387
     *
4388
     * @psalm-return static<TKey,T>
4389
     * @psalm-mutation-free
4390
     */
4391 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...
4392
    {
4393 15
        $tmpArray = $this->getArray();
4394
4395 15
        return static::create(
4396 15
            \array_splice($tmpArray, $from),
4397 15
            $this->iteratorClass,
4398 15
            false
4399
        );
4400
    }
4401
4402
    /**
4403
     * Return the array in the reverse order.
4404
     *
4405
     * @return $this
4406
     *               <p>(Mutable) Return this Arrayy object.</p>
4407
     *
4408
     * @psalm-return $this<TKey,T>
4409
     */
4410 9
    public function reverse(): self
4411
    {
4412 9
        $this->generatorToArray();
4413
4414 9
        $this->array = \array_reverse($this->array);
4415
4416 9
        return $this;
4417
    }
4418
4419
    /**
4420
     * Sort an array in reverse order.
4421
     *
4422
     * @param int $sort_flags [optional] <p>
4423
     *                        You may modify the behavior of the sort using the optional
4424
     *                        parameter sort_flags, for details
4425
     *                        see sort.
4426
     *                        </p>
4427
     *
4428
     * @return $this
4429
     *               <p>(Mutable) Return this Arrayy object.</p>
4430
     *
4431
     * @psalm-return $this<TKey,T>
4432
     */
4433 4
    public function rsort(int $sort_flags = 0): self
4434
    {
4435 4
        $this->generatorToArray();
4436
4437 4
        \rsort($this->array, $sort_flags);
4438
4439 4
        return $this;
4440
    }
4441
4442
    /**
4443
     * Search for the first index of the current array via $value.
4444
     *
4445
     * @param mixed $value
4446
     *
4447
     * @return false|float|int|string
4448
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
4449
     */
4450 21
    public function searchIndex($value)
4451
    {
4452 21
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
4453 20
            if ($value === $valueFromArray) {
4454 20
                return $keyFromArray;
4455
            }
4456
        }
4457
4458 11
        return false;
4459
    }
4460
4461
    /**
4462
     * Search for the value of the current array via $index.
4463
     *
4464
     * @param mixed $index
4465
     *
4466
     * @return static
4467
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
4468
     *
4469
     * @psalm-return static<TKey,T>
4470
     * @psalm-mutation-free
4471
     */
4472 9
    public function searchValue($index): self
4473
    {
4474 9
        $this->generatorToArray();
4475
4476
        // init
4477 9
        $return = [];
4478
4479 9
        if ($this->array === []) {
4480
            return static::create(
4481
                [],
4482
                $this->iteratorClass,
4483
                false
4484
            );
4485
        }
4486
4487
        // php cast "bool"-index into "int"-index
4488 9
        if ((bool) $index === $index) {
4489 1
            $index = (int) $index;
4490
        }
4491
4492 9
        if ($this->offsetExists($index)) {
4493 7
            $return = [$this->array[$index]];
4494
        }
4495
4496 9
        return static::create(
4497 9
            $return,
4498 9
            $this->iteratorClass,
4499 9
            false
4500
        );
4501
    }
4502
4503
    /**
4504
     * Set a value for the current array (optional using dot-notation).
4505
     *
4506
     * @param string $key   <p>The key to set.</p>
4507
     * @param mixed  $value <p>Its value.</p>
4508
     *
4509
     * @return $this
4510
     *               <p>(Mutable) Return this Arrayy object.</p>
4511
     *
4512
     * @psalm-param  TKey $key
4513
     * @psalm-param  T $value
4514
     * @psalm-return $this<TKey,T>
4515
     */
4516 18
    public function set($key, $value): self
4517
    {
4518 18
        $this->generatorToArray();
4519
4520 18
        $this->internalSet($key, $value);
4521
4522 18
        return $this;
4523
    }
4524
4525
    /**
4526
     * Get a value from a array and set it if it was not.
4527
     *
4528
     * WARNING: this method only set the value, if the $key is not already set
4529
     *
4530
     * @param mixed $key      <p>The key</p>
4531
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
4532
     *
4533
     * @return mixed
4534
     *               <p>(Mutable)</p>
4535
     */
4536 11
    public function setAndGet($key, $fallback = null)
4537
    {
4538 11
        $this->generatorToArray();
4539
4540
        // If the key doesn't exist, set it.
4541 11
        if (!$this->has($key)) {
4542 4
            $this->array = $this->set($key, $fallback)->getArray();
4543
        }
4544
4545 11
        return $this->get($key);
4546
    }
4547
4548
    /**
4549
     * Shifts a specified value off the beginning of array.
4550
     *
4551
     * @return mixed
4552
     *               <p>(Mutable) A shifted element from the current array.</p>
4553
     */
4554 5
    public function shift()
4555
    {
4556 5
        $this->generatorToArray();
4557
4558 5
        return \array_shift($this->array);
4559
    }
4560
4561
    /**
4562
     * Shuffle the current array.
4563
     *
4564
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
4565
     * @param array $array  [optional]
4566
     *
4567
     * @return static
4568
     *                <p>(Immutable)</p>
4569
     *
4570
     * @psalm-param  array<mixed,mixed>|array<TKey,T> $array
4571
     * @psalm-return static<TKey,T>
4572
     * @psalm-mutation-free
4573
     */
4574 2
    public function shuffle(bool $secure = false, array $array = null): self
4575
    {
4576 2
        if ($array === null) {
4577 2
            $array = $this->getArray();
4578
        }
4579
4580 2
        if ($secure !== true) {
4581
            /** @noinspection NonSecureShuffleUsageInspection */
4582 2
            \shuffle($array);
4583
        } else {
4584 1
            $size = \count($array, \COUNT_NORMAL);
4585 1
            $keys = \array_keys($array);
4586 1
            for ($i = $size - 1; $i > 0; --$i) {
4587
                try {
4588 1
                    $r = \random_int(0, $i);
4589
                } catch (\Exception $e) {
4590
                    /** @noinspection RandomApiMigrationInspection */
4591
                    $r = \mt_rand(0, $i);
4592
                }
4593 1
                if ($r !== $i) {
4594 1
                    $temp = $array[$keys[$r]];
4595 1
                    $array[$keys[$r]] = $array[$keys[$i]];
4596 1
                    $array[$keys[$i]] = $temp;
4597
                }
4598
            }
4599
4600
            // reset indices
4601 1
            $array = \array_values($array);
4602
        }
4603
4604 2
        foreach ($array as $key => $value) {
4605
            // check if recursive is needed
4606 2
            if (\is_array($value) === true) {
4607 2
                $array[$key] = $this->shuffle($secure, $value);
4608
            }
4609
        }
4610
4611 2
        return static::create(
4612 2
            $array,
4613 2
            $this->iteratorClass,
4614 2
            false
4615
        );
4616
    }
4617
4618
    /**
4619
     * Count the values from the current array.
4620
     *
4621
     * alias: for "Arrayy->count()"
4622
     *
4623
     * @param int $mode
4624
     *
4625
     * @return int
4626
     */
4627 20
    public function size(int $mode = \COUNT_NORMAL): int
4628
    {
4629 20
        return $this->count($mode);
4630
    }
4631
4632
    /**
4633
     * Checks whether array has exactly $size items.
4634
     *
4635
     * @param int $size
4636
     *
4637
     * @return bool
4638
     */
4639 1 View Code Duplication
    public function sizeIs(int $size): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4640
    {
4641
        // init
4642 1
        $itemsTempCount = 0;
4643
4644 1
        foreach ($this->getGenerator() as $key => $value) {
4645 1
            ++$itemsTempCount;
4646 1
            if ($itemsTempCount > $size) {
4647 1
                return false;
4648
            }
4649
        }
4650
4651 1
        return $itemsTempCount === $size;
4652
    }
4653
4654
    /**
4655
     * Checks whether array has between $fromSize to $toSize items. $toSize can be
4656
     * smaller than $fromSize.
4657
     *
4658
     * @param int $fromSize
4659
     * @param int $toSize
4660
     *
4661
     * @return bool
4662
     */
4663 1
    public function sizeIsBetween(int $fromSize, int $toSize): bool
4664
    {
4665 1
        if ($fromSize > $toSize) {
4666 1
            $tmp = $toSize;
4667 1
            $toSize = $fromSize;
4668 1
            $fromSize = $tmp;
4669
        }
4670
4671
        // init
4672 1
        $itemsTempCount = 0;
4673
4674 1
        foreach ($this->getGenerator() as $key => $value) {
4675 1
            ++$itemsTempCount;
4676 1
            if ($itemsTempCount > $toSize) {
4677 1
                return false;
4678
            }
4679
        }
4680
4681 1
        return $fromSize < $itemsTempCount && $itemsTempCount < $toSize;
4682
    }
4683
4684
    /**
4685
     * Checks whether array has more than $size items.
4686
     *
4687
     * @param int $size
4688
     *
4689
     * @return bool
4690
     */
4691 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...
4692
    {
4693
        // init
4694 1
        $itemsTempCount = 0;
4695
4696 1
        foreach ($this->getGenerator() as $key => $value) {
4697 1
            ++$itemsTempCount;
4698 1
            if ($itemsTempCount > $size) {
4699 1
                return true;
4700
            }
4701
        }
4702
4703 1
        return $itemsTempCount > $size;
4704
    }
4705
4706
    /**
4707
     * Checks whether array has less than $size items.
4708
     *
4709
     * @param int $size
4710
     *
4711
     * @return bool
4712
     */
4713 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...
4714
    {
4715
        // init
4716 1
        $itemsTempCount = 0;
4717
4718 1
        foreach ($this->getGenerator() as $key => $value) {
4719 1
            ++$itemsTempCount;
4720 1
            if ($itemsTempCount > $size) {
4721 1
                return false;
4722
            }
4723
        }
4724
4725 1
        return $itemsTempCount < $size;
4726
    }
4727
4728
    /**
4729
     * Counts all elements in an array, or something in an object.
4730
     *
4731
     * <p>
4732
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
4733
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
4734
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
4735
     * implemented and used in PHP.
4736
     * </p>
4737
     *
4738
     * @return int
4739
     *             <p>
4740
     *             The number of elements in var, which is
4741
     *             typically an array, since anything else will have one
4742
     *             element.
4743
     *             </p>
4744
     *             <p>
4745
     *             If var is not an array or an object with
4746
     *             implemented Countable interface,
4747
     *             1 will be returned.
4748
     *             There is one exception, if var is &null;,
4749
     *             0 will be returned.
4750
     *             </p>
4751
     *             <p>
4752
     *             Caution: count may return 0 for a variable that isn't set,
4753
     *             but it may also return 0 for a variable that has been initialized with an
4754
     *             empty array. Use isset to test if a variable is set.
4755
     *             </p>
4756
     */
4757 10
    public function sizeRecursive(): int
4758
    {
4759 10
        return \count($this->getArray(), \COUNT_RECURSIVE);
4760
    }
4761
4762
    /**
4763
     * Extract a slice of the array.
4764
     *
4765
     * @param int      $offset       <p>Slice begin index.</p>
4766
     * @param int|null $length       <p>Length of the slice.</p>
4767
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
4768
     *
4769
     * @return static
4770
     *                <p>(Immutable) A slice of the original array with length $length.</p>
4771
     *
4772
     * @psalm-return static<TKey,T>
4773
     * @psalm-mutation-free
4774
     */
4775 5
    public function slice(int $offset, int $length = null, bool $preserveKeys = false)
4776
    {
4777 5
        return static::create(
4778 5
            \array_slice(
4779 5
                $this->getArray(),
4780 5
                $offset,
4781 5
                $length,
4782 5
                $preserveKeys
4783
            ),
4784 5
            $this->iteratorClass,
4785 5
            false
4786
        );
4787
    }
4788
4789
    /**
4790
     * Sort the current array and optional you can keep the keys.
4791
     *
4792
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4793
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
4794
     *                              <strong>SORT_NATURAL</strong></p>
4795
     * @param bool       $keepKeys
4796
     *
4797
     * @return static
4798
     *                <p>(Mutable) Return this Arrayy object.</p>
4799
     *
4800
     * @psalm-return static<TKey,T>
4801
     */
4802 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4803
    {
4804 20
        $this->generatorToArray();
4805
4806 20
        return $this->sorting(
4807 20
            $this->array,
4808 20
            $direction,
4809 20
            $strategy,
4810 20
            $keepKeys
4811
        );
4812
    }
4813
4814
    /**
4815
     * Sort the current array by key.
4816
     *
4817
     * @see          http://php.net/manual/en/function.ksort.php
4818
     * @see          http://php.net/manual/en/function.krsort.php
4819
     *
4820
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4821
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4822
     *                              <strong>SORT_NATURAL</strong></p>
4823
     *
4824
     * @return $this
4825
     *               <p>(Mutable) Return this Arrayy object.</p>
4826
     *
4827
     * @psalm-return $this<TKey,T>
4828
     */
4829 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4830
    {
4831 18
        $this->generatorToArray();
4832
4833 18
        $this->sorterKeys($this->array, $direction, $strategy);
4834
4835 18
        return $this;
4836
    }
4837
4838
    /**
4839
     * Sort the current array by value.
4840
     *
4841
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4842
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4843
     *                              <strong>SORT_NATURAL</strong></p>
4844
     *
4845
     * @return static
4846
     *                <p>(Mutable)</p>
4847
     *
4848
     * @psalm-return static<TKey,T>
4849
     */
4850 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4851
    {
4852 1
        return $this->sort($direction, $strategy, true);
4853
    }
4854
4855
    /**
4856
     * Sort the current array by value.
4857
     *
4858
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4859
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4860
     *                              <strong>SORT_NATURAL</strong></p>
4861
     *
4862
     * @return static
4863
     *                <p>(Mutable)</p>
4864
     *
4865
     * @psalm-return static<TKey,T>
4866
     */
4867 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4868
    {
4869 1
        return $this->sort($direction, $strategy, false);
4870
    }
4871
4872
    /**
4873
     * Sort a array by value, by a closure or by a property.
4874
     *
4875
     * - If the sorter is null, the array is sorted naturally.
4876
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
4877
     *
4878
     * @param callable|string|null $sorter
4879
     * @param int|string           $direction <p>use <strong>SORT_ASC</strong> (default) or
4880
     *                                        <strong>SORT_DESC</strong></p>
4881
     * @param int                  $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4882
     *                                        <strong>SORT_NATURAL</strong></p>
4883
     *
4884
     * @return static
4885
     *                <p>(Immutable)</p>
4886
     *
4887
     * @psalm-return static<TKey,T>
4888
     * @psalm-mutation-free
4889
     */
4890 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4891
    {
4892 1
        $array = $this->getArray();
4893 1
        $direction = $this->getDirection($direction);
4894
4895
        // Transform all values into their results.
4896 1
        if ($sorter) {
4897 1
            $arrayy = static::create(
4898 1
                $array,
4899 1
                $this->iteratorClass,
4900 1
                false
4901
            );
4902
4903 1
            $results = $arrayy->each(
4904
                function ($value) use ($sorter) {
4905 1
                    if (\is_callable($sorter) === true) {
4906 1
                        return $sorter($value);
4907
                    }
4908
4909 1
                    return $this->get($sorter);
4910 1
                }
4911
            );
4912
4913 1
            $results = $results->getArray();
4914
        } else {
4915 1
            $results = $array;
4916
        }
4917
4918
        // Sort by the results and replace by original values
4919 1
        \array_multisort($results, $direction, $strategy, $array);
4920
4921 1
        return static::create(
4922 1
            $array,
4923 1
            $this->iteratorClass,
4924 1
            false
4925
        );
4926
    }
4927
4928
    /**
4929
     * @param int      $offset
4930
     * @param int|null $length
4931
     * @param array    $replacement
4932
     *
4933
     * @return static
4934
     *                <p>(Immutable)</p>
4935
     *
4936
     * @psalm-param  array<mixed,mixed>|array<mixed,T> $replacement
4937
     * @psalm-return static<TKey,T>
4938
     * @psalm-mutation-free
4939
     */
4940 1
    public function splice(int $offset, int $length = null, $replacement = []): self
4941
    {
4942 1
        $tmpArray = $this->getArray();
4943
4944 1
        \array_splice(
4945 1
            $tmpArray,
4946 1
            $offset,
4947 1
            $length ?? $this->count(),
4948 1
            $replacement
4949
        );
4950
4951 1
        return static::create(
4952 1
            $tmpArray,
4953 1
            $this->iteratorClass,
4954 1
            false
4955
        );
4956
    }
4957
4958
    /**
4959
     * Split an array in the given amount of pieces.
4960
     *
4961
     * @param int  $numberOfPieces
4962
     * @param bool $keepKeys
4963
     *
4964
     * @return static
4965
     *                <p>(Immutable)</p>
4966
     *
4967
     * @psalm-return static<TKey,T>
4968
     * @psalm-mutation-free
4969
     */
4970 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
4971
    {
4972 1
        $this->generatorToArray();
4973
4974 1
        $count = $this->count();
4975
4976 1
        if ($count === 0) {
4977 1
            $result = [];
4978
        } else {
4979 1
            $splitSize = (int) \ceil($count / $numberOfPieces);
4980 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
4981
        }
4982
4983 1
        return static::create(
4984 1
            $result,
4985 1
            $this->iteratorClass,
4986 1
            false
4987
        );
4988
    }
4989
4990
    /**
4991
     * Stripe all empty items.
4992
     *
4993
     * @return static
4994
     *                <p>(Immutable)</p>
4995
     *
4996
     * @psalm-return static<TKey,T>
4997
     * @psalm-mutation-free
4998
     */
4999 1
    public function stripEmpty(): self
5000
    {
5001 1
        return $this->filter(
5002
            static function ($item) {
5003 1
                if ($item === null) {
5004 1
                    return false;
5005
                }
5006
5007 1
                return (bool) \trim((string) $item);
5008 1
            }
5009
        );
5010
    }
5011
5012
    /**
5013
     * Swap two values between positions by key.
5014
     *
5015
     * @param int|string $swapA <p>a key in the array</p>
5016
     * @param int|string $swapB <p>a key in the array</p>
5017
     *
5018
     * @return static
5019
     *                <p>(Immutable)</p>
5020
     *
5021
     * @psalm-return static<TKey,T>
5022
     * @psalm-mutation-free
5023
     */
5024 1
    public function swap($swapA, $swapB): self
5025
    {
5026 1
        $array = $this->getArray();
5027
5028 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
5029
5030 1
        return static::create(
5031 1
            $array,
5032 1
            $this->iteratorClass,
5033 1
            false
5034
        );
5035
    }
5036
5037
    /**
5038
     * alias: for "Arrayy->getArray()"
5039
     *
5040
     * @param bool $convertAllArrayyElements
5041
     *
5042
     * @return array
5043
     *
5044
     * @see          Arrayy::getArray()
5045
     *
5046
     * @psalm-return array<array-key,mixed>
5047
     */
5048 241
    public function toArray(bool $convertAllArrayyElements = false): array
5049
    {
5050 241
        return $this->getArray($convertAllArrayyElements);
5051
    }
5052
5053
    /**
5054
     * Convert the current array to JSON.
5055
     *
5056
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
5057
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
5058
     *
5059
     * @return string
5060
     */
5061 7
    public function toJson(int $options = 0, int $depth = 512): string
5062
    {
5063 7
        $return = \json_encode($this->getArray(), $options, $depth);
5064 7
        if ($return === false) {
5065
            return '';
5066
        }
5067
5068 7
        return $return;
5069
    }
5070
5071
    /**
5072
     * @param string[]|null $items
5073
     * @param string[]      $helper
5074
     *
5075
     * @return static
5076
     *
5077
     * @psalm-return static<mixed,T>
5078
     */
5079 1
    public function toPermutation(array $items = null, array $helper = []): self
5080
    {
5081
        // init
5082 1
        $return = [];
5083
5084 1
        if ($items === null) {
5085 1
            $items = $this->getArray();
5086
        }
5087
5088 1
        if (empty($items)) {
5089 1
            $return[] = $helper;
5090
        } else {
5091 1
            for ($i = \count($items) - 1; $i >= 0; --$i) {
5092 1
                $new_items = $items;
5093 1
                $new_helper = $helper;
5094 1
                list($tmp_helper) = \array_splice($new_items, $i, 1);
5095
                /** @noinspection PhpSillyAssignmentInspection */
5096
                /** @var string[] $new_items */
5097 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...
5098 1
                \array_unshift($new_helper, $tmp_helper);
5099
                /** @noinspection SlowArrayOperationsInLoopInspection */
5100 1
                $return = \array_merge(
5101 1
                    $return,
5102 1
                    $this->toPermutation($new_items, $new_helper)->toArray()
5103
                );
5104
            }
5105
        }
5106
5107 1
        return static::create(
5108 1
            $return,
5109 1
            $this->iteratorClass,
5110 1
            false
5111
        );
5112
    }
5113
5114
    /**
5115
     * Implodes array to a string with specified separator.
5116
     *
5117
     * @param string $separator [optional] <p>The element's separator.</p>
5118
     *
5119
     * @return string
5120
     *                <p>The string representation of array, separated by ",".</p>
5121
     */
5122 19
    public function toString(string $separator = ','): string
5123
    {
5124 19
        return $this->implode($separator);
5125
    }
5126
5127
    /**
5128
     * Return a duplicate free copy of the current array.
5129
     *
5130
     * @return $this
5131
     *               <p>(Mutable)</p>
5132
     *
5133
     * @psalm-return $this<TKey,T>
5134
     */
5135 13
    public function unique(): self
5136
    {
5137
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
5138
5139 13
        $this->array = $this->reduce(
5140
            static function ($resultArray, $value) {
5141 12
                if (!\in_array($value, $resultArray, true)) {
5142 12
                    $resultArray[] = $value;
5143
                }
5144
5145 12
                return $resultArray;
5146 13
            },
5147 13
            []
5148 13
        )->getArray();
5149 13
        $this->generator = null;
5150
5151 13
        return $this;
5152
    }
5153
5154
    /**
5155
     * Return a duplicate free copy of the current array. (with the old keys)
5156
     *
5157
     * @return $this
5158
     *               <p>(Mutable)</p>
5159
     *
5160
     * @psalm-return $this<TKey,T>
5161
     */
5162 11
    public function uniqueKeepIndex(): self
5163
    {
5164
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
5165
5166
        // init
5167 11
        $array = $this->getArray();
5168
5169 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...
5170 11
            \array_keys($array),
5171
            static function ($resultArray, $key) use ($array) {
5172 10
                if (!\in_array($array[$key], $resultArray, true)) {
5173 10
                    $resultArray[$key] = $array[$key];
5174
                }
5175
5176 10
                return $resultArray;
5177 11
            },
5178 11
            []
5179
        );
5180 11
        $this->generator = null;
5181
5182 11
        if ($this->array === null) {
5183
            $this->array = [];
5184
        } else {
5185 11
            $this->array = (array) $this->array;
5186
        }
5187
5188 11
        return $this;
5189
    }
5190
5191
    /**
5192
     * alias: for "Arrayy->unique()"
5193
     *
5194
     * @return static
5195
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
5196
     *
5197
     * @see          Arrayy::unique()
5198
     *
5199
     * @psalm-return static<TKey,T>
5200
     */
5201 10
    public function uniqueNewIndex(): self
5202
    {
5203 10
        return $this->unique();
5204
    }
5205
5206
    /**
5207
     * Prepends one or more values to the beginning of array at once.
5208
     *
5209
     * @param array ...$args
5210
     *
5211
     * @return $this
5212
     *               <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
5213
     *
5214
     * @psalm-param  array<mixed,mixed>|array<TKey,T> ...$args
5215
     * @psalm-return $this<TKey,T>
5216
     */
5217 4
    public function unshift(...$args): self
5218
    {
5219 4
        $this->generatorToArray();
5220
5221 4
        \array_unshift(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_unshift() as the parameter $array expects a reference.
Loading history...
5222
5223 4
        return $this;
5224
    }
5225
5226
    /**
5227
     * Tests whether the given closure retrun something valid for all elements of this array.
5228
     *
5229
     * @param \Closure $closure the predicate
5230
     *
5231
     * @return bool
5232
     *              <p>TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.</p>
5233
     */
5234 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...
5235
    {
5236 1
        foreach ($this->getGenerator() as $key => $value) {
5237 1
            if (!$closure($value, $key)) {
5238 1
                return false;
5239
            }
5240
        }
5241
5242 1
        return true;
5243
    }
5244
5245
    /**
5246
     * Get all values from a array.
5247
     *
5248
     * @return static
5249
     *                <p>(Immutable)</p>
5250
     *
5251
     * @psalm-return static<mixed,T>
5252
     * @psalm-mutation-free
5253
     */
5254 2
    public function values(): self
5255
    {
5256 2
        return static::create(
5257
            function () {
5258
                /** @noinspection YieldFromCanBeUsedInspection */
5259 2
                foreach ($this->getGenerator() as $value) {
5260 2
                    yield $value;
5261
                }
5262 2
            },
5263 2
            $this->iteratorClass,
5264 2
            false
5265
        );
5266
    }
5267
5268
    /**
5269
     * Apply the given function to every element in the array, discarding the results.
5270
     *
5271
     * @param callable $callable
5272
     * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
5273
     *
5274
     * @return $this
5275
     *               <p>(Mutable) Return this Arrayy object, with modified elements.</p>
5276
     *
5277
     * @psalm-return $this<TKey,T>
5278
     */
5279 12
    public function walk($callable, bool $recursive = false): self
5280
    {
5281 12
        $this->generatorToArray();
5282
5283 12
        if ($recursive === true) {
5284 6
            \array_walk_recursive($this->array, $callable);
5285
        } else {
5286 6
            \array_walk($this->array, $callable);
5287
        }
5288
5289 12
        return $this;
5290
    }
5291
5292
    /**
5293
     * Returns a collection of matching items.
5294
     *
5295
     * @param string $keyOrPropertyOrMethod the property or method to evaluate
5296
     * @param mixed  $value                 the value to match
5297
     *
5298
     * @throws \InvalidArgumentException if property or method is not defined
5299
     *
5300
     * @return static
5301
     *
5302
     * @psalm-param  T $value
5303
     * @psalm-return static<TKey,T>
5304
     */
5305 1
    public function where(string $keyOrPropertyOrMethod, $value): self
5306
    {
5307 1
        return $this->filter(
5308
            function ($item) use ($keyOrPropertyOrMethod, $value) {
5309 1
                $accessorValue = $this->extractValue(
5310 1
                    $item,
5311 1
                    $keyOrPropertyOrMethod
5312
                );
5313
5314 1
                return $accessorValue === $value;
5315 1
            }
5316
        );
5317
    }
5318
5319
    /**
5320
     * Convert an array into a object.
5321
     *
5322
     * @param array $array
5323
     *
5324
     * @return \stdClass
5325
     *
5326
     * @psalm-param array<mixed,mixed> $array
5327
     */
5328 4
    final protected static function arrayToObject(array $array = []): \stdClass
5329
    {
5330
        // init
5331 4
        $object = new \stdClass();
5332
5333 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
5334 1
            return $object;
5335
        }
5336
5337 3
        foreach ($array as $name => $value) {
5338 3
            if (\is_array($value) === true) {
5339 1
                $object->{$name} = static::arrayToObject($value);
5340
            } else {
5341 3
                $object->{$name} = $value;
5342
            }
5343
        }
5344
5345 3
        return $object;
5346
    }
5347
5348
    /**
5349
     * @param array|\Generator|null $input         <p>
5350
     *                                             An array containing keys to return.
5351
     *                                             </p>
5352
     * @param mixed|null            $search_values [optional] <p>
5353
     *                                             If specified, then only keys containing these values are returned.
5354
     *                                             </p>
5355
     * @param bool                  $strict        [optional] <p>
5356
     *                                             Determines if strict comparison (===) should be used during the
5357
     *                                             search.
5358
     *                                             </p>
5359
     *
5360
     * @return array
5361
     *               <p>an array of all the keys in input</p>
5362
     *
5363
     * @psalm-param  array<mixed,mixed>|\Generator<TKey,T>|null $input
5364
     * @psalm-return array<TKey|mixed>
5365
     */
5366 11
    protected function array_keys_recursive(
5367
        $input = null,
5368
        $search_values = null,
5369
        bool $strict = true
5370
    ): array {
5371
        // init
5372 11
        $keys = [];
5373 11
        $keysTmp = [];
5374
5375 11
        if ($input === null) {
5376 4
            $input = $this->getGenerator();
5377
        }
5378
5379 11
        if ($search_values === null) {
5380 11
            foreach ($input as $key => $value) {
5381 11
                $keys[] = $key;
5382
5383
                // check if recursive is needed
5384 11
                if (\is_array($value) === true) {
5385 11
                    $keysTmp[] = $this->array_keys_recursive($value);
5386
                }
5387
            }
5388
        } else {
5389 1
            $is_array_tmp = \is_array($search_values);
5390
5391 1
            foreach ($input as $key => $value) {
5392 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...
5393
                    (
5394 1
                        $is_array_tmp === false
5395
                        &&
5396 1
                        $strict === true
5397
                        &&
5398 1
                        $search_values === $value
5399
                    )
5400
                    ||
5401
                    (
5402 1
                        $is_array_tmp === false
5403
                        &&
5404 1
                        $strict === false
5405
                        &&
5406 1
                        $search_values == $value
5407
                    )
5408
                    ||
5409
                    (
5410 1
                        $is_array_tmp === true
5411
                        &&
5412 1
                        \in_array($value, $search_values, $strict)
5413
                    )
5414
                ) {
5415 1
                    $keys[] = $key;
5416
                }
5417
5418
                // check if recursive is needed
5419 1
                if (\is_array($value) === true) {
5420 1
                    $keysTmp[] = $this->array_keys_recursive($value);
5421
                }
5422
            }
5423
        }
5424
5425 11
        return $keysTmp === [] ? $keys : \array_merge($keys, ...$keysTmp);
5426
    }
5427
5428
    /**
5429
     * @param mixed      $path
5430
     * @param callable   $callable
5431
     * @param array|null $currentOffset
5432
     *
5433
     * @return void
5434
     *
5435
     * @psalm-param array<mixed,mixed>|array<TKey,T>|null $currentOffset
5436
     */
5437 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
5438
    {
5439 4
        $this->generatorToArray();
5440
5441 4
        if ($currentOffset === null) {
5442 4
            $currentOffset = &$this->array;
5443
        }
5444
5445 4
        $explodedPath = \explode($this->pathSeparator, $path);
5446 4
        if ($explodedPath === false) {
5447
            return;
5448
        }
5449
5450 4
        $nextPath = \array_shift($explodedPath);
5451
5452 4
        if (!isset($currentOffset[$nextPath])) {
5453
            return;
5454
        }
5455
5456 4
        if (!empty($explodedPath)) {
5457 1
            $this->callAtPath(
5458 1
                \implode($this->pathSeparator, $explodedPath),
5459 1
                $callable,
5460 1
                $currentOffset[$nextPath]
5461
            );
5462
        } else {
5463 4
            $callable($currentOffset[$nextPath]);
5464
        }
5465 4
    }
5466
5467
    /**
5468
     * Extracts the value of the given property or method from the object.
5469
     *
5470
     * @param static $object                <p>The object to extract the value from.</p>
5471
     * @param string $keyOrPropertyOrMethod <p>The property or method for which the
5472
     *                                      value should be extracted.</p>
5473
     *
5474
     * @throws \InvalidArgumentException if the method or property is not defined
5475
     *
5476
     * @return mixed
5477
     *               <p>The value extracted from the specified property or method.</p>
5478
     *
5479
     * @psalm-param self<TKey,T> $object
5480
     */
5481 2
    final protected function extractValue(self $object, string $keyOrPropertyOrMethod)
5482
    {
5483 2
        if (isset($object[$keyOrPropertyOrMethod])) {
5484 2
            $return = $object->get($keyOrPropertyOrMethod);
5485
5486 2
            if ($return instanceof self) {
5487 1
                return $return->getArray();
5488
            }
5489
5490 1
            return $return;
5491
        }
5492
5493
        if (\property_exists($object, $keyOrPropertyOrMethod)) {
5494
            return $object->{$keyOrPropertyOrMethod};
5495
        }
5496
5497
        if (\method_exists($object, $keyOrPropertyOrMethod)) {
5498
            return $object->{$keyOrPropertyOrMethod}();
5499
        }
5500
5501
        throw new \InvalidArgumentException(\sprintf('array-key & property & method "%s" not defined in %s', $keyOrPropertyOrMethod, \gettype($object)));
5502
    }
5503
5504
    /**
5505
     * create a fallback for array
5506
     *
5507
     * 1. use the current array, if it's a array
5508
     * 2. fallback to empty array, if there is nothing
5509
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
5510
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
5511
     * 5. call "__toArray()" on object, if the method exists
5512
     * 6. cast a string or object with "__toString()" into an array
5513
     * 7. throw a "InvalidArgumentException"-Exception
5514
     *
5515
     * @param mixed $data
5516
     *
5517
     * @throws \InvalidArgumentException
5518
     *
5519
     * @return array
5520
     *
5521
     * @psalm-return array<mixed,mixed>|array<TKey,T>
5522
     */
5523 1066
    protected function fallbackForArray(&$data): array
5524
    {
5525 1066
        $data = $this->internalGetArray($data);
5526
5527 1066
        if ($data === null) {
5528 2
            throw new \InvalidArgumentException('Passed value should be a array');
5529
        }
5530
5531 1064
        return $data;
5532
    }
5533
5534
    /**
5535
     * @return bool
5536
     *
5537
     * @noinspection ReturnTypeCanBeDeclaredInspection
5538
     */
5539 982
    protected function generatorToArray()
5540
    {
5541 982
        if ($this->generator) {
5542 2
            $this->array = $this->getArray();
5543 2
            $this->generator = null;
5544
5545 2
            return true;
5546
        }
5547
5548 982
        return false;
5549
    }
5550
5551
    /**
5552
     * Get correct PHP constant for direction.
5553
     *
5554
     * @param int|string $direction
5555
     *
5556
     * @return int
5557
     */
5558 39
    protected function getDirection($direction): int
5559
    {
5560 39
        if ((string) $direction === $direction) {
5561 10
            $direction = \strtolower($direction);
5562
5563 10
            if ($direction === 'desc') {
5564 2
                $direction = \SORT_DESC;
5565
            } else {
5566 8
                $direction = \SORT_ASC;
5567
            }
5568
        }
5569
5570
        if (
5571 39
            $direction !== \SORT_DESC
5572
            &&
5573 39
            $direction !== \SORT_ASC
5574
        ) {
5575
            $direction = \SORT_ASC;
5576
        }
5577
5578 39
        return $direction;
5579
    }
5580
5581
    /**
5582
     * @return TypeCheckPhpDoc[]
5583
     *
5584
     * @noinspection ReturnTypeCanBeDeclaredInspection
5585
     */
5586 16
    protected function getPropertiesFromPhpDoc()
5587
    {
5588 16
        static $PROPERTY_CACHE = [];
5589 16
        $cacheKey = 'Class::' . static::class;
5590
5591 16
        if (isset($PROPERTY_CACHE[$cacheKey])) {
5592 15
            return $PROPERTY_CACHE[$cacheKey];
5593
        }
5594
5595
        // init
5596 2
        $properties = [];
5597
5598 2
        $reflector = new \ReflectionClass($this);
5599 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
5600 2
        $docComment = $reflector->getDocComment();
5601 2
        if ($docComment) {
5602 2
            $docblock = $factory->create($docComment);
5603
            /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
5604 2
            foreach ($docblock->getTagsByName('property') as $tag) {
5605 2
                $properties[$tag->getVariableName()] = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag);
5606
            }
5607
        }
5608
5609 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
5610
    }
5611
5612
    /**
5613
     * @param mixed $glue
5614
     * @param mixed $pieces
5615
     * @param bool  $useKeys
5616
     *
5617
     * @return string
5618
     */
5619 36
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
5620
    {
5621 36
        if ($pieces instanceof self) {
5622 1
            $pieces = $pieces->getArray();
5623
        }
5624
5625 36
        if (\is_array($pieces) === true) {
5626 36
            $pieces_count = \count($pieces, \COUNT_NORMAL);
5627 36
            $pieces_count_not_zero = $pieces_count > 0;
5628
5629 36
            return \implode(
5630 36
                $glue,
5631 36
                \array_map(
5632 36
                    [$this, 'implode_recursive'],
5633 36
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
5634 36
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
5635
                )
5636
            );
5637
        }
5638
5639
        if (
5640 36
            \is_scalar($pieces) === true
5641
            ||
5642 36
            (\is_object($pieces) && \method_exists($pieces, '__toString'))
5643
        ) {
5644 32
            return (string) $pieces;
5645
        }
5646
5647 8
        return '';
5648
    }
5649
5650
    /**
5651
     * @param mixed                 $needle   <p>
5652
     *                                        The searched value.
5653
     *                                        </p>
5654
     *                                        <p>
5655
     *                                        If needle is a string, the comparison is done
5656
     *                                        in a case-sensitive manner.
5657
     *                                        </p>
5658
     * @param array|\Generator|null $haystack <p>
5659
     *                                        The array.
5660
     *                                        </p>
5661
     * @param bool                  $strict   [optional] <p>
5662
     *                                        If the third parameter strict is set to true
5663
     *                                        then the in_array function will also check the
5664
     *                                        types of the
5665
     *                                        needle in the haystack.
5666
     *                                        </p>
5667
     *
5668
     * @return bool
5669
     *              <p>true if needle is found in the array, false otherwise</p>
5670
     *
5671
     * @psalm-param array<mixed,mixed>|\Generator<TKey,T>|null $haystack
5672
     */
5673 18
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
5674
    {
5675 18
        if ($haystack === null) {
5676
            $haystack = $this->getGenerator();
5677
        }
5678
5679 18
        foreach ($haystack as $item) {
5680 14
            if (\is_array($item) === true) {
5681 3
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
5682
            } else {
5683
                /** @noinspection NestedPositiveIfStatementsInspection */
5684 14
                if ($strict === true) {
5685 14
                    $returnTmp = $item === $needle;
5686
                } else {
5687
                    $returnTmp = $item == $needle;
5688
                }
5689
            }
5690
5691 14
            if ($returnTmp === true) {
5692 14
                return true;
5693
            }
5694
        }
5695
5696 8
        return false;
5697
    }
5698
5699
    /**
5700
     * @param mixed $data
5701
     *
5702
     * @return array|null
5703
     *
5704
     * @psalm-return array<mixed,mixed>|array<TKey,T>|null
5705
     */
5706 1066
    protected function internalGetArray(&$data)
5707
    {
5708 1066
        if (\is_array($data) === true) {
5709 1063
            return $data;
5710
        }
5711
5712 52
        if (!$data) {
5713 6
            return [];
5714
        }
5715
5716 51
        if (\is_object($data) === true) {
5717 46
            if ($data instanceof \ArrayObject) {
5718 4
                return $data->getArrayCopy();
5719
            }
5720
5721 43
            if ($data instanceof \Generator) {
5722
                return static::createFromGeneratorImmutable($data)->getArray();
5723
            }
5724
5725 43
            if ($data instanceof \Traversable) {
5726
                return static::createFromObject($data)->getArray();
5727
            }
5728
5729 43
            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...
5730
                return (array) $data->jsonSerialize();
5731
            }
5732
5733 43
            if (\method_exists($data, '__toArray')) {
5734
                return (array) $data->__toArray();
5735
            }
5736
5737 43
            if (\method_exists($data, '__toString')) {
5738
                return [(string) $data];
5739
            }
5740
        }
5741
5742 48
        if (\is_callable($data)) {
5743 41
            $this->generator = new ArrayyRewindableGenerator($data);
5744
5745 41
            return [];
5746
        }
5747
5748 9
        if (\is_scalar($data)) {
5749 7
            return [$data];
5750
        }
5751
5752 2
        return null;
5753
    }
5754
5755
    /**
5756
     * Internal mechanics of remove method.
5757
     *
5758
     * @param mixed $key
5759
     *
5760
     * @return bool
5761
     */
5762 18
    protected function internalRemove($key): bool
5763
    {
5764 18
        $this->generatorToArray();
5765
5766
        if (
5767 18
            $this->pathSeparator
5768
            &&
5769 18
            (string) $key === $key
5770
            &&
5771 18
            \strpos($key, $this->pathSeparator) !== false
5772
        ) {
5773
            $path = \explode($this->pathSeparator, (string) $key);
5774
5775
            if ($path !== false) {
5776
                // crawl though the keys
5777
                while (\count($path, \COUNT_NORMAL) > 1) {
5778
                    $key = \array_shift($path);
5779
5780
                    if (!$this->has($key)) {
5781
                        return false;
5782
                    }
5783
5784
                    $this->array = &$this->array[$key];
5785
                }
5786
5787
                $key = \array_shift($path);
5788
            }
5789
        }
5790
5791 18
        unset($this->array[$key]);
5792
5793 18
        return true;
5794
    }
5795
5796
    /**
5797
     * Internal mechanic of set method.
5798
     *
5799
     * @param int|string|null $key
5800
     * @param mixed           $value
5801
     * @param bool            $checkProperties
5802
     *
5803
     * @return bool
5804
     */
5805 938
    protected function internalSet(
5806
        $key,
5807
        &$value,
5808
        bool $checkProperties = true
5809
    ): bool {
5810
        if (
5811 938
            $checkProperties === true
5812
            &&
5813 938
            $this->properties !== []
5814
        ) {
5815 87
            $this->checkType($key, $value);
5816
        }
5817
5818 936
        if ($key === null) {
5819
            return false;
5820
        }
5821
5822 936
        $this->generatorToArray();
5823
5824 936
        $array = &$this->array;
5825
5826
        if (
5827 936
            $this->pathSeparator
5828
            &&
5829 936
            (string) $key === $key
5830
            &&
5831 936
            \strpos($key, $this->pathSeparator) !== false
5832
        ) {
5833 3
            $path = \explode($this->pathSeparator, (string) $key);
5834
5835 3
            if ($path !== false) {
5836
                // crawl through the keys
5837 3
                while (\count($path, \COUNT_NORMAL) > 1) {
5838 3
                    $key = \array_shift($path);
5839
5840 3
                    $array = &$array[$key];
5841
                }
5842
5843 3
                $key = \array_shift($path);
5844
            }
5845
        }
5846
5847 936
        $array[$key] = $value;
5848
5849 936
        return true;
5850
    }
5851
5852
    /**
5853
     * Convert a object into an array.
5854
     *
5855
     * @param object $object
5856
     *
5857
     * @return mixed
5858
     */
5859 5
    protected static function objectToArray($object)
5860
    {
5861 5
        if (!\is_object($object)) {
5862 4
            return $object;
5863
        }
5864
5865 5
        if (\is_object($object)) {
5866 5
            $object = \get_object_vars($object);
5867
        }
5868
5869 5
        return \array_map(['static', 'objectToArray'], $object);
5870
    }
5871
5872
    /**
5873
     * @param array $data
5874
     * @param bool  $checkPropertiesInConstructor
5875
     *
5876
     * @return void
5877
     *
5878
     * @psalm-param array<mixed,T> $data
5879
     */
5880 1064
    protected function setInitialValuesAndProperties(array &$data, bool $checkPropertiesInConstructor)
5881
    {
5882 1064
        $checkPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
5883
                                        &&
5884 1064
                                        $checkPropertiesInConstructor === true;
5885
5886 1064
        if ($this->properties !== []) {
5887 78
            foreach ($data as $key => &$valueInner) {
5888 78
                $this->internalSet(
5889 78
                    $key,
5890 78
                    $valueInner,
5891 78
                    $checkPropertiesInConstructor
5892
                );
5893
            }
5894
        } else {
5895
            if (
5896 997
                $this->checkPropertyTypes === true
5897
                ||
5898 997
                $checkPropertiesInConstructor === true
5899
            ) {
5900 16
                $this->properties = $this->getPropertiesFromPhpDoc();
5901
            }
5902
5903
            if (
5904 997
                $this->checkPropertiesMismatchInConstructor === true
5905
                &&
5906 997
                \count($data) !== 0
5907
                &&
5908 997
                \count(\array_diff_key($this->properties, $data)) > 0
5909
            ) {
5910 1
                throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($this->properties), true));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'Property mismatch - inp...his->properties), true).

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

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

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

Loading history...
5911
            }
5912
5913 996
            foreach ($data as $key => &$valueInner) {
5914 864
                $this->internalSet(
5915 864
                    $key,
5916 864
                    $valueInner,
5917 864
                    $checkPropertiesInConstructor
5918
                );
5919
            }
5920
        }
5921 1057
    }
5922
5923
    /**
5924
     * sorting keys
5925
     *
5926
     * @param array      $elements
5927
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5928
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5929
     *                              <strong>SORT_NATURAL</strong></p>
5930
     *
5931
     * @return $this
5932
     *               <p>(Mutable) Return this Arrayy object.</p>
5933
     *
5934
     * @psalm-param  array<mixed,mixed>|array<mixed|TKey,T> $elements
5935
     * @psalm-return $this<mixed|TKey,T>
5936
     */
5937 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
5938
    {
5939 18
        $direction = $this->getDirection($direction);
5940
5941
        switch ($direction) {
5942 18
            case 'desc':
5943 18
            case \SORT_DESC:
5944 6
                \krsort($elements, $strategy);
5945
5946 6
                break;
5947 13
            case 'asc':
5948 13
            case \SORT_ASC:
5949
            default:
5950 13
                \ksort($elements, $strategy);
5951
        }
5952
5953 18
        return $this;
5954
    }
5955
5956
    /**
5957
     * @param array      $elements  <p>Warning: used as reference</p>
5958
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5959
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5960
     *                              <strong>SORT_NATURAL</strong></p>
5961
     * @param bool       $keepKeys
5962
     *
5963
     * @return $this
5964
     *               <p>(Mutable) Return this Arrayy object.</p>
5965
     *
5966
     * @psalm-param  array<mixed> $elements
5967
     * @psalm-return $this<mixed|TKey,T>
5968
     */
5969 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
5970
    {
5971 20
        $direction = $this->getDirection($direction);
5972
5973 20
        if (!$strategy) {
5974 20
            $strategy = \SORT_REGULAR;
5975
        }
5976
5977
        switch ($direction) {
5978 20
            case 'desc':
5979 20
            case \SORT_DESC:
5980 9
                if ($keepKeys) {
5981 5
                    \arsort($elements, $strategy);
5982
                } else {
5983 4
                    \rsort($elements, $strategy);
5984
                }
5985
5986 9
                break;
5987 11
            case 'asc':
5988 11
            case \SORT_ASC:
5989
            default:
5990 11
                if ($keepKeys) {
5991 4
                    \asort($elements, $strategy);
5992
                } else {
5993 7
                    \sort($elements, $strategy);
5994
                }
5995
        }
5996
5997 20
        return $this;
5998
    }
5999
6000
    /**
6001
     * @param int|string|null $key
6002
     * @param mixed           $value
6003
     *
6004
     * @return void
6005
     */
6006 87
    private function checkType($key, $value)
6007
    {
6008
        if (
6009 87
            $key !== null
6010
            &&
6011 87
            isset($this->properties[$key]) === false
6012
            &&
6013 87
            $this->checkPropertiesMismatch === true
6014
        ) {
6015
            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...
6016
        }
6017
6018 87
        if (isset($this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES])) {
6019 76
            $this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES]->checkType($value);
6020 17
        } elseif ($key !== null && isset($this->properties[$key])) {
6021 17
            $this->properties[$key]->checkType($value);
6022
        }
6023 85
    }
6024
}
6025