Completed
Push — master ( f8fd3e...f85948 )
by Lars
01:47 queued 11s
created

Arrayy::moveElementToFirstPlace()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 16
Ratio 100 %

Code Coverage

Tests 10
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 16
loc 16
ccs 10
cts 10
cp 1
crap 2
rs 9.7333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arrayy;
6
7
use Arrayy\Type\TypeInterface;
8
use Arrayy\TypeCheck\TypeCheckArray;
9
use Arrayy\TypeCheck\TypeCheckInterface;
10
use Arrayy\TypeCheck\TypeCheckPhpDoc;
11
12
/**
13
 * Methods to manage arrays.
14
 *
15
 * For the full copyright and license information, please view the LICENSE
16
 * file that was distributed with this source code.
17
 *
18
 * @template TKey of array-key
19
 * @template T
20
 * @template-extends \ArrayObject<TKey,T>
21
 * @template-implements \IteratorAggregate<TKey,T>
22
 * @template-implements \ArrayAccess<TKey,T>
23
 */
24
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \JsonSerializable, \Countable
25
{
26
    const ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES = '!!!!Arrayy_Helper_Types_For_All_Properties!!!!';
27
28
    const ARRAYY_HELPER_WALK = '!!!!Arrayy_Helper_Walk!!!!';
29
30
    /**
31
     * @var array
32
     *
33
     * @phpstan-var array<int|string|TKey,T>
34
     */
35
    protected $array = [];
36
37
    /**
38
     * @var \Arrayy\ArrayyRewindableGenerator|null
39
     *
40
     * @phpstan-var \Arrayy\ArrayyRewindableGenerator<TKey,T>|null
41
     */
42
    protected $generator;
43
44
    /**
45
     * @var string
46
     *
47
     * @phpstan-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>|mixed|TypeCheckArray<int|string,TypeCheckInterface>|TypeInterface
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
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
100
     */
101 1212
    public function __construct(
102
        $data = [],
103
        string $iteratorClass = ArrayyIterator::class,
104
        bool $checkPropertiesInConstructor = true
105
    ) {
106 1212
        $data = $this->fallbackForArray($data);
107
108
        // used only for serialize + unserialize, all other methods are overwritten
109
        /**
110
         * @psalm-suppress InvalidArgument - why?
111
         */
112 1210
        parent::__construct([], 0, $iteratorClass);
113
114 1210
        $this->setInitialValuesAndProperties($data, $checkPropertiesInConstructor);
115
116 1202
        $this->setIteratorClass($iteratorClass);
117 1202
    }
118
119
    /**
120
     * @return void
121
     */
122 52
    public function __clone()
123
    {
124 52
        if (!\is_array($this->properties)) {
125
            $this->properties = clone $this->properties;
0 ignored issues
show
Documentation Bug introduced by
It seems like clone $this->properties of type object is incompatible with the declared type array of property $properties.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

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

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

This assignement can be removed without consequences.

Loading history...
2479
2480
            $generator = function () use ($closure) {
2481 1
                foreach ($this->getGenerator() as $key => $value) {
2482 1
                    if ($closure($key) === true) {
2483 1
                        yield $key => $value;
2484
                    }
2485
                }
2486 1
            };
2487 12
        } elseif ($flag === \ARRAY_FILTER_USE_BOTH) {
2488
            /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
2489
            /** @phpstan-var \Closure(T=,TKey=):bool $closure */
2490 12
            $closure = $closure;
0 ignored issues
show
Bug introduced by
Why assign $closure to itself?

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

This assignement can be removed without consequences.

Loading history...
2491
2492
            $generator = function () use ($closure) {
2493 11
                foreach ($this->getGenerator() as $key => $value) {
2494 10
                    if ($closure($value, $key) === true) {
2495 10
                        yield $key => $value;
2496
                    }
2497
                }
2498 12
            };
2499
        } else {
2500
            /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
2501
            /** @phpstan-var \Closure(T=):bool $closure */
2502 1
            $closure = $closure;
0 ignored issues
show
Bug introduced by
Why assign $closure to itself?

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

This assignement can be removed without consequences.

Loading history...
2503
2504
            $generator = function () use ($closure) {
2505 1
                foreach ($this->getGenerator() as $key => $value) {
2506 1
                    if ($closure($value) === true) {
2507 1
                        yield $key => $value;
2508
                    }
2509
                }
2510 1
            };
2511
        }
2512
2513 12
        return static::create(
2514 12
            $generator,
2515 12
            $this->iteratorClass,
2516 12
            false
2517
        );
2518
    }
2519
2520
    /**
2521
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
2522
     * property within that.
2523
     *
2524
     * @param string      $property
2525
     * @param mixed       $value
2526
     * @param string|null $comparisonOp
2527
     *                                  <p>
2528
     *                                  'eq' (equals),<br />
2529
     *                                  'gt' (greater),<br />
2530
     *                                  'gte' || 'ge' (greater or equals),<br />
2531
     *                                  'lt' (less),<br />
2532
     *                                  'lte' || 'le' (less or equals),<br />
2533
     *                                  'ne' (not equals),<br />
2534
     *                                  'contains',<br />
2535
     *                                  'notContains',<br />
2536
     *                                  'newer' (via strtotime),<br />
2537
     *                                  'older' (via strtotime),<br />
2538
     *                                  </p>
2539
     *
2540
     * @return static
2541
     *                <p>(Immutable)</p>
2542
     *
2543
     * @phpstan-param mixed|T $value
2544
     * @phpstan-return static<TKey,T>
2545
     * @psalm-mutation-free
2546
     *
2547
     * @psalm-suppress MissingClosureReturnType
2548
     * @psalm-suppress MissingClosureParamType
2549
     */
2550 1
    public function filterBy(
2551
        string $property,
2552
        $value,
2553
        string $comparisonOp = null
2554
    ): self {
2555 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...
2556 1
            $comparisonOp = \is_array($value) ? 'contains' : 'eq';
2557
        }
2558
2559
        $ops = [
2560
            'eq' => static function ($item, $prop, $value): bool {
2561 1
                return $item[$prop] === $value;
2562 1
            },
2563
            'gt' => static function ($item, $prop, $value): bool {
2564
                return $item[$prop] > $value;
2565 1
            },
2566
            'ge' => static function ($item, $prop, $value): bool {
2567
                return $item[$prop] >= $value;
2568 1
            },
2569
            'gte' => static function ($item, $prop, $value): bool {
2570
                return $item[$prop] >= $value;
2571 1
            },
2572
            'lt' => static function ($item, $prop, $value): bool {
2573 1
                return $item[$prop] < $value;
2574 1
            },
2575
            'le' => static function ($item, $prop, $value): bool {
2576
                return $item[$prop] <= $value;
2577 1
            },
2578
            'lte' => static function ($item, $prop, $value): bool {
2579
                return $item[$prop] <= $value;
2580 1
            },
2581
            'ne' => static function ($item, $prop, $value): bool {
2582
                return $item[$prop] !== $value;
2583 1
            },
2584
            'contains' => static function ($item, $prop, $value): bool {
2585 1
                return \in_array($item[$prop], (array) $value, true);
2586 1
            },
2587
            'notContains' => static function ($item, $prop, $value): bool {
2588
                return !\in_array($item[$prop], (array) $value, true);
2589 1
            },
2590
            'newer' => static function ($item, $prop, $value): bool {
2591
                return \strtotime($item[$prop]) > \strtotime($value);
2592 1
            },
2593
            'older' => static function ($item, $prop, $value): bool {
2594
                return \strtotime($item[$prop]) < \strtotime($value);
2595 1
            },
2596
        ];
2597
2598 1
        $result = \array_values(
2599 1
            \array_filter(
2600 1
                $this->toArray(false, true),
2601
                static function ($item) use (
2602 1
                    $property,
2603 1
                    $value,
2604 1
                    $ops,
2605 1
                    $comparisonOp
2606
                ) {
2607 1
                    $item = (array) $item;
2608 1
                    $itemArrayy = static::create($item);
2609 1
                    $item[$property] = $itemArrayy->get($property, []);
2610
2611 1
                    return $ops[$comparisonOp]($item, $property, $value);
2612 1
                }
2613
            )
2614
        );
2615
2616 1
        return static::create(
2617 1
            $result,
2618 1
            $this->iteratorClass,
2619 1
            false
2620
        );
2621
    }
2622
2623
    /**
2624
     * Find the first item in an array that passes the truth test, otherwise return false.
2625
     *
2626
     * EXAMPLE: <code>
2627
     * $search = 'foo';
2628
     * $closure = function ($value, $key) use ($search) {
2629
     *     return $value === $search;
2630
     * };
2631
     * a(['foo', 'bar', 'lall'])->find($closure); // 'foo'
2632
     * </code>
2633
     *
2634
     * @param \Closure $closure
2635
     *
2636
     * @return false|mixed
2637
     *                     <p>Return false if we did not find the value.</p>
2638
     *
2639
     * @phpstan-param \Closure(T=,TKey=):bool $closure
2640
     * @phpstan-return T|false
2641
     */
2642 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...
2643
    {
2644 8
        foreach ($this->getGenerator() as $key => $value) {
2645 6
            if ($closure($value, $key)) {
2646 6
                return $value;
2647
            }
2648
        }
2649
2650 3
        return false;
2651
    }
2652
2653
    /**
2654
     * find by ...
2655
     *
2656
     * EXAMPLE: <code>
2657
     * $array = [
2658
     *     0 => ['id' => 123, 'name' => 'foo', 'group' => 'primary', 'value' => 123456, 'when' => '2014-01-01'],
2659
     *     1 => ['id' => 456, 'name' => 'bar', 'group' => 'primary', 'value' => 1468, 'when' => '2014-07-15'],
2660
     * ];
2661
     * a($array)->filterBy('name', 'foo'); // Arrayy[0 => ['id' => 123, 'name' => 'foo', 'group' => 'primary', 'value' => 123456, 'when' => '2014-01-01']]
2662
     * </code>
2663
     *
2664
     * @param string $property
2665
     * @param mixed  $value
2666
     * @param string $comparisonOp
2667
     *
2668
     * @return static
2669
     *                <p>(Immutable)</p>
2670
     *
2671
     * @phpstan-param mixed|T $value
2672
     * @phpstan-return static<TKey,T>
2673
     * @psalm-mutation-free
2674
     */
2675 1
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
2676
    {
2677 1
        return $this->filterBy($property, $value, $comparisonOp);
2678
    }
2679
2680
    /**
2681
     * Get the first value from the current array.
2682
     *
2683
     * EXAMPLE: <code>
2684
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->first(); // 'foo'
2685
     * </code>
2686
     *
2687
     * @return mixed|null
2688
     *                    <p>Return null if there wasn't a element.</p>
2689
     *
2690
     * @phpstan-return T|null
2691
     * @psalm-mutation-free
2692
     */
2693 23
    public function first()
2694
    {
2695 23
        $key_first = $this->firstKey();
2696 23
        if ($key_first === null) {
2697 3
            return null;
2698
        }
2699
2700 20
        return $this->get($key_first);
2701
    }
2702
2703
    /**
2704
     * Get the first key from the current array.
2705
     *
2706
     * @return mixed|null
2707
     *                    <p>Return null if there wasn't a element.</p>
2708
     *
2709
     * @psalm-mutation-free
2710
     */
2711 30
    public function firstKey()
2712
    {
2713 30
        $this->generatorToArray();
2714
2715 30
        return \array_key_first($this->array);
2716
    }
2717
2718
    /**
2719
     * Get the first value(s) from the current array.
2720
     * And will return an empty array if there was no first entry.
2721
     *
2722
     * EXAMPLE: <code>
2723
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->firstsImmutable(2); // Arrayy[0 => 'foo', 1 => 'bar']
2724
     * </code>
2725
     *
2726
     * @param int|null $number <p>How many values you will take?</p>
2727
     *
2728
     * @return static
2729
     *                <p>(Immutable)</p>
2730
     *
2731
     * @phpstan-return static<TKey,T>
2732
     * @psalm-mutation-free
2733
     */
2734 37
    public function firstsImmutable(int $number = null): self
2735
    {
2736 37
        $arrayTmp = $this->toArray();
2737
2738 37
        if ($number === null) {
2739 14
            $array = (array) \array_shift($arrayTmp);
2740
        } else {
2741 23
            $array = \array_splice($arrayTmp, 0, $number);
2742
        }
2743
2744 37
        return static::create(
2745 37
            $array,
2746 37
            $this->iteratorClass,
2747 37
            false
2748
        );
2749
    }
2750
2751
    /**
2752
     * Get the first value(s) from the current array.
2753
     * And will return an empty array if there was no first entry.
2754
     *
2755
     * @param int|null $number <p>How many values you will take?</p>
2756
     *
2757
     * @return static
2758
     *                <p>(Immutable)</p>
2759
     *
2760
     * @phpstan-return static<TKey,T>
2761
     * @psalm-mutation-free
2762
     */
2763 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...
2764
    {
2765 3
        $arrayTmp = $this->keys()->toArray();
2766
2767 3
        if ($number === null) {
2768
            $array = (array) \array_shift($arrayTmp);
2769
        } else {
2770 3
            $array = \array_splice($arrayTmp, 0, $number);
2771
        }
2772
2773 3
        return static::create(
2774 3
            $array,
2775 3
            $this->iteratorClass,
2776 3
            false
2777
        );
2778
    }
2779
2780
    /**
2781
     * Get and remove the first value(s) from the current array.
2782
     * And will return an empty array if there was no first entry.
2783
     *
2784
     * EXAMPLE: <code>
2785
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->firstsMutable(); // 'foo'
2786
     * </code>
2787
     *
2788
     * @param int|null $number <p>How many values you will take?</p>
2789
     *
2790
     * @return $this
2791
     *               <p>(Mutable)</p>
2792
     *
2793
     * @phpstan-return static<TKey,T>
2794
     */
2795 34
    public function firstsMutable(int $number = null): self
2796
    {
2797 34
        $this->generatorToArray();
2798
2799 34
        if ($number === null) {
2800 19
            $this->array = (array) \array_shift($this->array);
2801
        } else {
2802 15
            $this->array = \array_splice($this->array, 0, $number);
2803
        }
2804
2805 34
        return $this;
2806
    }
2807
2808
    /**
2809
     * Exchanges all keys with their associated values in an array.
2810
     *
2811
     * EXAMPLE: <code>
2812
     * a([0 => 'foo', 1 => 'bar'])->flip(); // Arrayy['foo' => 0, 'bar' => 1]
2813
     * </code>
2814
     *
2815
     * @return static
2816
     *                <p>(Immutable)</p>
2817
     *
2818
     * @phpstan-return static<array-key,TKey>
2819
     * @psalm-mutation-free
2820
     */
2821 1
    public function flip(): self
2822
    {
2823
        $generator = function (): \Generator {
2824 1
            foreach ($this->getGenerator() as $key => $value) {
2825 1
                yield (string) $value => $key;
2826
            }
2827 1
        };
2828
2829 1
        return static::create(
2830 1
            $generator,
2831 1
            $this->iteratorClass,
2832 1
            false
2833
        );
2834
    }
2835
2836
    /**
2837
     * Get a value from an array (optional using dot-notation).
2838
     *
2839
     * EXAMPLE: <code>
2840
     * $arrayy = a(['user' => ['lastname' => 'Moelleken']]);
2841
     * $arrayy->get('user.lastname'); // 'Moelleken'
2842
     * // ---
2843
     * $arrayy = new A();
2844
     * $arrayy['user'] = ['lastname' => 'Moelleken'];
2845
     * $arrayy['user.firstname'] = 'Lars';
2846
     * $arrayy['user']['lastname']; // Moelleken
2847
     * $arrayy['user.lastname']; // Moelleken
2848
     * $arrayy['user.firstname']; // Lars
2849
     * </code>
2850
     *
2851
     * @param int|string $key            <p>The key to look for.</p>
2852
     * @param mixed      $fallback       <p>Value to fallback to.</p>
2853
     * @param array|null $array          <p>The array to get from, if it's set to "null" we use the current array from the
2854
     *                                   class.</p>
2855
     * @param bool       $useByReference
2856
     *
2857
     * @return mixed|static
2858
     *
2859
     * @phpstan-param array-key $key
2860
     * @phpstan-param array<array-key,mixed>|array<TKey,T> $array
2861
     * @psalm-mutation-free
2862
     */
2863 248
    public function get(
2864
        $key = null,
2865
        $fallback = null,
2866
        array $array = null,
2867
        bool $useByReference = false
2868
    ) {
2869 248
        if ($array === null && $key === null) {
2870 1
            if ($useByReference) {
2871
                return $this;
2872
            }
2873
2874 1
            return clone $this;
2875
        }
2876
2877 248
        if ($array !== null) {
2878 4
            if ($useByReference) {
2879
                $usedArray = &$array;
2880
            } else {
2881 4
                $usedArray = $array;
2882
            }
2883
        } else {
2884 245
            $this->generatorToArray();
2885
2886 245
            if ($useByReference) {
2887 133
                $usedArray = &$this->array;
2888
            } else {
2889 131
                $usedArray = $this->array;
2890
            }
2891
        }
2892
2893 248
        if ($key === null) {
2894 1
            return static::create(
2895 1
                [],
2896 1
                $this->iteratorClass,
2897 1
                false
2898 1
            )->createByReference($usedArray);
2899
        }
2900
2901
        // php cast "bool"-index into "int"-index
2902
        /** @phpstan-ignore-next-line | this is only a fallback */
2903 248
        if ((bool) $key === $key) {
2904 3
            $key = (int) $key;
2905
        }
2906
2907 248
        if (\array_key_exists($key, $usedArray) === true) {
2908 210
            if (\is_array($usedArray[$key])) {
2909 19
                return static::create(
2910 19
                    [],
2911 19
                    $this->iteratorClass,
2912 19
                    false
2913 19
                )->createByReference($usedArray[$key]);
2914
            }
2915
2916 196
            return $usedArray[$key];
2917
        }
2918
2919
        // crawl through array, get key according to object or not
2920 61
        $usePath = false;
2921
        if (
2922 61
            $this->pathSeparator
2923
            &&
2924 61
            (string) $key === $key
2925
            &&
2926 61
            \strpos($key, $this->pathSeparator) !== false
2927
        ) {
2928 31
            $segments = \explode($this->pathSeparator, (string) $key);
2929 31
            if ($segments !== false) {
2930 31
                $usePath = true;
2931 31
                $usedArrayTmp = $usedArray; // do not use the reference for dot-annotations
2932
2933 31
                foreach ($segments as $segment) {
2934
                    if (
2935
                        (
2936 31
                            \is_array($usedArrayTmp)
2937
                            ||
2938 31
                            $usedArrayTmp instanceof \ArrayAccess
2939
                        )
2940
                        &&
2941 31
                        isset($usedArrayTmp[$segment])
2942
                    ) {
2943 30
                        $usedArrayTmp = $usedArrayTmp[$segment];
2944
2945 30
                        continue;
2946
                    }
2947
2948
                    if (
2949 14
                        \is_object($usedArrayTmp) === true
2950
                        &&
2951 14
                        \property_exists($usedArrayTmp, $segment)
2952
                    ) {
2953 1
                        $usedArrayTmp = $usedArrayTmp->{$segment};
2954
2955 1
                        continue;
2956
                    }
2957
2958 13
                    if (isset($segments[0]) && $segments[0] === '*') {
2959 1
                        $segmentsTmp = $segments;
2960 1
                        unset($segmentsTmp[0]);
2961 1
                        $keyTmp = \implode('.', $segmentsTmp);
2962 1
                        $returnTmp = static::create(
2963 1
                            [],
2964 1
                            $this->iteratorClass,
2965 1
                            false
2966
                        );
2967 1
                        foreach ($this->getAll() as $dataTmp) {
2968 1
                            if ($dataTmp instanceof self) {
2969
                                $returnTmp->add($dataTmp->get($keyTmp));
2970
2971
                                continue;
2972
                            }
2973
2974
                            if (
2975
                                (
2976 1
                                    \is_array($dataTmp)
2977
                                    ||
2978 1
                                    $dataTmp instanceof \ArrayAccess
2979
                                )
2980
                                &&
2981 1
                                isset($dataTmp[$keyTmp])
2982
                            ) {
2983
                                $returnTmp->add($dataTmp[$keyTmp]);
2984
2985
                                continue;
2986
                            }
2987
2988
                            if (
2989 1
                                \is_object($dataTmp) === true
2990
                                &&
2991 1
                                \property_exists($dataTmp, $keyTmp)
2992
                            ) {
2993 1
                                $returnTmp->add($dataTmp->{$keyTmp});
2994
2995
                                /** @noinspection UnnecessaryContinueInspection */
2996 1
                                continue;
2997
                            }
2998
                        }
2999
3000 1
                        if ($returnTmp->count() > 0) {
3001 1
                            return $returnTmp;
3002
                        }
3003
                    }
3004
3005 12
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
3006
                }
3007
            }
3008
        }
3009
3010 58
        if (isset($usedArrayTmp)) {
3011 28 View Code Duplication
            if (!$usePath && !isset($usedArrayTmp[$key])) {
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...
3012
                return $fallback instanceof \Closure ? $fallback() : $fallback;
3013
            }
3014
3015 28
            if (\is_array($usedArrayTmp)) {
3016 6
                return static::create(
3017 6
                    [],
3018 6
                    $this->iteratorClass,
3019 6
                    false
3020 6
                )->createByReference($usedArrayTmp);
3021
            }
3022
3023 28
            return $usedArrayTmp;
3024
        }
3025
3026 30 View Code Duplication
        if (!$usePath && !isset($usedArray[$key])) {
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...
3027 30
            return $fallback instanceof \Closure ? $fallback() : $fallback;
3028
        }
3029
3030
        return static::create(
3031
            [],
3032
            $this->iteratorClass,
3033
            false
3034
        )->createByReference($usedArray);
3035
    }
3036
3037
    /**
3038
     * alias: for "Arrayy->toArray()"
3039
     *
3040
     * @return array
3041
     *
3042
     * @see          Arrayy::getArray()
3043
     *
3044
     * @phpstan-return array<TKey,T>
3045
     */
3046 15
    public function getAll(): array
3047
    {
3048 15
        return $this->toArray();
3049
    }
3050
3051
    /**
3052
     * Get the current array from the "Arrayy"-object.
3053
     *
3054
     * alias for "toArray()"
3055
     *
3056
     * @param bool $convertAllArrayyElements <p>
3057
     *                                       Convert all Child-"Arrayy" objects also to arrays.
3058
     *                                       </p>
3059
     * @param bool $preserveKeys             <p>
3060
     *                                       e.g.: A generator maybe return the same key more then once,
3061
     *                                       so maybe you will ignore the keys.
3062
     *                                       </p>
3063
     *
3064
     * @return array
3065
     *
3066
     * @phpstan-return array<TKey,T>
3067
     * @psalm-mutation-free
3068
     *
3069
     * @see Arrayy::toArray()
3070
     */
3071 512
    public function getArray(
3072
        bool $convertAllArrayyElements = false,
3073
        bool $preserveKeys = true
3074
    ): array {
3075 512
        return $this->toArray(
3076 512
            $convertAllArrayyElements,
3077 512
            $preserveKeys
3078
        );
3079
    }
3080
3081
    /**
3082
     * @param string $json
3083
     *
3084
     * @return $this
3085
     */
3086 3
    public static function createFromJsonMapper(string $json)
3087
    {
3088
        // init
3089 3
        $class = static::create();
3090
3091 3
        $jsonObject = \json_decode($json, false);
3092
3093 3
        $mapper = new \Arrayy\Mapper\Json();
3094 View Code Duplication
        $mapper->undefinedPropertyHandler = static function ($object, $key, $jsonValue) use ($class) {
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...
3095
            if ($class->checkPropertiesMismatchInConstructor) {
3096
                throw new \TypeError('Property mismatch - input: ' . \print_r(['key' => $key, 'jsonValue' => $jsonValue], true) . ' for object: ' . \get_class($object));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'Property mismatch - inp...' . \get_class($object).

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...
3097
            }
3098
        };
3099
3100 3
        return $mapper->map($jsonObject, $class);
3101
    }
3102
3103
    /**
3104
     * @return array<int|string,TypeCheckInterface>|mixed|TypeCheckArray<int|string,TypeCheckInterface>|TypeInterface
0 ignored issues
show
Documentation introduced by
The doc-type array<int|string,TypeChe...nterface>|TypeInterface could not be parsed: Expected "|" or "end of type", but got "<" at position 57. (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...
3105
     *
3106
     * @internal
3107
     */
3108 6
    public function getPhpDocPropertiesFromClass()
3109
    {
3110 6
        if ($this->properties === []) {
3111 1
            $this->properties = $this->getPropertiesFromPhpDoc();
3112
        }
3113
3114 6
        return $this->properties;
3115
    }
3116
3117
    /**
3118
     * Get the current array from the "Arrayy"-object as list.
3119
     *
3120
     * alias for "toList()"
3121
     *
3122
     * @param bool $convertAllArrayyElements <p>
3123
     *                                       Convert all Child-"Arrayy" objects also to arrays.
3124
     *                                       </p>
3125
     *
3126
     * @return array
3127
     *
3128
     * @phpstan-return list<mixed>|list<T>
3129
     * @psalm-mutation-free
3130
     *
3131
     * @see Arrayy::toList()
3132
     */
3133 1
    public function getList(bool $convertAllArrayyElements = false): array
3134
    {
3135 1
        return $this->toList($convertAllArrayyElements);
3136
    }
3137
3138
    /**
3139
     * Returns the values from a single column of the input array, identified by
3140
     * the $columnKey, can be used to extract data-columns from multi-arrays.
3141
     *
3142
     * EXAMPLE: <code>
3143
     * a([['foo' => 'bar', 'id' => 1], ['foo => 'lall', 'id' => 2]])->getColumn('foo', 'id'); // Arrayy[1 => 'bar', 2 => 'lall']
3144
     * </code>
3145
     *
3146
     * INFO: Optionally, you may provide an $indexKey to index the values in the returned
3147
     *       array by the values from the $indexKey column in the input array.
3148
     *
3149
     * @param int|string|null $columnKey
3150
     * @param int|string|null $indexKey
3151
     *
3152
     * @return static
3153
     *                <p>(Immutable)</p>
3154
     *
3155
     * @phpstan-return static<TKey,T>
3156
     * @psalm-mutation-free
3157
     */
3158 1
    public function getColumn($columnKey = null, $indexKey = null): self
3159
    {
3160 1
        if ($columnKey === null && $indexKey === null) {
3161
            $generator = function () {
3162 1
                foreach ($this->getGenerator() as $key => $value) {
3163 1
                    yield $value;
3164
                }
3165 1
            };
3166
        } else {
3167
            $generator = function () use ($columnKey, $indexKey) {
3168 1
                foreach ($this->getGenerator() as $key => $value) {
3169
                    // reset
3170 1
                    $newKey = null;
3171 1
                    $newValue = null;
3172 1
                    $newValueFound = false;
3173
3174 1
                    if ($indexKey !== null) {
3175 1
                        foreach ($value as $keyInner => $valueInner) {
3176 1
                            if ($indexKey === $keyInner) {
3177 1
                                $newKey = $valueInner;
3178
                            }
3179
3180 1
                            if ($columnKey === $keyInner) {
3181 1
                                $newValue = $valueInner;
3182 1
                                $newValueFound = true;
3183
                            }
3184
                        }
3185
                    } else {
3186 1
                        foreach ($value as $keyInner => $valueInner) {
3187 1
                            if ($columnKey === $keyInner) {
3188 1
                                $newValue = $valueInner;
3189 1
                                $newValueFound = true;
3190
                            }
3191
                        }
3192
                    }
3193
3194 1
                    if ($newValueFound === false) {
3195 1
                        if ($newKey !== null) {
3196 1
                            yield $newKey => $value;
3197
                        } else {
3198 1
                            yield $value;
3199
                        }
3200
                    } else {
3201
                        /** @noinspection NestedPositiveIfStatementsInspection */
3202 1
                        if ($newKey !== null) {
3203 1
                            yield $newKey => $newValue;
3204
                        } else {
3205 1
                            yield $newValue;
3206
                        }
3207
                    }
3208
                }
3209 1
            };
3210
        }
3211
3212 1
        return static::create(
3213 1
            $generator,
3214 1
            $this->iteratorClass,
3215 1
            false
3216
        );
3217
    }
3218
3219
    /**
3220
     * Get the current array from the "Arrayy"-object as generator by reference.
3221
     *
3222
     * @return \Generator
3223
     *
3224
     * @phpstan-return \Generator<mixed,T>|\Generator<TKey,T>
3225
     */
3226 75
    public function &getGeneratorByReference(): \Generator
3227
    {
3228 75
        if ($this->generator instanceof ArrayyRewindableGenerator) {
3229
            // -> false-positive -> see "&" from method
3230
            /** @noinspection YieldFromCanBeUsedInspection */
3231 17
            foreach ($this->generator as $key => $value) {
3232 17
                yield $key => $value;
3233
            }
3234
3235 5
            return;
3236
        }
3237
3238
        // -> false-positive -> see "&$value"
3239
        /** @noinspection YieldFromCanBeUsedInspection */
3240
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
3241 59
        foreach ($this->array as $key => &$value) {
3242 54
            yield $key => $value;
3243
        }
3244 35
    }
3245
3246
    /**
3247
     * Get the current array from the "Arrayy"-object as generator.
3248
     *
3249
     * @return \Generator
3250
     *
3251
     * @phpstan-return \Generator<mixed,T>|\Generator<TKey,T>
3252
     * @psalm-mutation-free
3253
     */
3254 1072
    public function getGenerator(): \Generator
3255
    {
3256 1072
        if ($this->generator instanceof ArrayyRewindableGenerator) {
3257 77
            yield from $this->generator;
3258
3259 77
            return;
3260
        }
3261
3262 1070
        yield from $this->array;
3263 1029
    }
3264
3265
    /**
3266
     * alias: for "Arrayy->keys()"
3267
     *
3268
     * @return static
3269
     *                <p>(Immutable)</p>
3270
     *
3271
     * @see          Arrayy::keys()
3272
     *
3273
     * @phpstan-return static<int,TKey>
3274
     * @psalm-mutation-free
3275
     */
3276 2
    public function getKeys()
3277
    {
3278 2
        return $this->keys();
3279
    }
3280
3281
    /**
3282
     * Get the current array from the "Arrayy"-object as object.
3283
     *
3284
     * @return \stdClass
3285
     */
3286 4
    public function getObject(): \stdClass
3287
    {
3288 4
        return self::arrayToObject($this->toArray());
3289
    }
3290
3291
    /**
3292
     * alias: for "Arrayy->randomImmutable()"
3293
     *
3294
     * @return static
3295
     *                <p>(Immutable)</p>
3296
     *
3297
     * @see          Arrayy::randomImmutable()
3298
     *
3299
     * @phpstan-return static<int|array-key,T>
3300
     */
3301 4
    public function getRandom(): self
3302
    {
3303 4
        return $this->randomImmutable();
3304
    }
3305
3306
    /**
3307
     * alias: for "Arrayy->randomKey()"
3308
     *
3309
     * @return mixed
3310
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
3311
     *
3312
     * @see Arrayy::randomKey()
3313
     */
3314 3
    public function getRandomKey()
3315
    {
3316 3
        return $this->randomKey();
3317
    }
3318
3319
    /**
3320
     * alias: for "Arrayy->randomKeys()"
3321
     *
3322
     * @param int $number
3323
     *
3324
     * @return static
3325
     *                <p>(Immutable)</p>
3326
     *
3327
     * @see          Arrayy::randomKeys()
3328
     *
3329
     * @phpstan-return static<TKey,T>
3330
     */
3331 8
    public function getRandomKeys(int $number): self
3332
    {
3333 8
        return $this->randomKeys($number);
3334
    }
3335
3336
    /**
3337
     * alias: for "Arrayy->randomValue()"
3338
     *
3339
     * @return mixed
3340
     *               <p>Get a random value or null if there wasn't a value.</p>
3341
     *
3342
     * @see Arrayy::randomValue()
3343
     */
3344 3
    public function getRandomValue()
3345
    {
3346 3
        return $this->randomValue();
3347
    }
3348
3349
    /**
3350
     * alias: for "Arrayy->randomValues()"
3351
     *
3352
     * @param int $number
3353
     *
3354
     * @return static
3355
     *                <p>(Immutable)</p>
3356
     *
3357
     * @see          Arrayy::randomValues()
3358
     *
3359
     * @phpstan-return static<TKey,T>
3360
     */
3361 6
    public function getRandomValues(int $number): self
3362
    {
3363 6
        return $this->randomValues($number);
3364
    }
3365
3366
    /**
3367
     * Gets all values.
3368
     *
3369
     * @return static
3370
     *                <p>The values of all elements in this array, in the order they
3371
     *                appear in the array.</p>
3372
     *
3373
     * @phpstan-return static<TKey,T>
3374
     */
3375 4
    public function getValues()
3376
    {
3377 4
        $this->generatorToArray(false);
3378
3379 4
        return static::create(
3380 4
            \array_values($this->array),
3381 4
            $this->iteratorClass,
3382 4
            false
3383
        );
3384
    }
3385
3386
    /**
3387
     * Gets all values via Generator.
3388
     *
3389
     * @return \Generator
3390
     *                    <p>The values of all elements in this array, in the order they
3391
     *                    appear in the array as Generator.</p>
3392
     *
3393
     * @phpstan-return \Generator<TKey,T>
3394
     */
3395 4
    public function getValuesYield(): \Generator
3396
    {
3397 4
        yield from $this->getGenerator();
3398 4
    }
3399
3400
    /**
3401
     * Group values from a array according to the results of a closure.
3402
     *
3403
     * @param callable|string $grouper  <p>A callable function name.</p>
3404
     * @param bool            $saveKeys
3405
     *
3406
     * @return static
3407
     *                <p>(Immutable)</p>
3408
     *
3409
     * @phpstan-return static<TKey,T>
3410
     * @psalm-mutation-free
3411
     */
3412 4
    public function group($grouper, bool $saveKeys = false): self
3413
    {
3414
        // init
3415 4
        $result = [];
3416
3417
        // Iterate over values, group by property/results from closure.
3418 4
        foreach ($this->getGenerator() as $key => $value) {
3419 4
            if (\is_callable($grouper) === true) {
3420 3
                $groupKey = $grouper($value, $key);
3421
            } else {
3422 1
                $groupKey = $this->get($grouper);
3423
            }
3424
3425 4
            $newValue = $this->get($groupKey, null, $result);
3426
3427 4
            if ($groupKey instanceof self) {
3428
                $groupKey = $groupKey->toArray();
3429
            }
3430
3431 4
            if ($newValue instanceof self) {
3432 4
                $newValue = $newValue->toArray();
3433
            }
3434
3435
            // Add to results.
3436 4
            if ($groupKey !== null) {
3437 3
                if ($saveKeys) {
3438 2
                    $result[$groupKey] = $newValue;
3439 2
                    $result[$groupKey][$key] = $value;
3440
                } else {
3441 1
                    $result[$groupKey] = $newValue;
3442 4
                    $result[$groupKey][] = $value;
3443
                }
3444
            }
3445
        }
3446
3447 4
        return static::create(
3448 4
            $result,
3449 4
            $this->iteratorClass,
3450 4
            false
3451
        );
3452
    }
3453
3454
    /**
3455
     * Check if an array has a given key.
3456
     *
3457
     * @param mixed $key
3458
     *
3459
     * @return bool
3460
     */
3461 30
    public function has($key): bool
3462
    {
3463 30
        static $UN_FOUND = null;
3464
3465 30
        if ($UN_FOUND === null) {
3466
            // Generate unique string to use as marker.
3467 1
            $UN_FOUND = 'arrayy--' . \uniqid('arrayy', true);
3468
        }
3469
3470 30
        if (\is_array($key)) {
3471 1
            if ($key === []) {
3472
                return false;
3473
            }
3474
3475 1
            foreach ($key as $keyTmp) {
3476 1
                $found = ($this->get($keyTmp, $UN_FOUND) !== $UN_FOUND);
3477 1
                if ($found === false) {
3478 1
                    return false;
3479
                }
3480
            }
3481
3482 1
            return true;
3483
        }
3484
3485 29
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
3486
    }
3487
3488
    /**
3489
     * Check if an array has a given value.
3490
     *
3491
     * INFO: If you need to search recursive please use ```contains($value, true)```.
3492
     *
3493
     * @param mixed $value
3494
     *
3495
     * @return bool
3496
     */
3497 1
    public function hasValue($value): bool
3498
    {
3499 1
        return $this->contains($value);
3500
    }
3501
3502
    /**
3503
     * Implodes the values of this array.
3504
     *
3505
     * EXAMPLE: <code>
3506
     * a([0 => -9, 1, 2])->implode('|'); // '-9|1|2'
3507
     * </code>
3508
     *
3509
     * @param string $glue
3510
     * @param string $prefix
3511
     *
3512
     * @return string
3513
     * @psalm-mutation-free
3514
     */
3515 28
    public function implode(string $glue = '', string $prefix = ''): string
3516
    {
3517 28
        return $prefix . $this->implode_recursive($glue, $this->toArray(), false);
3518
    }
3519
3520
    /**
3521
     * Implodes the keys of this array.
3522
     *
3523
     * @param string $glue
3524
     *
3525
     * @return string
3526
     * @psalm-mutation-free
3527
     */
3528 8
    public function implodeKeys(string $glue = ''): string
3529
    {
3530 8
        return $this->implode_recursive($glue, $this->toArray(), true);
3531
    }
3532
3533
    /**
3534
     * Given a list and an iterate-function that returns
3535
     * a key for each element in the list (or a property name),
3536
     * returns an object with an index of each item.
3537
     *
3538
     * @param mixed $key
3539
     *
3540
     * @return static
3541
     *                <p>(Immutable)</p>
3542
     *
3543
     * @phpstan-return static<TKey,T>
3544
     * @psalm-mutation-free
3545
     */
3546 4 View Code Duplication
    public function indexBy($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...
3547
    {
3548
        // init
3549 4
        $results = [];
3550
3551 4
        foreach ($this->getGenerator() as $a) {
3552 4
            if (\array_key_exists($key, $a) === true) {
3553 4
                $results[$a[$key]] = $a;
3554
            }
3555
        }
3556
3557 4
        return static::create(
3558 4
            $results,
3559 4
            $this->iteratorClass,
3560 4
            false
3561
        );
3562
    }
3563
3564
    /**
3565
     * alias: for "Arrayy->searchIndex()"
3566
     *
3567
     * @param mixed $value <p>The value to search for.</p>
3568
     *
3569
     * @return false|mixed
3570
     *
3571
     * @see Arrayy::searchIndex()
3572
     */
3573 4
    public function indexOf($value)
3574
    {
3575 4
        return $this->searchIndex($value);
3576
    }
3577
3578
    /**
3579
     * Get everything but the last..$to items.
3580
     *
3581
     * EXAMPLE: <code>
3582
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->initial(2); // Arrayy[0 => 'foo']
3583
     * </code>
3584
     *
3585
     * @param int $to
3586
     *
3587
     * @return static
3588
     *                <p>(Immutable)</p>
3589
     *
3590
     * @phpstan-return static<TKey,T>
3591
     * @psalm-mutation-free
3592
     */
3593 12
    public function initial(int $to = 1): self
3594
    {
3595 12
        return $this->firstsImmutable(\count($this->toArray(), \COUNT_NORMAL) - $to);
3596
    }
3597
3598
    /**
3599
     * Return an array with all elements found in input array.
3600
     *
3601
     * EXAMPLE: <code>
3602
     * a(['foo', 'bar'])->intersection(['bar', 'baz']); // Arrayy['bar']
3603
     * </code>
3604
     *
3605
     * @param array $search
3606
     * @param bool  $keepKeys
3607
     *
3608
     * @return static
3609
     *                <p>(Immutable)</p>
3610
     *
3611
     * @phpstan-param  array<TKey,T> $search
3612
     * @phpstan-return static<TKey,T>
3613
     * @psalm-mutation-free
3614
     */
3615 4
    public function intersection(array $search, bool $keepKeys = false): self
3616
    {
3617 4
        if ($keepKeys) {
3618
            /**
3619
             * @psalm-suppress MissingClosureReturnType
3620
             * @psalm-suppress MissingClosureParamType
3621
             */
3622 1
            return static::create(
3623 1
                \array_uintersect(
3624 1
                    $this->toArray(),
3625 1
                    $search,
3626
                    static function ($a, $b) {
3627 1
                        return $a === $b ? 0 : -1;
3628 1
                    }
3629
                ),
3630 1
                $this->iteratorClass,
3631 1
                false
3632
            );
3633
        }
3634
3635 3
        return static::create(
3636 3
            \array_values(\array_intersect($this->toArray(), $search)),
3637 3
            $this->iteratorClass,
3638 3
            false
3639
        );
3640
    }
3641
3642
    /**
3643
     * Return an array with all elements found in input array.
3644
     *
3645
     * @param array ...$array
3646
     *
3647
     * @return static
3648
     *                <p>(Immutable)</p>
3649
     *
3650
     * @phpstan-param  array<array<TKey,T>> ...$array
3651
     * @phpstan-return static<TKey,T>
3652
     * @psalm-mutation-free
3653
     */
3654 1
    public function intersectionMulti(...$array): self
3655
    {
3656 1
        return static::create(
3657 1
            \array_values(\array_intersect($this->toArray(), ...$array)),
3658 1
            $this->iteratorClass,
3659 1
            false
3660
        );
3661
    }
3662
3663
    /**
3664
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
3665
     *
3666
     * EXAMPLE: <code>
3667
     * a(['foo', 'bar'])->intersects(['föö', 'bär']); // false
3668
     * </code>
3669
     *
3670
     * @param array $search
3671
     *
3672
     * @return bool
3673
     *
3674
     * @phpstan-param array<TKey,T> $search
3675
     */
3676 1
    public function intersects(array $search): bool
3677
    {
3678 1
        return $this->intersection($search)->count() > 0;
3679
    }
3680
3681
    /**
3682
     * Invoke a function on all of an array's values.
3683
     *
3684
     * @param callable $callable
3685
     * @param mixed    $arguments
3686
     *
3687
     * @return static
3688
     *                <p>(Immutable)</p>
3689
     *
3690
     * @phpstan-param  callable(T=,mixed):mixed $callable
3691
     * @phpstan-return static<TKey,T>
3692
     * @psalm-mutation-free
3693
     */
3694 1
    public function invoke($callable, $arguments = []): self
3695
    {
3696
        // If one argument given for each iteration, create an array for it.
3697 1
        if (!\is_array($arguments)) {
3698 1
            $arguments = \array_fill(
3699 1
                0,
3700 1
                $this->count(),
3701 1
                $arguments
3702
            );
3703
        }
3704
3705
        // If the callable has arguments, pass them.
3706 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...
3707 1
            $array = \array_map($callable, $this->toArray(), $arguments);
3708
        } else {
3709 1
            $array = $this->map($callable);
3710
        }
3711
3712 1
        return static::create(
3713 1
            $array,
3714 1
            $this->iteratorClass,
3715 1
            false
3716
        );
3717
    }
3718
3719
    /**
3720
     * Check whether array is associative or not.
3721
     *
3722
     * EXAMPLE: <code>
3723
     * a(['foo' => 'bar', 2, 3])->isAssoc(); // true
3724
     * </code>
3725
     *
3726
     * @param bool $recursive
3727
     *
3728
     * @return bool
3729
     *              <p>Returns true if associative, false otherwise.</p>
3730
     */
3731 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...
3732
    {
3733 15
        if ($this->isEmpty()) {
3734 3
            return false;
3735
        }
3736
3737
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
3738 13
        foreach ($this->keys($recursive)->getGeneratorByReference() as &$key) {
3739 13
            if ((string) $key !== $key) {
3740 13
                return false;
3741
            }
3742
        }
3743
3744 3
        return true;
3745
    }
3746
3747
    /**
3748
     * Check if a given key or keys are empty.
3749
     *
3750
     * @param int|int[]|string|string[]|null $keys
3751
     *
3752
     * @return bool
3753
     *              <p>Returns true if empty, false otherwise.</p>
3754
     * @psalm-mutation-free
3755
     */
3756 45
    public function isEmpty($keys = null): bool
3757
    {
3758 45
        if ($this->generator) {
3759
            return $this->toArray() === [];
3760
        }
3761
3762 45
        if ($keys === null) {
3763 43
            return $this->array === [];
3764
        }
3765
3766 2
        foreach ((array) $keys as $key) {
3767 2
            if (!empty($this->get($key))) {
3768 2
                return false;
3769
            }
3770
        }
3771
3772 2
        return true;
3773
    }
3774
3775
    /**
3776
     * Check if the current array is equal to the given "$array" or not.
3777
     *
3778
     * EXAMPLE: <code>
3779
     * a(['💩'])->isEqual(['💩']); // true
3780
     * </code>
3781
     *
3782
     * @param array $array
3783
     *
3784
     * @return bool
3785
     *
3786
     * @phpstan-param array<int|string,mixed> $array
3787
     */
3788 1
    public function isEqual(array $array): bool
3789
    {
3790 1
        return $this->toArray() === $array;
3791
    }
3792
3793
    /**
3794
     * Check if the current array is a multi-array.
3795
     *
3796
     * EXAMPLE: <code>
3797
     * a(['foo' => [1, 2 , 3]])->isMultiArray(); // true
3798
     * </code>
3799
     *
3800
     * @return bool
3801
     */
3802 22
    public function isMultiArray(): bool
3803
    {
3804 22
        foreach ($this->getGenerator() as $key => $value) {
3805 20
            if (\is_array($value)) {
3806 20
                return true;
3807
            }
3808
        }
3809
3810 18
        return false;
3811
    }
3812
3813
    /**
3814
     * Check whether array is numeric or not.
3815
     *
3816
     * @return bool
3817
     *              <p>Returns true if numeric, false otherwise.</p>
3818
     */
3819 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...
3820
    {
3821 5
        if ($this->isEmpty()) {
3822 2
            return false;
3823
        }
3824
3825
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
3826 4
        foreach ($this->keys()->getGeneratorByReference() as &$key) {
3827 4
            if ((int) $key !== $key) {
3828 4
                return false;
3829
            }
3830
        }
3831
3832 2
        return true;
3833
    }
3834
3835
    /**
3836
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
3837
     *
3838
     * EXAMPLE: <code>
3839
     * a([0 => 'foo', 1 => 'lall', 2 => 'foobar'])->isSequential(); // true
3840
     * </code>
3841
     *
3842
     * INFO: If the array is empty we count it as non-sequential.
3843
     *
3844
     * @param bool $recursive
3845
     *
3846
     * @return bool
3847
     * @psalm-mutation-free
3848
     */
3849 10
    public function isSequential(bool $recursive = false): bool
3850
    {
3851 10
        $i = 0;
3852 10
        foreach ($this->getGenerator() as $key => $value) {
3853
            /** @noinspection IsIterableCanBeUsedInspection */
3854
            if (
3855 9
                $recursive
3856
                &&
3857 9
                (\is_array($value) || $value instanceof \Traversable)
3858
                &&
3859 9
                self::create($value)->isSequential() === false
3860
            ) {
3861 1
                return false;
3862
            }
3863
3864 9
            if ($key !== $i) {
3865 3
                return false;
3866
            }
3867
3868 8
            ++$i;
3869
        }
3870
3871
        /** @noinspection IfReturnReturnSimplificationInspection */
3872 9
        if ($i === 0) {
3873 3
            return false;
3874
        }
3875
3876 8
        return true;
3877
    }
3878
3879
    /**
3880
     * @return array
3881
     *
3882
     * @phpstan-return array<TKey,T>
3883
     */
3884 2
    public function jsonSerialize(): array
3885
    {
3886 2
        return $this->toArray();
3887
    }
3888
3889
    /**
3890
     * Gets the key/index of the element at the current internal iterator position.
3891
     *
3892
     * @return int|string|null
3893
     * @phpstan-return array-key|null
3894
     */
3895
    public function key()
3896
    {
3897
        if ($this->generator) {
3898
            return $this->generator->key();
3899
        }
3900
3901
        return \key($this->array);
3902
    }
3903
3904
    /**
3905
     * Checks if the given key exists in the provided array.
3906
     *
3907
     * INFO: This method only use "array_key_exists()" if you want to use "dot"-notation,
3908
     *       then you need to use "Arrayy->offsetExists()".
3909
     *
3910
     * @param int|string $key the key to look for
3911
     *
3912
     * @return bool
3913
     * @psalm-mutation-free
3914
     */
3915 174
    public function keyExists($key): bool
3916
    {
3917 174
        foreach ($this->getGenerator() as $keyTmp => $value) {
3918 169
            if ($key === $keyTmp) {
3919 169
                return true;
3920
            }
3921
        }
3922
3923 131
        return false;
3924
    }
3925
3926
    /**
3927
     * Get all keys from the current array.
3928
     *
3929
     * EXAMPLE: <code>
3930
     * a([1 => 'foo', 2 => 'foo2', 3 => 'bar'])->keys(); // Arrayy[1, 2, 3]
3931
     * </code>
3932
     *
3933
     * @param bool       $recursive     [optional] <p>
3934
     *                                  Get all keys, also from all sub-arrays from an multi-dimensional array.
3935
     *                                  </p>
3936
     * @param mixed|null $search_values [optional] <p>
3937
     *                                  If specified, then only keys containing these values are returned.
3938
     *                                  </p>
3939
     * @param bool       $strict        [optional] <p>
3940
     *                                  Determines if strict comparison (===) should be used during the search.
3941
     *                                  </p>
3942
     *
3943
     * @return static
3944
     *                <p>(Immutable) An array of all the keys in input.</p>
3945
     *
3946
     * @phpstan-return static<int,TKey>
3947
     * @psalm-mutation-free
3948
     */
3949 29
    public function keys(
3950
        bool $recursive = false,
3951
        $search_values = null,
3952
        bool $strict = true
3953
    ): self {
3954
3955
        // recursive
3956
3957 29
        if ($recursive === true) {
3958 4
            $array = $this->array_keys_recursive(
3959 4
                null,
3960 4
                $search_values,
3961 4
                $strict
3962
            );
3963
3964 4
            return static::create(
3965 4
                $array,
3966 4
                $this->iteratorClass,
3967 4
                false
3968
            );
3969
        }
3970
3971
        // non recursive
3972
3973 28
        if ($search_values === null) {
3974
            $arrayFunction = function (): \Generator {
3975 28
                foreach ($this->getGenerator() as $key => $value) {
3976 26
                    yield $key;
3977
                }
3978 28
            };
3979
        } else {
3980
            $arrayFunction = function () use ($search_values, $strict): \Generator {
3981 1
                $is_array_tmp = \is_array($search_values);
3982
3983
                /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
3984 1
                foreach ($this->getGeneratorByReference() as $key => &$value) {
3985 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...
3986
                        (
3987 1
                            $is_array_tmp === false
3988
                            &&
3989 1
                            $strict === true
3990
                            &&
3991 1
                            $search_values === $value
3992
                        )
3993
                        ||
3994
                        (
3995 1
                            $is_array_tmp === false
3996
                            &&
3997 1
                            $strict === false
3998
                            &&
3999 1
                            $search_values == $value
4000
                        )
4001
                        ||
4002
                        (
4003 1
                            $is_array_tmp === true
4004
                            &&
4005 1
                            \in_array($value, $search_values, $strict)
4006
                        )
4007
                    ) {
4008 1
                        yield $key;
4009
                    }
4010
                }
4011 1
            };
4012
        }
4013
4014 28
        return static::create(
4015 28
            $arrayFunction,
4016 28
            $this->iteratorClass,
4017 28
            false
4018
        );
4019
    }
4020
4021
    /**
4022
     * Sort an array by key in reverse order.
4023
     *
4024
     * @param int $sort_flags [optional] <p>
4025
     *                        You may modify the behavior of the sort using the optional
4026
     *                        parameter sort_flags, for details
4027
     *                        see sort.
4028
     *                        </p>
4029
     *
4030
     * @return $this
4031
     *               <p>(Mutable) Return this Arrayy object.</p>
4032
     *
4033
     * @phpstan-return static<TKey,T>
4034
     */
4035 4
    public function krsort(int $sort_flags = 0): self
4036
    {
4037 4
        $this->generatorToArray();
4038
4039 4
        \krsort($this->array, $sort_flags);
4040
4041 4
        return $this;
4042
    }
4043
4044
    /**
4045
     * Sort an array by key in reverse order.
4046
     *
4047
     * @param int $sort_flags [optional] <p>
4048
     *                        You may modify the behavior of the sort using the optional
4049
     *                        parameter sort_flags, for details
4050
     *                        see sort.
4051
     *                        </p>
4052
     *
4053
     * @return $this
4054
     *               <p>(Immutable) Return this Arrayy object.</p>
4055
     *
4056
     * @phpstan-return static<TKey,T>
4057
     * @psalm-mutation-free
4058
     */
4059 4
    public function krsortImmutable(int $sort_flags = 0): self
4060
    {
4061 4
        $that = clone $this;
4062
4063
        /**
4064
         * @psalm-suppress ImpureMethodCall - object is already cloned
4065
         */
4066 4
        $that->krsort($sort_flags);
4067
4068 4
        return $that;
4069
    }
4070
4071
    /**
4072
     * Get the last value from the current array.
4073
     *
4074
     * EXAMPLE: <code>
4075
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->last(); // 'lall'
4076
     * </code>
4077
     *
4078
     * @return mixed|null
4079
     *                    <p>Return null if there wasn't a element.</p>
4080
     *
4081
     * @phpstan-return T|null
4082
     * @psalm-mutation-free
4083
     */
4084 17
    public function last()
4085
    {
4086 17
        $key_last = $this->lastKey();
4087 17
        if ($key_last === null) {
4088 2
            return null;
4089
        }
4090
4091 15
        return $this->get($key_last);
4092
    }
4093
4094
    /**
4095
     * Get the last key from the current array.
4096
     *
4097
     * @return mixed|null
4098
     *                    <p>Return null if there wasn't a element.</p>
4099
     * @psalm-mutation-free
4100
     */
4101 21
    public function lastKey()
4102
    {
4103 21
        $this->generatorToArray();
4104
4105 21
        return \array_key_last($this->array);
4106
    }
4107
4108
    /**
4109
     * Get the last value(s) from the current array.
4110
     *
4111
     * EXAMPLE: <code>
4112
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->lasts(2); // Arrayy[0 => 'bar', 1 => 'lall']
4113
     * </code>
4114
     *
4115
     * @param int|null $number
4116
     *
4117
     * @return static
4118
     *                <p>(Immutable)</p>
4119
     *
4120
     * @phpstan-return static<TKey,T>
4121
     * @psalm-mutation-free
4122
     */
4123 13
    public function lastsImmutable(int $number = null): self
4124
    {
4125 13
        if ($this->isEmpty()) {
4126 1
            return static::create(
4127 1
                [],
4128 1
                $this->iteratorClass,
4129 1
                false
4130
            );
4131
        }
4132
4133 12
        if ($number === null) {
4134 8
            $poppedValue = $this->last();
4135
4136 8
            if ($poppedValue === null) {
4137 1
                $poppedValue = [$poppedValue];
4138
            } else {
4139 7
                $poppedValue = (array) $poppedValue;
4140
            }
4141
4142 8
            $arrayy = static::create(
4143 8
                $poppedValue,
4144 8
                $this->iteratorClass,
4145 8
                false
4146
            );
4147
        } else {
4148 4
            $arrayy = $this->rest(-$number);
4149
        }
4150
4151 12
        return $arrayy;
4152
    }
4153
4154
    /**
4155
     * Get the last value(s) from the current array.
4156
     *
4157
     * EXAMPLE: <code>
4158
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->lasts(2); // Arrayy[0 => 'bar', 1 => 'lall']
4159
     * </code>
4160
     *
4161
     * @param int|null $number
4162
     *
4163
     * @return $this
4164
     *               <p>(Mutable)</p>
4165
     *
4166
     * @phpstan-return static<TKey,T>
4167
     */
4168 13
    public function lastsMutable(int $number = null): self
4169
    {
4170 13
        if ($this->isEmpty()) {
4171 1
            return $this;
4172
        }
4173
4174 12
        $this->array = $this->lastsImmutable($number)->toArray();
4175 12
        $this->generator = null;
4176
4177 12
        return $this;
4178
    }
4179
4180
    /**
4181
     * Count the values from the current array.
4182
     *
4183
     * alias: for "Arrayy->count()"
4184
     *
4185
     * @param int $mode
4186
     *
4187
     * @return int
4188
     *
4189
     * @see Arrayy::count()
4190
     */
4191 20
    public function length(int $mode = \COUNT_NORMAL): int
4192
    {
4193 20
        return $this->count($mode);
4194
    }
4195
4196
    /**
4197
     * Apply the given function to the every element of the array,
4198
     * collecting the results.
4199
     *
4200
     * EXAMPLE: <code>
4201
     * a(['foo', 'Foo'])->map('mb_strtoupper'); // Arrayy['FOO', 'FOO']
4202
     * </code>
4203
     *
4204
     * @param callable $callable
4205
     * @param bool     $useKeyAsSecondParameter
4206
     * @param mixed    ...$arguments
4207
     *
4208
     * @return static
4209
     *                <p>(Immutable) Arrayy object with modified elements.</p>
4210
     *
4211
     * @template T2
4212
     *              <p>The output value type.</p>
4213
     *
4214
     * @phpstan-param callable(T,TKey=,mixed=):T2 $callable
4215
     * @phpstan-return static<TKey,T2>
4216
     * @psalm-mutation-free
4217
     */
4218 6
    public function map(
4219
        callable $callable,
4220
        bool $useKeyAsSecondParameter = false,
4221
        ...$arguments
4222
    ) {
4223
        /**
4224
         * @psalm-suppress ImpureFunctionCall - func_num_args is only used to detect the number of args
4225
         */
4226 6
        $useArguments = \func_num_args() > 2;
4227
4228 6
        return static::create(
4229
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
4230 6
                foreach ($this->getGenerator() as $key => $value) {
4231 5
                    if ($useArguments) {
4232 3
                        if ($useKeyAsSecondParameter) {
4233
                            yield $key => $callable($value, $key, ...$arguments);
4234
                        } else {
4235 3
                            yield $key => $callable($value, ...$arguments);
4236
                        }
4237
                    } else {
4238
                        /** @noinspection NestedPositiveIfStatementsInspection */
4239 5
                        if ($useKeyAsSecondParameter) {
4240
                            yield $key => $callable($value, $key);
4241
                        } else {
4242 5
                            yield $key => $callable($value);
4243
                        }
4244
                    }
4245
                }
4246 6
            },
4247 6
            $this->iteratorClass,
4248 6
            false
4249
        );
4250
    }
4251
4252
    /**
4253
     * Check if all items in current array match a truth test.
4254
     *
4255
     * EXAMPLE: <code>
4256
     * $closure = function ($value, $key) {
4257
     *     return ($value % 2 === 0);
4258
     * };
4259
     * a([2, 4, 8])->matches($closure); // true
4260
     * </code>
4261
     *
4262
     * @param \Closure $closure
4263
     *
4264
     * @return bool
4265
     *
4266
     * @phpstan-param \Closure(T=,TKey=):bool $closure
4267
     */
4268 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...
4269
    {
4270 15
        if ($this->count() === 0) {
4271 2
            return false;
4272
        }
4273
4274 13
        foreach ($this->getGenerator() as $key => $value) {
4275 13
            $value = $closure($value, $key);
4276
4277 13
            if ($value === false) {
4278 13
                return false;
4279
            }
4280
        }
4281
4282 7
        return true;
4283
    }
4284
4285
    /**
4286
     * Check if any item in the current array matches a truth test.
4287
     *
4288
     * EXAMPLE: <code>
4289
     * $closure = function ($value, $key) {
4290
     *     return ($value % 2 === 0);
4291
     * };
4292
     * a([1, 4, 7])->matches($closure); // true
4293
     * </code>
4294
     *
4295
     * @param \Closure $closure
4296
     *
4297
     * @return bool
4298
     *
4299
     * @phpstan-param \Closure(T=,TKey=):bool $closure
4300
     */
4301 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...
4302
    {
4303 14
        if ($this->count() === 0) {
4304 2
            return false;
4305
        }
4306
4307 12
        foreach ($this->getGenerator() as $key => $value) {
4308 12
            $value = $closure($value, $key);
4309
4310 12
            if ($value === true) {
4311 12
                return true;
4312
            }
4313
        }
4314
4315 4
        return false;
4316
    }
4317
4318
    /**
4319
     * Get the max value from an array.
4320
     *
4321
     * EXAMPLE: <code>
4322
     * a([-9, -8, -7, 1.32])->max(); // 1.32
4323
     * </code>
4324
     *
4325
     * @return false|float|int|string
4326
     *                                <p>Will return false if there are no values.</p>
4327
     */
4328 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...
4329
    {
4330 10
        if ($this->count() === 0) {
4331 1
            return false;
4332
        }
4333
4334 9
        $max = false;
4335
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
4336 9
        foreach ($this->getGeneratorByReference() as &$value) {
4337
            if (
4338 9
                $max === false
4339
                ||
4340 9
                $value > $max
4341
            ) {
4342 9
                $max = $value;
4343
            }
4344
        }
4345
4346 9
        return $max;
4347
    }
4348
4349
    /**
4350
     * Merge the new $array into the current array.
4351
     *
4352
     * - keep key,value from the current array, also if the index is in the new $array
4353
     *
4354
     * EXAMPLE: <code>
4355
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
4356
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
4357
     * a($array1)->mergeAppendKeepIndex($array2); // Arrayy[1 => 'one', 'foo' => 'bar2', 3 => 'three']
4358
     * // ---
4359
     * $array1 = [0 => 'one', 1 => 'foo'];
4360
     * $array2 = [0 => 'foo', 1 => 'bar2'];
4361
     * a($array1)->mergeAppendKeepIndex($array2); // Arrayy[0 => 'foo', 1 => 'bar2']
4362
     * </code>
4363
     *
4364
     * @param array $array
4365
     * @param bool  $recursive
4366
     *
4367
     * @return static
4368
     *                <p>(Immutable)</p>
4369
     *
4370
     * @phpstan-param  array<int|TKey,T> $array
4371
     * @phpstan-return static<int|TKey,T>
4372
     * @psalm-mutation-free
4373
     */
4374 33 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...
4375
    {
4376 33
        if ($recursive === true) {
4377 9
            $array = $this->getArrayRecursiveHelperArrayy($array);
4378 9
            $result = \array_replace_recursive($this->toArray(), $array);
4379
        } else {
4380 24
            $result = \array_replace($this->toArray(), $array);
4381
        }
4382
4383 33
        return static::create(
4384 33
            $result,
4385 33
            $this->iteratorClass,
4386 33
            false
4387
        );
4388
    }
4389
4390
    /**
4391
     * Merge the new $array into the current array.
4392
     *
4393
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
4394
     * - create new indexes
4395
     *
4396
     * EXAMPLE: <code>
4397
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
4398
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
4399
     * a($array1)->mergeAppendNewIndex($array2); // Arrayy[0 => 'one', 'foo' => 'bar2', 1 => 'three']
4400
     * // ---
4401
     * $array1 = [0 => 'one', 1 => 'foo'];
4402
     * $array2 = [0 => 'foo', 1 => 'bar2'];
4403
     * a($array1)->mergeAppendNewIndex($array2); // Arrayy[0 => 'one', 1 => 'foo', 2 => 'foo', 3 => 'bar2']
4404
     * </code>
4405
     *
4406
     * @param array $array
4407
     * @param bool  $recursive
4408
     *
4409
     * @return static
4410
     *                <p>(Immutable)</p>
4411
     *
4412
     * @phpstan-param  array<TKey,T> $array
4413
     * @phpstan-return static<int,T>
4414
     * @psalm-mutation-free
4415
     */
4416 20 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...
4417
    {
4418 20
        if ($recursive === true) {
4419 5
            $array = $this->getArrayRecursiveHelperArrayy($array);
4420 5
            $result = \array_merge_recursive($this->toArray(), $array);
4421
        } else {
4422 15
            $result = \array_merge($this->toArray(), $array);
4423
        }
4424
4425 20
        return static::create(
4426 20
            $result,
4427 20
            $this->iteratorClass,
4428 20
            false
4429
        );
4430
    }
4431
4432
    /**
4433
     * Merge the the current array into the $array.
4434
     *
4435
     * - use key,value from the new $array, also if the index is in the current array
4436
     *
4437
     * EXAMPLE: <code>
4438
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
4439
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
4440
     * a($array1)->mergePrependKeepIndex($array2); // Arrayy['foo' => 'bar1', 3 => 'three', 1 => 'one']
4441
     * // ---
4442
     * $array1 = [0 => 'one', 1 => 'foo'];
4443
     * $array2 = [0 => 'foo', 1 => 'bar2'];
4444
     * a($array1)->mergePrependKeepIndex($array2); // Arrayy[0 => 'one', 1 => 'foo']
4445
     * </code>
4446
     *
4447
     * @param array $array
4448
     * @param bool  $recursive
4449
     *
4450
     * @return static
4451
     *                <p>(Immutable)</p>
4452
     *
4453
     * @phpstan-param  array<TKey,T> $array
4454
     * @phpstan-return static<TKey,T>
4455
     * @psalm-mutation-free
4456
     */
4457 17 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...
4458
    {
4459 17
        if ($recursive === true) {
4460 4
            $array = $this->getArrayRecursiveHelperArrayy($array);
4461 4
            $result = \array_replace_recursive($array, $this->toArray());
4462
        } else {
4463 13
            $result = \array_replace($array, $this->toArray());
4464
        }
4465
4466 17
        return static::create(
4467 17
            $result,
4468 17
            $this->iteratorClass,
4469 17
            false
4470
        );
4471
    }
4472
4473
    /**
4474
     * Merge the current array into the new $array.
4475
     *
4476
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
4477
     * - create new indexes
4478
     *
4479
     * EXAMPLE: <code>
4480
     * $array1 = [1 => 'one', 'foo' => 'bar1'];
4481
     * $array2 = ['foo' => 'bar2', 3 => 'three'];
4482
     * a($array1)->mergePrependNewIndex($array2); // Arrayy['foo' => 'bar1', 0 => 'three', 1 => 'one']
4483
     * // ---
4484
     * $array1 = [0 => 'one', 1 => 'foo'];
4485
     * $array2 = [0 => 'foo', 1 => 'bar2'];
4486
     * a($array1)->mergePrependNewIndex($array2); // Arrayy[0 => 'foo', 1 => 'bar2', 2 => 'one', 3 => 'foo']
4487
     * </code>
4488
     *
4489
     * @param array $array
4490
     * @param bool  $recursive
4491
     *
4492
     * @return static
4493
     *                <p>(Immutable)</p>
4494
     *
4495
     * @phpstan-param  array<TKey,T> $array
4496
     * @phpstan-return static<int,T>
4497
     * @psalm-mutation-free
4498
     */
4499 21 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...
4500
    {
4501 21
        if ($recursive === true) {
4502 7
            $array = $this->getArrayRecursiveHelperArrayy($array);
4503 7
            $result = \array_merge_recursive($array, $this->toArray());
4504
        } else {
4505 14
            $result = \array_merge($array, $this->toArray());
4506
        }
4507
4508 21
        return static::create(
4509 21
            $result,
4510 21
            $this->iteratorClass,
4511 21
            false
4512
        );
4513
    }
4514
4515
    /**
4516
     * @return ArrayyMeta|mixed|static
4517
     */
4518 18
    public static function meta()
4519
    {
4520 18
        return (new ArrayyMeta())->getMetaObject(static::class);
4521
    }
4522
4523
    /**
4524
     * Get the min value from an array.
4525
     *
4526
     * EXAMPLE: <code>
4527
     * a([-9, -8, -7, 1.32])->min(); // -9
4528
     * </code>
4529
     *
4530
     * @return false|mixed
4531
     *                     <p>Will return false if there are no values.</p>
4532
     */
4533 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...
4534
    {
4535 10
        if ($this->count() === 0) {
4536 1
            return false;
4537
        }
4538
4539 9
        $min = false;
4540
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
4541 9
        foreach ($this->getGeneratorByReference() as &$value) {
4542
            if (
4543 9
                $min === false
4544
                ||
4545 9
                $value < $min
4546
            ) {
4547 9
                $min = $value;
4548
            }
4549
        }
4550
4551 9
        return $min;
4552
    }
4553
4554
    /**
4555
     * Get the most used value from the array.
4556
     *
4557
     * @return mixed|null
4558
     *                    <p>(Immutable) Return null if there wasn't a element.</p>
4559
     *
4560
     * @phpstan-return T|null
4561
     * @psalm-mutation-free
4562
     */
4563 3
    public function mostUsedValue()
4564
    {
4565 3
        return $this->countValues()->arsortImmutable()->firstKey();
4566
    }
4567
4568
    /**
4569
     * Get the most used value from the array.
4570
     *
4571
     * @param int|null $number <p>How many values you will take?</p>
4572
     *
4573
     * @return static
4574
     *                <p>(Immutable)</p>
4575
     *
4576
     * @phpstan-return static<TKey,T>
4577
     * @psalm-mutation-free
4578
     */
4579 3
    public function mostUsedValues(int $number = null): self
4580
    {
4581 3
        return $this->countValues()->arsortImmutable()->firstsKeys($number);
4582
    }
4583
4584
    /**
4585
     * Move an array element to a new index.
4586
     *
4587
     * EXAMPLE: <code>
4588
     * $arr2 = new A(['A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e']);
4589
     * $newArr2 = $arr2->moveElement('D', 1); // Arrayy['A' => 'a', 'D' => 'd', 'B' => 'b', 'C' => 'c', 'E' => 'e']
4590
     * </code>
4591
     *
4592
     * @param int|string $from
4593
     * @param int        $to
4594
     *
4595
     * @return static
4596
     *                <p>(Immutable)</p>
4597
     *
4598
     * @phpstan-return static<TKey,T>
4599
     * @psalm-mutation-free
4600
     */
4601 1
    public function moveElement($from, $to): self
4602
    {
4603 1
        $array = $this->toArray();
4604
4605 1
        if ((int) $from === $from) {
4606 1
            $tmp = \array_splice($array, $from, 1);
4607 1
            \array_splice($array, (int) $to, 0, $tmp);
4608 1
            $output = $array;
4609 1
        } elseif ((string) $from === $from) {
4610 1
            $indexToMove = \array_search($from, \array_keys($array), true);
4611 1
            $itemToMove = $array[$from];
4612 1
            if ($indexToMove !== false) {
4613 1
                \array_splice($array, $indexToMove, 1);
4614
            }
4615 1
            $i = 0;
4616 1
            $output = [];
4617 1
            foreach ($array as $key => $item) {
4618 1
                if ($i === $to) {
4619 1
                    $output[$from] = $itemToMove;
4620
                }
4621 1
                $output[$key] = $item;
4622 1
                ++$i;
4623
            }
4624
        } else {
4625
            $output = [];
4626
        }
4627
4628 1
        return static::create(
4629 1
            $output,
4630 1
            $this->iteratorClass,
4631 1
            false
4632
        );
4633
    }
4634
4635
    /**
4636
     * Move an array element to the first place.
4637
     *
4638
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
4639
     *       loss the keys of an indexed array.
4640
     *
4641
     * @param int|string $key
4642
     *
4643
     * @return static
4644
     *                <p>(Immutable)</p>
4645
     *
4646
     * @phpstan-return static<TKey,T>
4647
     * @psalm-mutation-free
4648
     */
4649 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...
4650
    {
4651 1
        $array = $this->toArray();
4652
4653 1
        if ($this->offsetExists($key)) {
4654 1
            $tmpValue = $this->get($key);
4655 1
            unset($array[$key]);
4656 1
            $array = [$key => $tmpValue] + $array;
4657
        }
4658
4659 1
        return static::create(
4660 1
            $array,
4661 1
            $this->iteratorClass,
4662 1
            false
4663
        );
4664
    }
4665
4666
    /**
4667
     * Move an array element to the last place.
4668
     *
4669
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
4670
     *       loss the keys of an indexed array.
4671
     *
4672
     * @param int|string $key
4673
     *
4674
     * @return static
4675
     *                <p>(Immutable)</p>
4676
     *
4677
     * @phpstan-return static<TKey,T>
4678
     * @psalm-mutation-free
4679
     */
4680 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...
4681
    {
4682 1
        $array = $this->toArray();
4683
4684 1
        if ($this->offsetExists($key)) {
4685 1
            $tmpValue = $this->get($key);
4686 1
            unset($array[$key]);
4687 1
            $array += [$key => $tmpValue];
4688
        }
4689
4690 1
        return static::create(
4691 1
            $array,
4692 1
            $this->iteratorClass,
4693 1
            false
4694
        );
4695
    }
4696
4697
    /**
4698
     * Moves the internal iterator position to the next element and returns this element.
4699
     *
4700
     * @return false|mixed
4701
     *                     <p>(Mutable) Will return false if there are no values.</p>
4702
     *
4703
     * @phpstan-return false|T
4704
     */
4705
    public function next()
4706
    {
4707
        if ($this->generator) {
4708
            $this->generator->next();
4709
4710
            return $this->generator->current() ?? false;
4711
        }
4712
4713
        return \next($this->array);
4714
    }
4715
4716
    /**
4717
     * Get the next nth keys and values from the array.
4718
     *
4719
     * @param int $step
4720
     * @param int $offset
4721
     *
4722
     * @return static
4723
     *                <p>(Immutable)</p>
4724
     *
4725
     * @phpstan-return static<TKey,T>
4726
     * @psalm-mutation-free
4727
     */
4728 1
    public function nth(int $step, int $offset = 0): self
4729
    {
4730
        $arrayFunction = function () use ($step, $offset): \Generator {
4731 1
            $position = 0;
4732 1
            foreach ($this->getGenerator() as $key => $value) {
4733 1
                if ($position++ % $step !== $offset) {
4734 1
                    continue;
4735
                }
4736
4737 1
                yield $key => $value;
4738
            }
4739 1
        };
4740
4741 1
        return static::create(
4742 1
            $arrayFunction,
4743 1
            $this->iteratorClass,
4744 1
            false
4745
        );
4746
    }
4747
4748
    /**
4749
     * Get a subset of the items from the given array.
4750
     *
4751
     * @param int[]|string[] $keys
4752
     *
4753
     * @return static
4754
     *                <p>(Immutable)</p>
4755
     *
4756
     * @phpstan-param array-key[] $keys
4757
     * @phpstan-return static<TKey,T>
4758
     * @psalm-mutation-free
4759
     */
4760 1 View Code Duplication
    public function only(array $keys): 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...
4761
    {
4762 1
        $keys = \array_flip($keys);
4763
4764
        $generator = function () use ($keys): \Generator {
4765 1
            foreach ($this->getGenerator() as $key => $value) {
4766 1
                if (isset($keys[$key])) {
4767 1
                    yield $key => $value;
4768
                }
4769
            }
4770 1
        };
4771
4772 1
        return static::create(
4773 1
            $generator,
4774 1
            $this->iteratorClass,
4775 1
            false
4776
        );
4777
    }
4778
4779
    /**
4780
     * Pad array to the specified size with a given value.
4781
     *
4782
     * @param int   $size  <p>Size of the result array.</p>
4783
     * @param mixed $value <p>Empty value by default.</p>
4784
     *
4785
     * @return static
4786
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
4787
     *
4788
     * @phpstan-return static<TKey,T>
4789
     * @psalm-mutation-free
4790
     */
4791 5
    public function pad(int $size, $value): self
4792
    {
4793 5
        return static::create(
4794 5
            \array_pad($this->toArray(), $size, $value),
4795 5
            $this->iteratorClass,
4796 5
            false
4797
        );
4798
    }
4799
4800
    /**
4801
     * Partitions this array in two array according to a predicate.
4802
     * Keys are preserved in the resulting array.
4803
     *
4804
     * @param \Closure $closure
4805
     *                          <p>The predicate on which to partition.</p>
4806
     *
4807
     * @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...
4808
     *                    <p>An array with two elements. The first element contains the array
4809
     *                    of elements where the predicate returned TRUE, the second element
4810
     *                    contains the array of elements where the predicate returned FALSE.</p>
4811
     *
4812
     * @phpstan-param \Closure(T=,TKey=):bool $closure
4813
     * @phpstan-return array<int, static<TKey,T>>
4814
     */
4815 1
    public function partition(\Closure $closure): array
4816
    {
4817
        // init
4818 1
        $matches = [];
4819 1
        $noMatches = [];
4820
4821 1
        foreach ($this->getGenerator() as $key => $value) {
4822 1
            if ($closure($value, $key)) {
4823 1
                $matches[$key] = $value;
4824
            } else {
4825 1
                $noMatches[$key] = $value;
4826
            }
4827
        }
4828
4829 1
        return [self::create($matches), self::create($noMatches)];
4830
    }
4831
4832
    /**
4833
     * Pop a specified value off the end of the current array.
4834
     *
4835
     * @return mixed|null
4836
     *                    <p>(Mutable) The popped element from the current array or null if the array is e.g. empty.</p>
4837
     *
4838
     * @phpstan-return T|null
4839
     */
4840 5
    public function pop()
4841
    {
4842 5
        $this->generatorToArray();
4843
4844 5
        return \array_pop($this->array);
4845
    }
4846
4847
    /**
4848
     * Prepend a (key) + value to the current array.
4849
     *
4850
     * EXAMPLE: <code>
4851
     * a(['fòô' => 'bàř'])->prepend('foo'); // Arrayy[0 => 'foo', 'fòô' => 'bàř']
4852
     * </code>
4853
     *
4854
     * @param mixed $value
4855
     * @param mixed $key
4856
     *
4857
     * @return $this
4858
     *               <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
4859
     *
4860
     * @phpstan-param T $value
4861
     * @phpstan-param TKey|null $key
4862
     * @phpstan-return static<TKey,T>
4863
     */
4864 11
    public function prepend($value, $key = null)
4865
    {
4866 11
        $this->generatorToArray();
4867
4868 11
        if ($this->properties !== []) {
4869 3
            $this->checkType($key, $value);
4870
        }
4871
4872 9
        if ($key === null) {
4873 8
            \array_unshift($this->array, $value);
4874
        } else {
4875 2
            $this->array = [$key => $value] + $this->array;
4876
        }
4877
4878 9
        return $this;
4879
    }
4880
4881
    /**
4882
     * Prepend a (key) + value to the current array.
4883
     *
4884
     * EXAMPLE: <code>
4885
     * a(['fòô' => 'bàř'])->prependImmutable('foo')->getArray(); // [0 => 'foo', 'fòô' => 'bàř']
4886
     * </code>
4887
     *
4888
     * @param mixed $value
4889
     * @param mixed $key
4890
     *
4891
     * @return $this
4892
     *               <p>(Immutable) Return this Arrayy object, with the prepended value.</p>
4893
     *
4894
     * @phpstan-param T $value
4895
     * @phpstan-param TKey $key
4896
     * @phpstan-return static<TKey,T>
4897
     * @psalm-mutation-free
4898
     */
4899 1 View Code Duplication
    public function prependImmutable($value, $key = null)
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...
4900
    {
4901
        $generator = function () use ($key, $value): \Generator {
4902 1
            if ($this->properties !== []) {
4903
                $this->checkType($key, $value);
4904
            }
4905
4906 1
            if ($key !== null) {
4907
                yield $key => $value;
4908
            } else {
4909 1
                yield $value;
4910
            }
4911
4912
            /** @noinspection YieldFromCanBeUsedInspection - FP */
4913 1
            foreach ($this->getGenerator() as $keyOld => $itemOld) {
4914 1
                yield $keyOld => $itemOld;
4915
            }
4916 1
        };
4917
4918 1
        return static::create(
4919 1
            $generator,
4920 1
            $this->iteratorClass,
4921 1
            false
4922
        );
4923
    }
4924
4925
    /**
4926
     * Add a suffix to each key.
4927
     *
4928
     * @param float|int|string $suffix
4929
     *
4930
     * @return static
4931
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
4932
     *
4933
     * @phpstan-return static<TKey,T>
4934
     * @psalm-mutation-free
4935
     */
4936 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...
4937
    {
4938
        // init
4939 10
        $result = [];
4940
4941 10
        foreach ($this->getGenerator() as $key => $item) {
4942 9
            if ($item instanceof self) {
4943
                $result[$key] = $item->prependToEachKey($suffix);
4944 9
            } elseif (\is_array($item)) {
4945
                $result[$key] = self::create(
4946
                    $item,
4947
                    $this->iteratorClass,
4948
                    false
4949
                )->prependToEachKey($suffix)
4950
                    ->toArray();
4951
            } else {
4952 9
                $result[$key . $suffix] = $item;
4953
            }
4954
        }
4955
4956 10
        return self::create(
4957 10
            $result,
4958 10
            $this->iteratorClass,
4959 10
            false
4960
        );
4961
    }
4962
4963
    /**
4964
     * Add a suffix to each value.
4965
     *
4966
     * @param float|int|string $suffix
4967
     *
4968
     * @return static
4969
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
4970
     *
4971
     * @phpstan-return static<TKey,T>
4972
     * @psalm-mutation-free
4973
     */
4974 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...
4975
    {
4976
        // init
4977 10
        $result = [];
4978
4979 10
        foreach ($this->getGenerator() as $key => $item) {
4980 9
            if ($item instanceof self) {
4981
                $result[$key] = $item->prependToEachValue($suffix);
4982 9
            } elseif (\is_array($item)) {
4983
                $result[$key] = self::create(
4984
                    $item,
4985
                    $this->iteratorClass,
4986
                    false
4987
                )->prependToEachValue($suffix)
4988
                    ->toArray();
4989 9
            } elseif (\is_object($item) === true) {
4990 1
                $result[$key] = $item;
4991
            } else {
4992 9
                $result[$key] = $item . $suffix;
4993
            }
4994
        }
4995
4996 10
        return self::create(
4997 10
            $result,
4998 10
            $this->iteratorClass,
4999 10
            false
5000
        );
5001
    }
5002
5003
    /**
5004
     * Return the value of a given key and
5005
     * delete the key.
5006
     *
5007
     * @param int|int[]|string|string[]|null $keyOrKeys
5008
     * @param mixed                          $fallback
5009
     *
5010
     * @return mixed
5011
     */
5012 6
    public function pull($keyOrKeys = null, $fallback = null)
5013
    {
5014 6
        if ($keyOrKeys === null) {
5015 1
            $array = $this->toArray();
5016 1
            $this->clear();
5017
5018 1
            return $array;
5019
        }
5020
5021 5
        if (\is_array($keyOrKeys)) {
5022 1
            $valueOrValues = [];
5023 1
            foreach ($keyOrKeys as $key) {
5024 1
                $valueOrValues[] = $this->get($key, $fallback);
5025 1
                $this->offsetUnset($key);
5026
            }
5027
        } else {
5028 5
            $valueOrValues = $this->get($keyOrKeys, $fallback);
5029 5
            $this->offsetUnset($keyOrKeys);
5030
        }
5031
5032 5
        return $valueOrValues;
5033
    }
5034
5035
    /**
5036
     * Push one or more values onto the end of array at once.
5037
     *
5038
     * @param mixed ...$args
5039
     *
5040
     * @return $this
5041
     *               <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
5042
     *
5043
     * @noinspection ReturnTypeCanBeDeclaredInspection
5044
     *
5045
     * @phpstan-param  array<TKey,T> ...$args
5046
     * @phpstan-return static<TKey,T>
5047
     */
5048 9 View Code Duplication
    public function push(...$args)
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...
5049
    {
5050 9
        $this->generatorToArray();
5051
5052
        if (
5053 9
            $this->checkPropertyTypes
5054
            &&
5055 9
            $this->properties !== []
5056
        ) {
5057 3
            foreach ($args as $key => $value) {
5058 3
                $this->checkType($key, $value);
5059
            }
5060
        }
5061
5062 8
        \array_push($this->array, ...$args);
5063
5064 8
        return $this;
5065
    }
5066
5067
    /**
5068
     * Get a random value from the current array.
5069
     *
5070
     * EXAMPLE: <code>
5071
     * a([1, 2, 3, 4])->randomImmutable(2); // e.g.: Arrayy[1, 4]
5072
     * </code>
5073
     *
5074
     * @param int|null $number <p>How many values you will take?</p>
5075
     *
5076
     * @return static
5077
     *                <p>(Immutable)</p>
5078
     *
5079
     * @phpstan-return static<int|array-key,T>
5080
     */
5081 19
    public function randomImmutable(int $number = null): self
5082
    {
5083 19
        $this->generatorToArray();
5084
5085 19
        if ($this->count() === 0) {
5086 1
            return static::create(
5087 1
                [],
5088 1
                $this->iteratorClass,
5089 1
                false
5090
            );
5091
        }
5092
5093 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...
5094
            /** @noinspection NonSecureArrayRandUsageInspection */
5095 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
5096
5097 13
            return static::create(
5098 13
                $arrayRandValue,
5099 13
                $this->iteratorClass,
5100 13
                false
5101
            );
5102
        }
5103
5104 6
        $arrayTmp = $this->array;
5105
        /** @noinspection NonSecureShuffleUsageInspection */
5106 6
        \shuffle($arrayTmp);
5107
5108 6
        return static::create(
5109 6
            $arrayTmp,
5110 6
            $this->iteratorClass,
5111 6
            false
5112 6
        )->firstsImmutable($number);
5113
    }
5114
5115
    /**
5116
     * Pick a random key/index from the keys of this array.
5117
     *
5118
     * EXAMPLE: <code>
5119
     * $arrayy = A::create([1 => 'one', 2 => 'two']);
5120
     * $arrayy->randomKey(); // e.g. 2
5121
     * </code>
5122
     *
5123
     * @throws \RangeException If array is empty
5124
     *
5125
     * @return mixed
5126
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
5127
     */
5128 4
    public function randomKey()
5129
    {
5130 4
        $result = $this->randomKeys(1);
5131
5132 4
        if (!isset($result[0])) {
5133
            $result[0] = null;
5134
        }
5135
5136 4
        return $result[0];
5137
    }
5138
5139
    /**
5140
     * Pick a given number of random keys/indexes out of this array.
5141
     *
5142
     * EXAMPLE: <code>
5143
     * a([1 => 'one', 2 => 'two'])->randomKeys(); // e.g. Arrayy[1, 2]
5144
     * </code>
5145
     *
5146
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
5147
     *
5148
     * @throws \RangeException If array is empty
5149
     *
5150
     * @return static
5151
     *                <p>(Immutable)</p>
5152
     *
5153
     * @phpstan-return static<TKey,T>
5154
     */
5155 13
    public function randomKeys(int $number): self
5156
    {
5157 13
        $this->generatorToArray();
5158
5159 13
        $count = $this->count();
5160
5161
        if (
5162 13
            $number === 0
5163
            ||
5164 13
            $number > $count
5165
        ) {
5166 2
            throw new \RangeException(
5167 2
                \sprintf(
5168 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
5169 2
                    $number,
5170 2
                    $count
5171
                )
5172
            );
5173
        }
5174
5175 11
        $result = (array) \array_rand($this->array, $number);
5176
5177 11
        return static::create(
5178 11
            $result,
5179 11
            $this->iteratorClass,
5180 11
            false
5181
        );
5182
    }
5183
5184
    /**
5185
     * Get a random value from the current array.
5186
     *
5187
     * EXAMPLE: <code>
5188
     * a([1, 2, 3, 4])->randomMutable(2); // e.g.: Arrayy[1, 4]
5189
     * </code>
5190
     *
5191
     * @param int|null $number <p>How many values you will take?</p>
5192
     *
5193
     * @return $this
5194
     *               <p>(Mutable) Return this Arrayy object.</p>
5195
     *
5196
     * @phpstan-return static<TKey,T>
5197
     */
5198 17
    public function randomMutable(int $number = null): self
5199
    {
5200 17
        $this->generatorToArray();
5201
5202 17
        if ($this->count() === 0) {
5203
            return static::create(
5204
                [],
5205
                $this->iteratorClass,
5206
                false
5207
            );
5208
        }
5209
5210 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...
5211
            /** @noinspection NonSecureArrayRandUsageInspection */
5212 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
5213 7
            $this->array = $arrayRandValue;
5214
5215 7
            return $this;
5216
        }
5217
5218
        /** @noinspection NonSecureShuffleUsageInspection */
5219 11
        \shuffle($this->array);
5220
5221 11
        return $this->firstsMutable($number);
5222
    }
5223
5224
    /**
5225
     * Pick a random value from the values of this array.
5226
     *
5227
     * EXAMPLE: <code>
5228
     * a([1 => 'one', 2 => 'two'])->randomValue(); // e.g. 'one'
5229
     * </code>
5230
     *
5231
     * @return mixed
5232
     *               <p>Get a random value or null if there wasn't a value.</p>
5233
     */
5234 4
    public function randomValue()
5235
    {
5236 4
        $result = $this->randomImmutable();
5237
5238 4
        if (!isset($result[0])) {
5239
            $result[0] = null;
5240
        }
5241
5242 4
        return $result[0];
5243
    }
5244
5245
    /**
5246
     * Pick a given number of random values out of this array.
5247
     *
5248
     * EXAMPLE: <code>
5249
     * a([1 => 'one', 2 => 'two'])->randomValues(); // e.g. Arrayy['one', 'two']
5250
     * </code>
5251
     *
5252
     * @param int $number
5253
     *
5254
     * @return static
5255
     *                <p>(Mutable)</p>
5256
     *
5257
     * @phpstan-return static<TKey,T>
5258
     */
5259 7
    public function randomValues(int $number): self
5260
    {
5261 7
        return $this->randomMutable($number);
5262
    }
5263
5264
    /**
5265
     * Get a random value from an array, with the ability to skew the results.
5266
     *
5267
     * EXAMPLE: <code>
5268
     * a([0 => 3, 1 => 4])->randomWeighted([1 => 4]); // e.g.: Arrayy[4] (has a 66% chance of returning 4)
5269
     * </code>
5270
     *
5271
     * @param array    $array
5272
     * @param int|null $number <p>How many values you will take?</p>
5273
     *
5274
     * @return static<int,mixed>
0 ignored issues
show
Documentation introduced by
The doc-type static<int,mixed> could not be parsed: Expected "|" or "end of type", but got "<" at position 6. (view supported doc-types)

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

Loading history...
5275
     *                           <p>(Immutable)</p>
5276
     *
5277
     * @phpstan-param  array<T,int> $array
5278
     * @phpstan-return static<(int|string),T>
5279
     */
5280 9
    public function randomWeighted(array $array, int $number = null): self
5281
    {
5282
        // init
5283 9
        $options = [];
5284
5285 9
        foreach ($array as $option => $weight) {
5286 9
            if ($this->searchIndex($option) !== false) {
5287 9
                for ($i = 0; $i < $weight; ++$i) {
5288 1
                    $options[] = $option;
5289
                }
5290
            }
5291
        }
5292
5293 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
5294
    }
5295
5296
    /**
5297
     * Reduce the current array via callable e.g. anonymous-function and return the end result.
5298
     *
5299
     * EXAMPLE: <code>
5300
     * a([1, 2, 3, 4])->reduce(
5301
     *     function ($carry, $item) {
5302
     *         return $carry * $item;
5303
     *     },
5304
     *     1
5305
     * ); // Arrayy[24]
5306
     * </code>
5307
     *
5308
     * @param callable $callable
5309
     * @param mixed    $initial
5310
     *
5311
     * @return static
5312
     *                <p>(Immutable)</p>
5313
     *
5314
     * @template T2
5315
     *              <p>The output value type.</p>
5316
     *
5317
     * @phpstan-param callable(T2, T, TKey): T2 $callable
5318
     * @phpstan-param T2                  $initial
5319
     *
5320
     * @phpstan-return static<TKey,T2>
5321
     * @psalm-mutation-free
5322
     */
5323 18 View Code Duplication
    public function reduce($callable, $initial = []): 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...
5324
    {
5325 18
        foreach ($this->getGenerator() as $key => $value) {
5326 17
            $initial = $callable($initial, $value, $key);
5327
        }
5328
5329 18
        return static::create(
5330 18
            $initial,
5331 18
            $this->iteratorClass,
5332 18
            false
5333
        );
5334
    }
5335
5336
    /**
5337
     * @param bool $unique
5338
     *
5339
     * @return static
5340
     *                <p>(Immutable)</p>
5341
     *
5342
     * @phpstan-return static<int,mixed>
5343
     * @psalm-mutation-free
5344
     */
5345 14
    public function reduce_dimension(bool $unique = true): self
5346
    {
5347
        // init
5348 14
        $result = [];
5349
5350 14
        foreach ($this->getGenerator() as $val) {
5351 12
            if (\is_array($val)) {
5352 5
                $result[] = (new static($val))->reduce_dimension($unique)->toArray();
5353
            } else {
5354 12
                $result[] = [$val];
5355
            }
5356
        }
5357
5358 14
        $result = $result === [] ? [] : \array_merge(...$result);
5359
5360 14
        $resultArrayy = new static($result);
5361
5362
        /**
5363
         * @psalm-suppress ImpureMethodCall - object is already re-created
5364
         * @psalm-suppress InvalidReturnStatement - why?
5365
         */
5366 14
        return $unique ? $resultArrayy->unique() : $resultArrayy;
5367
    }
5368
5369
    /**
5370
     * Create a numerically re-indexed Arrayy object.
5371
     *
5372
     * EXAMPLE: <code>
5373
     * a([2 => 1, 3 => 2])->reindex(); // Arrayy[0 => 1, 1 => 2]
5374
     * </code>
5375
     *
5376
     * @return $this
5377
     *               <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
5378
     *
5379
     * @phpstan-return static<TKey,T>
5380
     */
5381 9
    public function reindex(): self
5382
    {
5383 9
        $this->generatorToArray(false);
5384
5385 9
        $this->array = \array_values($this->array);
5386
5387 9
        return $this;
5388
    }
5389
5390
    /**
5391
     * Return all items that fail the truth test.
5392
     *
5393
     * EXAMPLE: <code>
5394
     * $closure = function ($value) {
5395
     *     return $value % 2 !== 0;
5396
     * }
5397
     * a([1, 2, 3, 4])->reject($closure); // Arrayy[1 => 2, 3 => 4]
5398
     * </code>
5399
     *
5400
     * @param \Closure $closure
5401
     *
5402
     * @return static
5403
     *                <p>(Immutable)</p>
5404
     *
5405
     * @phpstan-param \Closure(T=,TKey=):bool  $closure
5406
     * @phpstan-return static<TKey,T>
5407
     * @psalm-mutation-free
5408
     */
5409 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...
5410
    {
5411
        // init
5412 1
        $filtered = [];
5413
5414 1
        foreach ($this->getGenerator() as $key => $value) {
5415 1
            if (!$closure($value, $key)) {
5416 1
                $filtered[$key] = $value;
5417
            }
5418
        }
5419
5420 1
        return static::create(
5421 1
            $filtered,
5422 1
            $this->iteratorClass,
5423 1
            false
5424
        );
5425
    }
5426
5427
    /**
5428
     * Remove a value from the current array (optional using dot-notation).
5429
     *
5430
     * EXAMPLE: <code>
5431
     * a([1 => 'bar', 'foo' => 'foo'])->remove(1); // Arrayy['foo' => 'foo']
5432
     * </code>
5433
     *
5434
     * @param mixed $key
5435
     *
5436
     * @return static
5437
     *                <p>(Mutable)</p>
5438
     *
5439
     * @phpstan-param  TKey $key
5440
     * @phpstan-return static<TKey,T>
5441
     */
5442 22
    public function remove($key)
5443
    {
5444
        // recursive call
5445 22
        if (\is_array($key)) {
5446 1
            foreach ($key as $k) {
5447 1
                $this->internalRemove($k);
5448
            }
5449
5450 1
            return static::create(
5451 1
                $this->toArray(),
5452 1
                $this->iteratorClass,
5453 1
                false
5454
            );
5455
        }
5456
5457 21
        $this->internalRemove($key);
5458
5459 21
        return static::create(
5460 21
            $this->toArray(),
5461 21
            $this->iteratorClass,
5462 21
            false
5463
        );
5464
    }
5465
5466
    /**
5467
     * alias: for "Arrayy->removeValue()"
5468
     *
5469
     * @param mixed $element
5470
     *
5471
     * @return static
5472
     *                <p>(Immutable)</p>
5473
     *
5474
     * @phpstan-param  T $element
5475
     * @phpstan-return static<TKey,T>
5476
     * @psalm-mutation-free
5477
     */
5478 8
    public function removeElement($element)
5479
    {
5480 8
        return $this->removeValue($element);
5481
    }
5482
5483
    /**
5484
     * Remove the first value from the current array.
5485
     *
5486
     * EXAMPLE: <code>
5487
     * a([1 => 'bar', 'foo' => 'foo'])->removeFirst(); // Arrayy['foo' => 'foo']
5488
     * </code>
5489
     *
5490
     * @return static
5491
     *                <p>(Immutable)</p>
5492
     *
5493
     * @phpstan-return static<TKey,T>
5494
     * @psalm-mutation-free
5495
     */
5496 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...
5497
    {
5498 7
        $tmpArray = $this->toArray();
5499
5500 7
        \array_shift($tmpArray);
5501
5502 7
        return static::create(
5503 7
            $tmpArray,
5504 7
            $this->iteratorClass,
5505 7
            false
5506
        );
5507
    }
5508
5509
    /**
5510
     * Remove the last value from the current array.
5511
     *
5512
     * EXAMPLE: <code>
5513
     * a([1 => 'bar', 'foo' => 'foo'])->removeLast(); // Arrayy[1 => 'bar']
5514
     * </code>
5515
     *
5516
     * @return static
5517
     *                <p>(Immutable)</p>
5518
     *
5519
     * @phpstan-return static<TKey,T>
5520
     * @psalm-mutation-free
5521
     */
5522 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...
5523
    {
5524 7
        $tmpArray = $this->toArray();
5525
5526 7
        \array_pop($tmpArray);
5527
5528 7
        return static::create(
5529 7
            $tmpArray,
5530 7
            $this->iteratorClass,
5531 7
            false
5532
        );
5533
    }
5534
5535
    /**
5536
     * Removes a particular value from an array (numeric or associative).
5537
     *
5538
     * EXAMPLE: <code>
5539
     * a([1 => 'bar', 'foo' => 'foo'])->removeValue('foo'); // Arrayy[1 => 'bar']
5540
     * </code>
5541
     *
5542
     * @param mixed $value
5543
     *
5544
     * @return static
5545
     *                <p>(Immutable)</p>
5546
     *
5547
     * @phpstan-param  T $value
5548
     * @phpstan-return static<TKey,T>
5549
     * @psalm-mutation-free
5550
     */
5551 8
    public function removeValue($value): self
5552
    {
5553 8
        $this->generatorToArray();
5554
5555
        // init
5556 8
        $isSequentialArray = $this->isSequential();
5557
5558 8
        foreach ($this->array as $key => $item) {
5559 7
            if ($item === $value) {
5560
                /** @phpstan-ignore-next-line | "Possibly invalid array key type int|string|TKey.", is this a bug in phpstan? */
5561 7
                unset($this->array[$key]);
5562
            }
5563
        }
5564
5565 8
        if ($isSequentialArray) {
5566 6
            $this->array = \array_values($this->array);
5567
        }
5568
5569 8
        return static::create(
5570 8
            $this->array,
5571 8
            $this->iteratorClass,
5572 8
            false
5573
        );
5574
    }
5575
5576
    /**
5577
     * Generate array of repeated arrays.
5578
     *
5579
     * @param int $times <p>How many times has to be repeated.</p>
5580
     *
5581
     * @return static
5582
     *                <p>(Immutable)</p>
5583
     *
5584
     * @phpstan-return static<TKey,T>
5585
     * @psalm-mutation-free
5586
     */
5587 1
    public function repeat($times): self
5588
    {
5589 1
        if ($times === 0) {
5590 1
            return static::create([], $this->iteratorClass);
5591
        }
5592
5593 1
        return static::create(
5594 1
            \array_fill(0, (int) $times, $this->toArray()),
5595 1
            $this->iteratorClass,
5596 1
            false
5597
        );
5598
    }
5599
5600
    /**
5601
     * Replace a key with a new key/value pair.
5602
     *
5603
     * EXAMPLE: <code>
5604
     * $arrayy = a([1 => 'foo', 2 => 'foo2', 3 => 'bar']);
5605
     * $arrayy->replace(2, 'notfoo', 'notbar'); // Arrayy[1 => 'foo', 'notfoo' => 'notbar', 3 => 'bar']
5606
     * </code>
5607
     *
5608
     * @param mixed $oldKey
5609
     * @param mixed $newKey
5610
     * @param mixed $newValue
5611
     *
5612
     * @return static
5613
     *                <p>(Immutable)</p>
5614
     *
5615
     * @phpstan-return static<TKey,T>
5616
     * @psalm-mutation-free
5617
     */
5618 5
    public function replace($oldKey, $newKey, $newValue): self
5619
    {
5620 5
        $that = clone $this;
5621
5622
        /**
5623
         * @psalm-suppress ImpureMethodCall - object is already cloned
5624
         */
5625 5
        return $that->remove($oldKey)
5626 5
            ->set($newKey, $newValue);
5627
    }
5628
5629
    /**
5630
     * Create an array using the current array as values and the other array as keys.
5631
     *
5632
     * EXAMPLE: <code>
5633
     * $firstArray = [
5634
     *     1 => 'one',
5635
     *     2 => 'two',
5636
     *     3 => 'three',
5637
     * ];
5638
     * $secondArray = [
5639
     *     'one' => 1,
5640
     *     1     => 'one',
5641
     *     2     => 2,
5642
     * ];
5643
     * $arrayy = a($firstArray);
5644
     * $arrayy->replaceAllKeys($secondArray); // Arrayy[1 => "one", 'one' => "two", 2 => "three"]
5645
     * </code>
5646
     *
5647
     * @param int[]|string[] $keys <p>An array of keys.</p>
5648
     *
5649
     * @return static
5650
     *                <p>(Immutable) Arrayy object with keys from the other array, empty Arrayy object if the number of elements
5651
     *                for each array isn't equal or if the arrays are empty.
5652
     *                </p>
5653
     *
5654
     * @phpstan-param  array<array-key,TKey> $keys
5655
     * @phpstan-return static<TKey,T>
5656
     * @psalm-mutation-free
5657
     */
5658 2 View Code Duplication
    public function replaceAllKeys(array $keys): 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...
5659
    {
5660 2
        $data = \array_combine($keys, $this->toArray());
5661 2
        if ($data === false) {
5662
            $data = [];
5663
        }
5664
5665 2
        return static::create(
5666 2
            $data,
5667 2
            $this->iteratorClass,
5668 2
            false
5669
        );
5670
    }
5671
5672
    /**
5673
     * Create an array using the current array as keys and the other array as values.
5674
     *
5675
     * EXAMPLE: <code>
5676
     * $firstArray = [
5677
     *     1 => 'one',
5678
     *     2 => 'two',
5679
     *     3 => 'three',
5680
     * ];
5681
     * $secondArray = [
5682
     *     'one' => 1,
5683
     *     1     => 'one',
5684
     *     2     => 2,
5685
     * ];
5686
     * $arrayy = a($firstArray);
5687
     * $arrayy->replaceAllValues($secondArray); // Arrayy['one' => 1, 'two' => 'one', 'three' => 2]
5688
     * </code>
5689
     *
5690
     * @param array $array <p>An array of values.</p>
5691
     *
5692
     * @return static
5693
     *                <p>(Immutable) Arrayy object with values from the other array, empty Arrayy object if the number of elements
5694
     *                for each array isn't equal or if the arrays are empty.
5695
     *                </p>
5696
     *
5697
     * @phpstan-param  array<array-key,T> $array
5698
     * @phpstan-return static<TKey,T>
5699
     * @psalm-mutation-free
5700
     */
5701 2 View Code Duplication
    public function replaceAllValues(array $array): 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...
5702
    {
5703 2
        $data = \array_combine($this->toArray(), $array);
5704 2
        if ($data === false) {
5705
            $data = [];
5706
        }
5707
5708 2
        return static::create(
5709 2
            $data,
5710 2
            $this->iteratorClass,
5711 2
            false
5712
        );
5713
    }
5714
5715
    /**
5716
     * Replace the keys in an array with another set.
5717
     *
5718
     * EXAMPLE: <code>
5719
     * a([1 => 'bar', 'foo' => 'foo'])->replaceKeys([1 => 2, 'foo' => 'replaced']); // Arrayy[2 => 'bar', 'replaced' => 'foo']
5720
     * </code>
5721
     *
5722
     * @param array $keys <p>An array of keys matching the array's size.</p>
5723
     *
5724
     * @return static
5725
     *                <p>(Immutable)</p>
5726
     *
5727
     * @phpstan-param  array<array-key,TKey> $keys
5728
     * @phpstan-return static<TKey,T>
5729
     * @psalm-mutation-free
5730
     */
5731 1 View Code Duplication
    public function replaceKeys(array $keys): 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...
5732
    {
5733 1
        $values = \array_values($this->toArray());
5734 1
        $result = \array_combine($keys, $values);
5735 1
        if ($result === false) {
5736
            $result = [];
5737
        }
5738
5739 1
        return static::create(
5740 1
            $result,
5741 1
            $this->iteratorClass,
5742 1
            false
5743
        );
5744
    }
5745
5746
    /**
5747
     * Replace the first matched value in an array.
5748
     *
5749
     * EXAMPLE: <code>
5750
     * $testArray = ['bar', 'foo' => 'foo', 'foobar' => 'foobar'];
5751
     * a($testArray)->replaceOneValue('foo', 'replaced'); // Arrayy['bar', 'foo' => 'replaced', 'foobar' => 'foobar']
5752
     * </code>
5753
     *
5754
     * @param mixed $search      <p>The value to replace.</p>
5755
     * @param mixed $replacement <p>The value to replace.</p>
5756
     *
5757
     * @return static
5758
     *                <p>(Immutable)</p>
5759
     *
5760
     * @phpstan-return static<TKey,T>
5761
     * @psalm-mutation-free
5762
     */
5763 3
    public function replaceOneValue($search, $replacement = ''): self
5764
    {
5765 3
        $array = $this->toArray();
5766 3
        $key = \array_search($search, $array, true);
5767
5768 3
        if ($key !== false) {
5769 3
            $array[$key] = $replacement;
5770
        }
5771
5772 3
        return static::create(
5773 3
            $array,
5774 3
            $this->iteratorClass,
5775 3
            false
5776
        );
5777
    }
5778
5779
    /**
5780
     * Replace values in the current array.
5781
     *
5782
     * EXAMPLE: <code>
5783
     * $testArray = ['bar', 'foo' => 'foo', 'foobar' => 'foobar'];
5784
     * a($testArray)->replaceValues('foo', 'replaced'); // Arrayy['bar', 'foo' => 'replaced', 'foobar' => 'replacedbar']
5785
     * </code>
5786
     *
5787
     * @param string $search      <p>The value to replace.</p>
5788
     * @param string $replacement <p>What to replace it with.</p>
5789
     *
5790
     * @return static
5791
     *                <p>(Immutable)</p>
5792
     *
5793
     * @phpstan-return static<TKey,T>
5794
     * @psalm-mutation-free
5795
     */
5796 1
    public function replaceValues($search, $replacement = ''): self
5797
    {
5798
        $function = static function ($value) use ($search, $replacement) {
5799 1
            return \str_replace($search, $replacement, $value);
5800 1
        };
5801
5802
        /** @phpstan-ignore-next-line | ignore Closure with one or two parameters, is this a bug in phpstan? */
5803 1
        return $this->each($function);
5804
    }
5805
5806
    /**
5807
     * Get the last elements from index $from until the end of this array.
5808
     *
5809
     * EXAMPLE: <code>
5810
     * a([2 => 'foo', 3 => 'bar', 4 => 'lall'])->rest(2); // Arrayy[0 => 'lall']
5811
     * </code>
5812
     *
5813
     * @param int $from
5814
     *
5815
     * @return static
5816
     *                <p>(Immutable)</p>
5817
     *
5818
     * @phpstan-return static<TKey,T>
5819
     * @psalm-mutation-free
5820
     */
5821 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...
5822
    {
5823 15
        $tmpArray = $this->toArray();
5824
5825 15
        return static::create(
5826 15
            \array_splice($tmpArray, $from),
5827 15
            $this->iteratorClass,
5828 15
            false
5829
        );
5830
    }
5831
5832
    /**
5833
     * Return the array in the reverse order.
5834
     *
5835
     * EXAMPLE: <code>
5836
     * a([1, 2, 3])->reverse(); // self[3, 2, 1]
5837
     * </code>
5838
     *
5839
     * @return $this
5840
     *               <p>(Mutable) Return this Arrayy object.</p>
5841
     *
5842
     * @phpstan-return static<TKey,T>
5843
     */
5844 9
    public function reverse(): self
5845
    {
5846 9
        $this->generatorToArray();
5847
5848 9
        $this->array = \array_reverse($this->array);
5849
5850 9
        return $this;
5851
    }
5852
5853
    /**
5854
     * Sort an array in reverse order.
5855
     *
5856
     * @param int $sort_flags [optional] <p>
5857
     *                        You may modify the behavior of the sort using the optional
5858
     *                        parameter sort_flags, for details
5859
     *                        see sort.
5860
     *                        </p>
5861
     *
5862
     * @return $this
5863
     *               <p>(Mutable) Return this Arrayy object.</p>
5864
     *
5865
     * @phpstan-return static<TKey,T>
5866
     */
5867 4
    public function rsort(int $sort_flags = 0): self
5868
    {
5869 4
        $this->generatorToArray();
5870
5871 4
        \rsort($this->array, $sort_flags);
5872
5873 4
        return $this;
5874
    }
5875
5876
    /**
5877
     * Sort an array in reverse order.
5878
     *
5879
     * @param int $sort_flags [optional] <p>
5880
     *                        You may modify the behavior of the sort using the optional
5881
     *                        parameter sort_flags, for details
5882
     *                        see sort.
5883
     *                        </p>
5884
     *
5885
     * @return $this
5886
     *               <p>(Immutable) Return this Arrayy object.</p>
5887
     *
5888
     * @phpstan-return static<TKey,T>
5889
     * @psalm-mutation-free
5890
     */
5891 4
    public function rsortImmutable(int $sort_flags = 0): self
5892
    {
5893 4
        $that = clone $this;
5894
5895
        /**
5896
         * @psalm-suppress ImpureMethodCall - object is already cloned
5897
         */
5898 4
        $that->rsort($sort_flags);
5899
5900 4
        return $that;
5901
    }
5902
5903
    /**
5904
     * Search for the first index of the current array via $value.
5905
     *
5906
     * EXAMPLE: <code>
5907
     * a(['fòô' => 'bàř', 'lall' => 'bàř'])->searchIndex('bàř'); // Arrayy[0 => 'fòô']
5908
     * </code>
5909
     *
5910
     * @param mixed $value
5911
     *
5912
     * @return false|float|int|string
5913
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
5914
     * @psalm-mutation-free
5915
     */
5916 21
    public function searchIndex($value)
5917
    {
5918 21
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
5919 20
            if ($value === $valueFromArray) {
5920 20
                return $keyFromArray;
5921
            }
5922
        }
5923
5924 11
        return false;
5925
    }
5926
5927
    /**
5928
     * Search for the value of the current array via $index.
5929
     *
5930
     * EXAMPLE: <code>
5931
     * a(['fòô' => 'bàř'])->searchValue('fòô'); // Arrayy[0 => 'bàř']
5932
     * </code>
5933
     *
5934
     * @param mixed $index
5935
     *
5936
     * @return static
5937
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
5938
     *
5939
     * @phpstan-return static<TKey,T>
5940
     * @psalm-mutation-free
5941
     */
5942 9
    public function searchValue($index): self
5943
    {
5944 9
        $this->generatorToArray();
5945
5946
        // init
5947 9
        $return = [];
5948
5949 9
        if ($this->array === []) {
5950
            return static::create(
5951
                [],
5952
                $this->iteratorClass,
5953
                false
5954
            );
5955
        }
5956
5957
        // php cast "bool"-index into "int"-index
5958 9
        if ((bool) $index === $index) {
5959 1
            $index = (int) $index;
5960
        }
5961
5962 9
        if ($this->offsetExists($index)) {
5963 7
            $return = [$this->array[$index]];
5964
        }
5965
5966 9
        return static::create(
5967 9
            $return,
5968 9
            $this->iteratorClass,
5969 9
            false
5970
        );
5971
    }
5972
5973
    /**
5974
     * Set a value for the current array (optional using dot-notation).
5975
     *
5976
     * EXAMPLE: <code>
5977
     * $arrayy = a(['Lars' => ['lastname' => 'Moelleken']]);
5978
     * $arrayy->set('Lars.lastname', 'Müller'); // Arrayy['Lars', ['lastname' => 'Müller']]]
5979
     * </code>
5980
     *
5981
     * @param string $key   <p>The key to set.</p>
5982
     * @param mixed  $value <p>Its value.</p>
5983
     *
5984
     * @return $this
5985
     *               <p>(Mutable) Return this Arrayy object.</p>
5986
     *
5987
     * @phpstan-param  TKey $key
5988
     * @phpstan-param  T $value
5989
     * @phpstan-return static<TKey,T>
5990
     */
5991 28
    public function set($key, $value): self
5992
    {
5993 28
        $this->internalSet($key, $value);
5994
5995 27
        return $this;
5996
    }
5997
5998
    /**
5999
     * Get a value from a array and set it if it was not.
6000
     *
6001
     * WARNING: this method only set the value, if the $key is not already set
6002
     *
6003
     * EXAMPLE: <code>
6004
     * $arrayy = a([1 => 1, 2 => 2, 3 => 3]);
6005
     * $arrayy->setAndGet(1, 4); // 1
6006
     * $arrayy->setAndGet(0, 4); // 4
6007
     * </code>
6008
     *
6009
     * @param mixed $key      <p>The key</p>
6010
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
6011
     *
6012
     * @return mixed
6013
     *               <p>(Mutable)</p>
6014
     */
6015 11
    public function setAndGet($key, $fallback = null)
6016
    {
6017 11
        $this->generatorToArray();
6018
6019
        // If the key doesn't exist, set it.
6020 11
        if (!$this->has($key)) {
6021 4
            $this->array = $this->set($key, $fallback)->toArray();
6022
        }
6023
6024 11
        return $this->get($key);
6025
    }
6026
6027
    /**
6028
     * Shifts a specified value off the beginning of array.
6029
     *
6030
     * @return mixed
6031
     *               <p>(Mutable) A shifted element from the current array.</p>
6032
     */
6033 5
    public function shift()
6034
    {
6035 5
        $this->generatorToArray();
6036
6037 5
        return \array_shift($this->array);
6038
    }
6039
6040
    /**
6041
     * Shuffle the current array.
6042
     *
6043
     * EXAMPLE: <code>
6044
     * a([1 => 'bar', 'foo' => 'foo'])->shuffle(); // e.g.: Arrayy[['foo' => 'foo', 1 => 'bar']]
6045
     * </code>
6046
     *
6047
     * @param bool       $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
6048
     * @param array|null $array  [optional]
6049
     *
6050
     * @return static
6051
     *                <p>(Immutable)</p>
6052
     *
6053
     * @phpstan-param  array<TKey,T> $array
6054
     * @phpstan-return static<TKey,T>
6055
     *
6056
     * @noinspection BadExceptionsProcessingInspection
6057
     * @noinspection NonSecureShuffleUsageInspection
6058
     */
6059 2
    public function shuffle(bool $secure = false, array $array = null): self
6060
    {
6061 2
        if ($array === null) {
6062 2
            $array = $this->toArray(false);
6063
        }
6064
6065 2
        if ($secure !== true) {
6066 2
            \shuffle($array);
6067
        } else {
6068 1
            $size = \count($array, \COUNT_NORMAL);
6069 1
            $keys = \array_keys($array);
6070 1
            for ($i = $size - 1; $i > 0; --$i) {
6071
                try {
6072 1
                    $r = \random_int(0, $i);
6073
                } catch (\Exception $e) {
6074
                    $r = \mt_rand(0, $i);
6075
                }
6076 1
                if ($r !== $i) {
6077
                    $temp = $array[$keys[$r]];
6078
                    $array[$keys[$r]] = $array[$keys[$i]];
6079
                    $array[$keys[$i]] = $temp;
6080
                }
6081
            }
6082
        }
6083
6084 2
        foreach ($array as $key => $value) {
6085
            // check if recursive is needed
6086 2
            if (\is_array($value)) {
6087
                /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
6088
                /** @phpstan-var array<TKey,T> $value */
6089
                $value = $value;
0 ignored issues
show
Bug introduced by
Why assign $value to itself?

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

This assignement can be removed without consequences.

Loading history...
6090
6091 2
                $array[$key] = $this->shuffle($secure, $value);
6092
            }
6093
        }
6094
6095 2
        return static::create(
6096 2
            $array,
6097 2
            $this->iteratorClass,
6098 2
            false
6099
        );
6100
    }
6101
6102
    /**
6103
     * Count the values from the current array.
6104
     *
6105
     * alias: for "Arrayy->count()"
6106
     *
6107
     * @param int $mode
6108
     *
6109
     * @return int
6110
     */
6111 20
    public function size(int $mode = \COUNT_NORMAL): int
6112
    {
6113 20
        return $this->count($mode);
6114
    }
6115
6116
    /**
6117
     * Checks whether array has exactly $size items.
6118
     *
6119
     * @param int $size
6120
     *
6121
     * @return bool
6122
     */
6123 1
    public function sizeIs(int $size): bool
6124
    {
6125
        // init
6126 1
        $itemsTempCount = 0;
6127
6128
        /** @noinspection PhpUnusedLocalVariableInspection */
6129
        /** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
6130 1
        foreach ($this->getGeneratorByReference() as &$value) {
6131 1
            ++$itemsTempCount;
6132 1
            if ($itemsTempCount > $size) {
6133 1
                return false;
6134
            }
6135
        }
6136
6137 1
        return $itemsTempCount === $size;
6138
    }
6139
6140
    /**
6141
     * Checks whether array has between $fromSize to $toSize items. $toSize can be
6142
     * smaller than $fromSize.
6143
     *
6144
     * @param int $fromSize
6145
     * @param int $toSize
6146
     *
6147
     * @return bool
6148
     */
6149 1
    public function sizeIsBetween(int $fromSize, int $toSize): bool
6150
    {
6151 1
        if ($fromSize > $toSize) {
6152 1
            $tmp = $toSize;
6153 1
            $toSize = $fromSize;
6154 1
            $fromSize = $tmp;
6155
        }
6156
6157
        // init
6158 1
        $itemsTempCount = 0;
6159
6160 1
        foreach ($this->getGenerator() as $key => $value) {
6161 1
            ++$itemsTempCount;
6162 1
            if ($itemsTempCount > $toSize) {
6163 1
                return false;
6164
            }
6165
        }
6166
6167 1
        return $fromSize < $itemsTempCount && $itemsTempCount < $toSize;
6168
    }
6169
6170
    /**
6171
     * Checks whether array has more than $size items.
6172
     *
6173
     * @param int $size
6174
     *
6175
     * @return bool
6176
     */
6177 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...
6178
    {
6179
        // init
6180 1
        $itemsTempCount = 0;
6181
6182 1
        foreach ($this->getGenerator() as $key => $value) {
6183 1
            ++$itemsTempCount;
6184 1
            if ($itemsTempCount > $size) {
6185 1
                return true;
6186
            }
6187
        }
6188
6189 1
        return $itemsTempCount > $size;
6190
    }
6191
6192
    /**
6193
     * Checks whether array has less than $size items.
6194
     *
6195
     * @param int $size
6196
     *
6197
     * @return bool
6198
     */
6199 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...
6200
    {
6201
        // init
6202 1
        $itemsTempCount = 0;
6203
6204 1
        foreach ($this->getGenerator() as $key => $value) {
6205 1
            ++$itemsTempCount;
6206 1
            if ($itemsTempCount > $size) {
6207 1
                return false;
6208
            }
6209
        }
6210
6211 1
        return $itemsTempCount < $size;
6212
    }
6213
6214
    /**
6215
     * Counts all elements in an array, or something in an object.
6216
     *
6217
     * <p>
6218
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
6219
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
6220
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
6221
     * implemented and used in PHP.
6222
     * </p>
6223
     *
6224
     * @return int
6225
     *             <p>
6226
     *             The number of elements in var, which is
6227
     *             typically an array, since anything else will have one
6228
     *             element.
6229
     *             </p>
6230
     *             <p>
6231
     *             If var is not an array or an object with
6232
     *             implemented Countable interface,
6233
     *             1 will be returned.
6234
     *             There is one exception, if var is &null;,
6235
     *             0 will be returned.
6236
     *             </p>
6237
     *             <p>
6238
     *             Caution: count may return 0 for a variable that isn't set,
6239
     *             but it may also return 0 for a variable that has been initialized with an
6240
     *             empty array. Use isset to test if a variable is set.
6241
     *             </p>
6242
     */
6243 10
    public function sizeRecursive(): int
6244
    {
6245 10
        return \count($this->toArray(), \COUNT_RECURSIVE);
6246
    }
6247
6248
    /**
6249
     * Extract a slice of the array.
6250
     *
6251
     * @param int      $offset       <p>Slice begin index.</p>
6252
     * @param int|null $length       <p>Length of the slice.</p>
6253
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
6254
     *
6255
     * @return static
6256
     *                <p>(Immutable) A slice of the original array with length $length.</p>
6257
     *
6258
     * @phpstan-return static<TKey,T>
6259
     * @psalm-mutation-free
6260
     */
6261 5
    public function slice(int $offset, int $length = null, bool $preserveKeys = false)
6262
    {
6263 5
        return static::create(
6264 5
            \array_slice(
6265 5
                $this->toArray(),
6266 5
                $offset,
6267 5
                $length,
6268 5
                $preserveKeys
6269
            ),
6270 5
            $this->iteratorClass,
6271 5
            false
6272
        );
6273
    }
6274
6275
    /**
6276
     * Sort the current array and optional you can keep the keys.
6277
     *
6278
     * EXAMPLE: <code>
6279
     * a(3 => 'd', 2 => 'f', 0 => 'a')->sort(SORT_ASC, SORT_NATURAL, false); // Arrayy[0 => 'a', 1 => 'd', 2 => 'f']
6280
     * </code>
6281
     *
6282
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6283
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
6284
     *                              <strong>SORT_NATURAL</strong></p>
6285
     * @param bool       $keepKeys
6286
     *
6287
     * @return static
6288
     *                <p>(Mutable) Return this Arrayy object.</p>
6289
     *
6290
     * @phpstan-return static<int|TKey,T>
6291
     */
6292 20
    public function sort(
6293
        $direction = \SORT_ASC,
6294
        int $strategy = \SORT_REGULAR,
6295
        bool $keepKeys = false
6296
    ): self {
6297 20
        $this->generatorToArray();
6298
6299 20
        return $this->sorting(
6300 20
            $this->array,
6301 20
            $direction,
6302 20
            $strategy,
6303 20
            $keepKeys
6304
        );
6305
    }
6306
6307
    /**
6308
     * Sort the current array and optional you can keep the keys.
6309
     *
6310
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6311
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
6312
     *                              <strong>SORT_NATURAL</strong></p>
6313
     * @param bool       $keepKeys
6314
     *
6315
     * @return static
6316
     *                <p>(Immutable) Return this Arrayy object.</p>
6317
     *
6318
     * @phpstan-return static<int|TKey,T>
6319
     */
6320 12
    public function sortImmutable(
6321
        $direction = \SORT_ASC,
6322
        int $strategy = \SORT_REGULAR,
6323
        bool $keepKeys = false
6324
    ): self {
6325 12
        $that = clone $this;
6326
6327 12
        $that->generatorToArray();
6328
6329 12
        return $that->sorting(
6330 12
            $that->array,
6331 12
            $direction,
6332 12
            $strategy,
6333 12
            $keepKeys
6334
        );
6335
    }
6336
6337
    /**
6338
     * Sort the current array by key.
6339
     *
6340
     * EXAMPLE: <code>
6341
     * a([1 => 2, 0 => 1])->sortKeys(\SORT_ASC); // Arrayy[0 => 1, 1 => 2]
6342
     * </code>
6343
     *
6344
     * @see http://php.net/manual/en/function.ksort.php
6345
     * @see http://php.net/manual/en/function.krsort.php
6346
     *
6347
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6348
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
6349
     *                              <strong>SORT_NATURAL</strong></p>
6350
     *
6351
     * @return $this
6352
     *               <p>(Mutable) Return this Arrayy object.</p>
6353
     *
6354
     * @phpstan-return static<TKey,T>
6355
     */
6356 18
    public function sortKeys(
6357
        $direction = \SORT_ASC,
6358
        int $strategy = \SORT_REGULAR
6359
    ): self {
6360 18
        $this->generatorToArray();
6361
6362 18
        $this->sorterKeys($this->array, $direction, $strategy);
6363
6364 18
        return $this;
6365
    }
6366
6367
    /**
6368
     * Sort the current array by key.
6369
     *
6370
     * @see          http://php.net/manual/en/function.ksort.php
6371
     * @see          http://php.net/manual/en/function.krsort.php
6372
     *
6373
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6374
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
6375
     *                              <strong>SORT_NATURAL</strong></p>
6376
     *
6377
     * @return $this
6378
     *               <p>(Immutable) Return this Arrayy object.</p>
6379
     *
6380
     * @phpstan-return static<TKey,T>
6381
     * @psalm-mutation-free
6382
     */
6383 8
    public function sortKeysImmutable(
6384
        $direction = \SORT_ASC,
6385
        int $strategy = \SORT_REGULAR
6386
    ): self {
6387 8
        $that = clone $this;
6388
6389
        /**
6390
         * @psalm-suppress ImpureMethodCall - object is already cloned
6391
         */
6392 8
        $that->sortKeys($direction, $strategy);
6393
6394 8
        return $that;
6395
    }
6396
6397
    /**
6398
     * Sort the current array by value.
6399
     *
6400
     * EXAMPLE: <code>
6401
     * a(3 => 'd', 2 => 'f', 0 => 'a')->sortValueKeepIndex(SORT_ASC, SORT_REGULAR); // Arrayy[0 => 'a', 3 => 'd', 2 => 'f']
6402
     * </code>
6403
     *
6404
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6405
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
6406
     *                              <strong>SORT_NATURAL</strong></p>
6407
     *
6408
     * @return static
6409
     *                <p>(Mutable)</p>
6410
     *
6411
     * @phpstan-return static<int|TKey,T>
6412
     */
6413 1
    public function sortValueKeepIndex(
6414
        $direction = \SORT_ASC,
6415
        int $strategy = \SORT_REGULAR
6416
    ): self {
6417 1
        return $this->sort($direction, $strategy, true);
6418
    }
6419
6420
    /**
6421
     * Sort the current array by value.
6422
     *
6423
     * EXAMPLE: <code>
6424
     * a(3 => 'd', 2 => 'f', 0 => 'a')->sortValueNewIndex(SORT_ASC, SORT_NATURAL); // Arrayy[0 => 'a', 1 => 'd', 2 => 'f']
6425
     * </code>
6426
     *
6427
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
6428
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
6429
     *                              <strong>SORT_NATURAL</strong></p>
6430
     *
6431
     * @return static
6432
     *                <p>(Mutable)</p>
6433
     *
6434
     * @phpstan-return static<int|TKey,T>
6435
     */
6436 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
6437
    {
6438 1
        return $this->sort($direction, $strategy, false);
6439
    }
6440
6441
    /**
6442
     * Sort a array by value or by a closure.
6443
     *
6444
     * - If the sorter is null, the array is sorted naturally.
6445
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
6446
     *
6447
     * EXAMPLE: <code>
6448
     * $testArray = range(1, 5);
6449
     * $under = a($testArray)->sorter(
6450
     *     function ($value) {
6451
     *         return $value % 2 === 0;
6452
     *     }
6453
     * );
6454
     * var_dump($under); // Arrayy[1, 3, 5, 2, 4]
6455
     * </code>
6456
     *
6457
     * @param callable|mixed|null $sorter
6458
     * @param int|string          $direction <p>use <strong>SORT_ASC</strong> (default) or
6459
     *                                       <strong>SORT_DESC</strong></p>
6460
     * @param int                 $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
6461
     *                                       <strong>SORT_NATURAL</strong></p>
6462
     *
6463
     * @return static
6464
     *                <p>(Immutable)</p>
6465
     *
6466
     * @pslam-param callable|T|null $sorter
6467
     * @phpstan-return static<TKey,T>
6468
     * @psalm-mutation-free
6469
     */
6470 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
6471
    {
6472 1
        $array = $this->toArray();
6473 1
        $direction = $this->getDirection($direction);
6474
6475
        // Transform all values into their results.
6476 1
        if ($sorter) {
6477 1
            $arrayy = static::create(
6478 1
                $array,
6479 1
                $this->iteratorClass,
6480 1
                false
6481
            );
6482
6483
            /**
6484
             * @psalm-suppress MissingClosureReturnType
6485
             * @psalm-suppress MissingClosureParamType
6486
             */
6487 1
            $results = $arrayy->each(
6488
                static function ($value) use ($sorter) {
6489 1
                    if (\is_callable($sorter) === true) {
6490 1
                        return $sorter($value);
6491
                    }
6492
6493 1
                    return $sorter === $value;
6494 1
                }
6495
            );
6496
6497 1
            $results = $results->toArray();
6498
        } else {
6499 1
            $results = $array;
6500
        }
6501
6502
        // Sort by the results and replace by original values
6503 1
        \array_multisort($results, $direction, $strategy, $array);
6504
6505 1
        return static::create(
6506 1
            $array,
6507 1
            $this->iteratorClass,
6508 1
            false
6509
        );
6510
    }
6511
6512
    /**
6513
     * @param int      $offset
6514
     * @param int|null $length
6515
     * @param array    $replacement
6516
     *
6517
     * @return static
6518
     *                <p>(Immutable)</p>
6519
     *
6520
     * @phpstan-param  array<mixed,T> $replacement
6521
     * @phpstan-return static<TKey,T>
6522
     * @psalm-mutation-free
6523
     */
6524 1
    public function splice(int $offset, int $length = null, $replacement = []): self
6525
    {
6526 1
        $tmpArray = $this->toArray();
6527
6528 1
        \array_splice(
6529 1
            $tmpArray,
6530 1
            $offset,
6531 1
            $length ?? $this->count(),
6532 1
            $replacement
6533
        );
6534
6535 1
        return static::create(
6536 1
            $tmpArray,
6537 1
            $this->iteratorClass,
6538 1
            false
6539
        );
6540
    }
6541
6542
    /**
6543
     * Split an array in the given amount of pieces.
6544
     *
6545
     * EXAMPLE: <code>
6546
     * a(['a' => 1, 'b' => 2])->split(2, true); // Arrayy[['a' => 1], ['b' => 2]]
6547
     * </code>
6548
     *
6549
     * @param int  $numberOfPieces
6550
     * @param bool $keepKeys
6551
     *
6552
     * @return static
6553
     *                <p>(Immutable)</p>
6554
     *
6555
     * @phpstan-return static<TKey,T>
6556
     * @psalm-mutation-free
6557
     */
6558 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
6559
    {
6560 1
        if ($keepKeys) {
6561
            $generator = function () use ($numberOfPieces) {
6562 1
                $carry = [];
6563 1
                $i = 1;
6564 1
                foreach ($this->getGenerator() as $key => $value) {
6565 1
                    $carry[$key] = $value;
6566
6567 1
                    if ($i % $numberOfPieces !== 0) {
6568 1
                        ++$i;
6569
6570 1
                        continue;
6571
                    }
6572
6573 1
                    yield $carry;
6574
6575 1
                    $carry = [];
6576 1
                    $i = 1;
6577
                }
6578
6579 1
                if ($carry !== []) {
6580 1
                    yield $carry;
6581
                }
6582 1
            };
6583 View Code Duplication
        } else {
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...
6584
            $generator = function () use ($numberOfPieces) {
6585 1
                $carry = [];
6586 1
                $i = 1;
6587 1
                foreach ($this->getGenerator() as $key => $value) {
6588 1
                    $carry[] = $value;
6589
6590 1
                    if ($i % $numberOfPieces !== 0) {
6591 1
                        ++$i;
6592
6593 1
                        continue;
6594
                    }
6595
6596 1
                    yield $carry;
6597
6598 1
                    $carry = [];
6599 1
                    $i = 1;
6600
                }
6601
6602 1
                if ($carry !== []) {
6603 1
                    yield $carry;
6604
                }
6605 1
            };
6606
        }
6607
6608 1
        return static::create(
6609 1
            $generator,
6610 1
            $this->iteratorClass,
6611 1
            false
6612
        );
6613
    }
6614
6615
    /**
6616
     * Strip all empty items from the current array.
6617
     *
6618
     * EXAMPLE: <code>
6619
     * a(['a' => 1, 'b' => ''])->stripEmpty(); // Arrayy[['a' => 1]]
6620
     * </code>
6621
     *
6622
     * @return static
6623
     *                <p>(Immutable)</p>
6624
     *
6625
     * @phpstan-return static<TKey,T>
6626
     * @psalm-mutation-free
6627
     */
6628 1
    public function stripEmpty(): self
6629
    {
6630 1
        return $this->filter(
6631
            static function ($item) {
6632 1
                if ($item === null) {
6633 1
                    return false;
6634
                }
6635
6636 1
                return (bool) \trim((string) $item);
6637 1
            }
6638
        );
6639
    }
6640
6641
    /**
6642
     * Swap two values between positions by key.
6643
     *
6644
     * EXAMPLE: <code>
6645
     * a(['a' => 1, 'b' => ''])->swap('a', 'b'); // Arrayy[['a' => '', 'b' => 1]]
6646
     * </code>
6647
     *
6648
     * @param int|string $swapA <p>a key in the array</p>
6649
     * @param int|string $swapB <p>a key in the array</p>
6650
     *
6651
     * @return static
6652
     *                <p>(Immutable)</p>
6653
     *
6654
     * @phpstan-return static<TKey,T>
6655
     * @psalm-mutation-free
6656
     */
6657 1
    public function swap($swapA, $swapB): self
6658
    {
6659 1
        $array = $this->toArray();
6660
6661 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
6662
6663 1
        return static::create(
6664 1
            $array,
6665 1
            $this->iteratorClass,
6666 1
            false
6667
        );
6668
    }
6669
6670
    /**
6671
     * Get the current array from the "Arrayy"-object.
6672
     * alias for "getArray()"
6673
     *
6674
     * @param bool $convertAllArrayyElements <p>
6675
     *                                       Convert all Child-"Arrayy" objects also to arrays.
6676
     *                                       </p>
6677
     * @param bool $preserveKeys             <p>
6678
     *                                       e.g.: A generator maybe return the same key more then once,
6679
     *                                       so maybe you will ignore the keys.
6680
     *                                       </p>
6681
     *
6682
     * @return array
6683
     *
6684
     * @phpstan-return array<TKey,T>
6685
     * @psalm-mutation-free
6686
     */
6687 941
    public function toArray(
6688
        bool $convertAllArrayyElements = false,
6689
        bool $preserveKeys = true
6690
    ): array {
6691
        // init
6692 941
        $array = [];
6693
6694 941
        if ($convertAllArrayyElements) {
6695 2
            foreach ($this->getGenerator() as $key => $value) {
6696 2
                if ($value instanceof self) {
6697 1
                    $value = $value->toArray(
6698 1
                        $convertAllArrayyElements,
6699 1
                        $preserveKeys
6700
                    );
6701
                }
6702
6703 2
                if ($preserveKeys) {
6704 1
                    $array[$key] = $value;
6705
                } else {
6706 2
                    $array[] = $value;
6707
                }
6708
            }
6709
        } else {
6710 941
            $array = \iterator_to_array($this->getGenerator(), $preserveKeys);
6711
        }
6712
6713
        /** @phpstan-ignore-next-line - depends on the $convertAllArrayyElements parameter :/ */
6714 941
        return $array;
6715
    }
6716
6717
    /**
6718
     * Get the current array from the "Arrayy"-object as list.
6719
     *
6720
     * @param bool $convertAllArrayyElements <p>
6721
     *                                       Convert all Child-"Arrayy" objects also to arrays.
6722
     *                                       </p>
6723
     *
6724
     * @return array
6725
     *
6726
     * @phpstan-return list<mixed>|list<T>
6727
     * @psalm-mutation-free
6728
     */
6729 1
    public function toList(bool $convertAllArrayyElements = false): array
6730
    {
6731 1
        return $this->toArray(
6732 1
            $convertAllArrayyElements,
6733 1
            false
6734
        );
6735
    }
6736
6737
    /**
6738
     * Convert the current array to JSON.
6739
     *
6740
     * EXAMPLE: <code>
6741
     * a(['bar', ['foo']])->toJson(); // '["bar",{"1":"foo"}]'
6742
     * </code>
6743
     *
6744
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
6745
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
6746
     *
6747
     * @return string
6748
     */
6749 12
    public function toJson(int $options = 0, int $depth = 512): string
6750
    {
6751 12
        $return = \json_encode($this->toArray(), $options, $depth);
6752 12
        if ($return === false) {
6753
            return '';
6754
        }
6755
6756 12
        return $return;
6757
    }
6758
6759
    /**
6760
     * @param string[]|null $items  [optional]
6761
     * @param string[]      $helper [optional]
6762
     *
6763
     * @return static|static[]
6764
     *
6765
     * @phpstan-return static<int, static<TKey,T>>
6766
     */
6767 1
    public function toPermutation(array $items = null, array $helper = []): self
6768
    {
6769
        // init
6770 1
        $return = [];
6771
6772 1
        if ($items === null) {
6773 1
            $items = $this->toArray();
6774
        }
6775
6776 1
        if (empty($items)) {
6777 1
            $return[] = $helper;
6778
        } else {
6779 1
            for ($i = \count($items) - 1; $i >= 0; --$i) {
6780 1
                $new_items = $items;
6781 1
                $new_helper = $helper;
6782 1
                list($tmp_helper) = \array_splice($new_items, $i, 1);
6783
                /** @noinspection PhpSillyAssignmentInspection */
6784
                /** @var string[] $new_items */
6785 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...
6786 1
                \array_unshift($new_helper, $tmp_helper);
6787 1
                $return = \array_merge(
6788 1
                    $return,
6789 1
                    $this->toPermutation($new_items, $new_helper)->toArray()
6790
                );
6791
            }
6792
        }
6793
6794 1
        return static::create(
6795 1
            $return,
6796 1
            $this->iteratorClass,
6797 1
            false
6798
        );
6799
    }
6800
6801
    /**
6802
     * Implodes array to a string with specified separator.
6803
     *
6804
     * @param string $separator [optional] <p>The element's separator.</p>
6805
     *
6806
     * @return string
6807
     *                <p>The string representation of array, separated by ",".</p>
6808
     */
6809 19
    public function toString(string $separator = ','): string
6810
    {
6811 19
        return $this->implode($separator);
6812
    }
6813
6814
    /**
6815
     * Return a duplicate free copy of the current array.
6816
     *
6817
     * EXAMPLE: <code>
6818
     * a([2 => 1, 3 => 2, 4 => 2])->uniqueNewIndex(); // Arrayy[1, 2]
6819
     * </code>
6820
     *
6821
     * @return $this
6822
     *               <p>(Mutable)</p>
6823
     *
6824
     * @phpstan-return static<int,T>
6825
     */
6826 13
    public function uniqueNewIndex(): self
6827
    {
6828
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
6829
6830 13
        $this->array = $this->reduce(
6831
            static function ($resultArray, $value, $key) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
6832 12
                if (!\in_array($value, $resultArray, true)) {
6833 12
                    $resultArray[] = $value;
6834
                }
6835
6836 12
                return $resultArray;
6837 13
            },
6838 13
            []
6839 13
        )->toArray();
6840 13
        $this->generator = null;
6841
6842 13
        return $this;
6843
    }
6844
6845
    /**
6846
     * Return a duplicate free copy of the current array. (with the old keys)
6847
     *
6848
     * EXAMPLE: <code>
6849
     * a([2 => 1, 3 => 2, 4 => 2])->uniqueNewIndex(); // Arrayy[2 => 1, 3 => 2]
6850
     * </code>
6851
     *
6852
     * @return $this
6853
     *               <p>(Mutable)</p>
6854
     *
6855
     * @phpstan-return static<TKey,T>
6856
     */
6857 11
    public function uniqueKeepIndex(): self
6858
    {
6859
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
6860
6861
        // init
6862 11
        $array = $this->toArray();
6863
6864
        /**
6865
         * @psalm-suppress MissingClosureReturnType
6866
         * @psalm-suppress MissingClosureParamType
6867
         */
6868 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...
6869 11
            \array_keys($array),
6870
            static function ($resultArray, $key) use ($array) {
6871 10
                if (!\in_array($array[$key], $resultArray, true)) {
6872 10
                    $resultArray[$key] = $array[$key];
6873
                }
6874
6875 10
                return $resultArray;
6876 11
            },
6877 11
            []
6878
        );
6879 11
        $this->generator = null;
6880
6881 11
        return $this;
6882
    }
6883
6884
    /**
6885
     * alias: for "Arrayy->uniqueNewIndex()"
6886
     *
6887
     * @return static
6888
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
6889
     *
6890
     * @see          Arrayy::unique()
6891
     *
6892
     * @phpstan-return static<int,T>
6893
     */
6894 13
    public function unique(): self
6895
    {
6896 13
        return $this->uniqueNewIndex();
6897
    }
6898
6899
    /**
6900
     * Prepends one or more values to the beginning of array at once.
6901
     *
6902
     * @param mixed ...$args
6903
     *
6904
     * @return $this
6905
     *               <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
6906
     *
6907
     * @phpstan-param  array<TKey,T> ...$args
6908
     * @phpstan-return static<TKey,T>
6909
     */
6910 6 View Code Duplication
    public function unshift(...$args): 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...
6911
    {
6912 6
        $this->generatorToArray();
6913
6914
        if (
6915 6
            $this->checkPropertyTypes
6916
            &&
6917 6
            $this->properties !== []
6918
        ) {
6919 2
            foreach ($args as $key => $value) {
6920 2
                $this->checkType($key, $value);
6921
            }
6922
        }
6923
6924 5
        \array_unshift($this->array, ...$args);
6925
6926 5
        return $this;
6927
    }
6928
6929
    /**
6930
     * Tests whether the given closure return something valid for all elements of this array.
6931
     *
6932
     * @param \Closure $closure the predicate
6933
     *
6934
     * @return bool
6935
     *              <p>TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.</p>
6936
     *
6937
     * @phpstan-param \Closure(T=,TKey=):bool $closure
6938
     */
6939 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...
6940
    {
6941 1
        foreach ($this->getGenerator() as $key => $value) {
6942 1
            if (!$closure($value, $key)) {
6943 1
                return false;
6944
            }
6945
        }
6946
6947 1
        return true;
6948
    }
6949
6950
    /**
6951
     * Get all values from a array.
6952
     *
6953
     * EXAMPLE: <code>
6954
     * $arrayy = a([1 => 'foo', 2 => 'foo2', 3 => 'bar']);
6955
     * $arrayyTmp->values(); // Arrayy[0 => 'foo', 1 => 'foo2', 2 => 'bar']
6956
     * </code>
6957
     *
6958
     * @return static
6959
     *                <p>(Immutable)</p>
6960
     *
6961
     * @phpstan-return static<TKey,T>
6962
     * @psalm-mutation-free
6963
     */
6964 2
    public function values(): self
6965
    {
6966 2
        return static::create(
6967
            function () {
6968
                /** @noinspection YieldFromCanBeUsedInspection */
6969 2
                foreach ($this->getGenerator() as $value) {
6970 2
                    yield $value;
6971
                }
6972 2
            },
6973 2
            $this->iteratorClass,
6974 2
            false
6975
        );
6976
    }
6977
6978
    /**
6979
     * Apply the given function to every element in the array, discarding the results.
6980
     *
6981
     * EXAMPLE: <code>
6982
     * $callable = function (&$value, $key) {
6983
     *     $value = $key;
6984
     * };
6985
     * $arrayy = a([1, 2, 3]);
6986
     * $arrayy->walk($callable); // Arrayy[0, 1, 2]
6987
     * </code>
6988
     *
6989
     * @param callable $callable
6990
     * @param bool     $recursive [optional] <p>Whether array will be walked recursively or no</p>
6991
     * @param mixed    $userData  [optional] <p>
6992
     *                            If the optional $userData parameter is supplied,
6993
     *                            it will be passed as the third parameter to the $callable.
6994
     *                            </p>
6995
     *
6996
     * @return $this
6997
     *               <p>(Mutable) Return this Arrayy object, with modified elements.</p>
6998
     *
6999
     * @phpstan-return static<TKey,T>
7000
     */
7001 12
    public function walk(
7002
        $callable,
7003
        bool $recursive = false,
7004
        $userData = self::ARRAYY_HELPER_WALK
7005
    ): self {
7006 12
        $this->generatorToArray();
7007
7008 12
        if ($this->array !== []) {
7009 10
            if ($recursive === true) {
7010 5
                if ($userData !== self::ARRAYY_HELPER_WALK) {
7011
                    \array_walk_recursive($this->array, $callable, $userData);
7012
                } else {
7013 5
                    \array_walk_recursive($this->array, $callable);
7014
                }
7015
            } else {
7016
                /** @noinspection NestedPositiveIfStatementsInspection */
7017 5
                if ($userData !== self::ARRAYY_HELPER_WALK) {
7018
                    \array_walk($this->array, $callable, $userData);
7019
                } else {
7020 5
                    \array_walk($this->array, $callable);
7021
                }
7022
            }
7023
        }
7024
7025 12
        return $this;
7026
    }
7027
7028
    /**
7029
     * Returns a collection of matching items.
7030
     *
7031
     * @param string $keyOrPropertyOrMethod the property or method to evaluate
7032
     * @param mixed  $value                 the value to match
7033
     *
7034
     * @throws \InvalidArgumentException if property or method is not defined
7035
     *
7036
     * @return static
7037
     *
7038
     * @phpstan-return static<TKey,T>
7039
     */
7040 1
    public function where(string $keyOrPropertyOrMethod, $value): self
7041
    {
7042 1
        return $this->filter(
7043
            function ($item) use ($keyOrPropertyOrMethod, $value) {
7044
                $accessorValue = $this->extractValue(
7045
                    $item,
7046
                    $keyOrPropertyOrMethod
7047
                );
7048
7049
                return $accessorValue === $value;
7050 1
            }
7051
        );
7052
    }
7053
7054
    /**
7055
     * Convert an array into a object.
7056
     *
7057
     * @param array $array
7058
     *
7059
     * @return \stdClass
7060
     *
7061
     * @phpstan-param array<int|string,mixed> $array
7062
     */
7063 4
    final protected static function arrayToObject(array $array = []): \stdClass
7064
    {
7065
        // init
7066 4
        $object = new \stdClass();
7067
7068 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
7069 1
            return $object;
7070
        }
7071
7072 3
        foreach ($array as $name => $value) {
7073 3
            if (\is_array($value)) {
7074 1
                $object->{$name} = static::arrayToObject($value);
7075
            } else {
7076 3
                $object->{$name} = $value;
7077
            }
7078
        }
7079
7080 3
        return $object;
7081
    }
7082
7083
    /**
7084
     * @param array|\Generator|null $input         <p>
7085
     *                                             An array containing keys to return.
7086
     *                                             </p>
7087
     * @param mixed|null            $search_values [optional] <p>
7088
     *                                             If specified, then only keys containing these values are returned.
7089
     *                                             </p>
7090
     * @param bool                  $strict        [optional] <p>
7091
     *                                             Determines if strict comparison (===) should be used during the
7092
     *                                             search.
7093
     *                                             </p>
7094
     *
7095
     * @return array
7096
     *               <p>An array of all the keys in input.</p>
7097
     *
7098
     * @phpstan-param  array<mixed>|null $input
7099
     * @phpstan-return array<mixed>
7100
     * @psalm-mutation-free
7101
     */
7102 11
    protected function array_keys_recursive(
7103
        $input = null,
7104
        $search_values = null,
7105
        bool $strict = true
7106
    ): array {
7107
        // init
7108 11
        $keys = [];
7109 11
        $keysTmp = [];
7110
7111 11
        if ($input === null) {
7112 4
            $input = $this->getGenerator();
7113
        }
7114
7115 11
        if ($search_values === null) {
7116 11
            foreach ($input as $key => $value) {
7117 11
                $keys[] = $key;
7118
7119
                // check if recursive is needed
7120 11
                if (\is_array($value)) {
7121 11
                    $keysTmp[] = $this->array_keys_recursive($value);
7122
                }
7123
            }
7124
        } else {
7125 1
            $is_array_tmp = \is_array($search_values);
7126
7127 1
            foreach ($input as $key => $value) {
7128 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...
7129
                    (
7130 1
                        $is_array_tmp === false
7131
                        &&
7132 1
                        $strict === true
7133
                        &&
7134 1
                        $search_values === $value
7135
                    )
7136
                    ||
7137
                    (
7138 1
                        $is_array_tmp === false
7139
                        &&
7140 1
                        $strict === false
7141
                        &&
7142 1
                        $search_values == $value
7143
                    )
7144
                    ||
7145
                    (
7146 1
                        $is_array_tmp === true
7147
                        &&
7148 1
                        \in_array($value, $search_values, $strict)
7149
                    )
7150
                ) {
7151 1
                    $keys[] = $key;
7152
                }
7153
7154
                // check if recursive is needed
7155 1
                if (\is_array($value)) {
7156 1
                    $keysTmp[] = $this->array_keys_recursive($value);
7157
                }
7158
            }
7159
        }
7160
7161 11
        return $keysTmp === [] ? $keys : \array_merge($keys, ...$keysTmp);
7162
    }
7163
7164
    /**
7165
     * @param mixed      $path
7166
     * @param callable   $callable
7167
     * @param array|null $currentOffset
7168
     *
7169
     * @return void
7170
     *
7171
     * @phpstan-param array<TKey,T>|null $currentOffset
7172
     * @psalm-mutation-free
7173
     */
7174 10
    protected function callAtPath($path, $callable, &$currentOffset = null)
7175
    {
7176 10
        $this->generatorToArray();
7177
7178 10
        if ($currentOffset === null) {
7179 10
            $currentOffset = &$this->array;
7180
        }
7181
7182 10
        $explodedPath = \explode($this->pathSeparator, $path);
7183 10
        if ($explodedPath === false) {
7184
            return;
7185
        }
7186
7187 10
        $nextPath = \array_shift($explodedPath);
7188
7189 10
        if (!isset($currentOffset[$nextPath])) {
7190 1
            return;
7191
        }
7192
7193 9
        if (!empty($explodedPath)) {
7194 1
            $this->callAtPath(
7195 1
                \implode($this->pathSeparator, $explodedPath),
7196 1
                $callable,
7197 1
                $currentOffset[$nextPath]
7198
            );
7199
        } else {
7200 9
            $callable($currentOffset[$nextPath]);
7201
        }
7202 9
    }
7203
7204
    /**
7205
     * Extracts the value of the given property or method from the object.
7206
     *
7207
     * @param static $object                <p>The object to extract the value from.</p>
7208
     * @param string $keyOrPropertyOrMethod <p>The property or method for which the
7209
     *                                      value should be extracted.</p>
7210
     *
7211
     * @throws \InvalidArgumentException if the method or property is not defined
7212
     *
7213
     * @return mixed
7214
     *               <p>The value extracted from the specified property or method.</p>
7215
     *
7216
     * @phpstan-param self<TKey,T> $object
7217
     */
7218 1
    final protected function extractValue(self $object, string $keyOrPropertyOrMethod)
7219
    {
7220 1
        if (isset($object[$keyOrPropertyOrMethod])) {
7221 1
            $return = $object->get($keyOrPropertyOrMethod);
7222
7223 1
            if ($return instanceof self) {
7224
                return $return->toArray();
7225
            }
7226
7227 1
            return $return;
7228
        }
7229
7230
        if (\property_exists($object, $keyOrPropertyOrMethod)) {
7231
            return $object->{$keyOrPropertyOrMethod};
7232
        }
7233
7234
        if (\method_exists($object, $keyOrPropertyOrMethod)) {
7235
            return $object->{$keyOrPropertyOrMethod}();
7236
        }
7237
7238
        throw new \InvalidArgumentException(\sprintf('array-key & property & method "%s" not defined in %s', $keyOrPropertyOrMethod, \gettype($object)));
7239
    }
7240
7241
    /**
7242
     * create a fallback for array
7243
     *
7244
     * 1. use the current array, if it's a array
7245
     * 2. fallback to empty array, if there is nothing
7246
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
7247
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
7248
     * 5. call "__toArray()" on object, if the method exists
7249
     * 6. cast a string or object with "__toString()" into an array
7250
     * 7. throw a "InvalidArgumentException"-Exception
7251
     *
7252
     * @param mixed $data
7253
     *
7254
     * @throws \InvalidArgumentException
7255
     *
7256
     * @return array
7257
     *
7258
     * @phpstan-return array<mixed>|array<TKey,T>
7259
     */
7260 1212
    protected function fallbackForArray(&$data): array
7261
    {
7262 1212
        $data = $this->internalGetArray($data);
7263
7264 1212
        if ($data === null) {
7265 2
            throw new \InvalidArgumentException('Passed value should be a array');
7266
        }
7267
7268 1210
        return $data;
7269
    }
7270
7271
    /**
7272
     * @param bool $preserveKeys <p>
7273
     *                           e.g.: A generator maybe return the same key more then once,
7274
     *                           so maybe you will ignore the keys.
7275
     *                           </p>
7276
     *
7277
     * @return bool
7278
     *
7279
     * @noinspection ReturnTypeCanBeDeclaredInspection
7280
     * @psalm-mutation-free :/
7281
     */
7282 1121
    protected function generatorToArray(bool $preserveKeys = true)
7283
    {
7284 1121
        if ($this->generator) {
7285 2
            $this->array = $this->toArray(false, $preserveKeys);
7286 2
            $this->generator = null;
7287
7288 2
            return true;
7289
        }
7290
7291 1121
        return false;
7292
    }
7293
7294
    /**
7295
     * Get correct PHP constant for direction.
7296
     *
7297
     * @param int|string $direction
7298
     *
7299
     * @return int
7300
     * @psalm-mutation-free
7301
     */
7302 43
    protected function getDirection($direction): int
7303
    {
7304 43
        if ((string) $direction === $direction) {
7305 10
            $direction = \strtolower($direction);
7306
7307 10
            if ($direction === 'desc') {
7308 2
                $direction = \SORT_DESC;
7309
            } else {
7310 9
                $direction = \SORT_ASC;
7311
            }
7312
        }
7313
7314
        if (
7315 43
            $direction !== \SORT_DESC
7316
            &&
7317 43
            $direction !== \SORT_ASC
7318
        ) {
7319
            $direction = \SORT_ASC;
7320
        }
7321
7322 43
        return $direction;
7323
    }
7324
7325
    /**
7326
     * @return TypeCheckInterface[]
7327
     *
7328
     * @noinspection ReturnTypeCanBeDeclaredInspection
7329
     */
7330 24
    protected function getPropertiesFromPhpDoc()
7331
    {
7332 24
        static $PROPERTY_CACHE = [];
7333 24
        $cacheKey = 'Class::' . static::class;
7334
7335 24
        if (isset($PROPERTY_CACHE[$cacheKey])) {
7336 22
            return $PROPERTY_CACHE[$cacheKey];
7337
        }
7338
7339
        // init
7340 4
        $properties = [];
7341
7342 4
        $reflector = new \ReflectionClass($this);
7343 4
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
7344 4
        $docComment = $reflector->getDocComment();
7345 4 View Code Duplication
        if ($docComment) {
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...
7346 4
            $docblock = $factory->create($docComment);
7347
            /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
7348 4
            foreach ($docblock->getTagsByName('property') as $tag) {
7349 3
                $typeName = $tag->getVariableName();
7350
                /** @var string|null $typeName */
7351 3
                if ($typeName !== null) {
7352 3
                    $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName);
7353 3
                    if ($typeCheckPhpDoc !== null) {
7354 3
                        $properties[$typeName] = $typeCheckPhpDoc;
7355
                    }
7356
                }
7357
            }
7358
        }
7359
7360
        /** @noinspection PhpAssignmentInConditionInspection */
7361 4
        while ($reflector = $reflector->getParentClass()) {
7362 4
            $docComment = $reflector->getDocComment();
7363 4 View Code Duplication
            if ($docComment) {
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...
7364 4
                $docblock = $factory->create($docComment);
7365
                /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
7366 4
                foreach ($docblock->getTagsByName('property') as $tag) {
7367 1
                    $typeName = $tag->getVariableName();
7368
                    /** @var string|null $typeName */
7369 1
                    if ($typeName !== null) {
7370 1
                        if (isset($properties[$typeName])) {
7371 1
                            continue;
7372
                        }
7373
7374 1
                        $typeCheckPhpDoc = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag, $typeName);
7375 1
                        if ($typeCheckPhpDoc !== null) {
7376 1
                            $properties[$typeName] = $typeCheckPhpDoc;
7377
                        }
7378
                    }
7379
                }
7380
            }
7381
        }
7382
7383 4
        return $PROPERTY_CACHE[$cacheKey] = $properties;
7384
    }
7385
7386
    /**
7387
     * @param mixed $glue
7388
     * @param mixed $pieces
7389
     * @param bool  $useKeys
7390
     *
7391
     * @return string
7392
     *
7393
     * @phpstan-param scalar|object|self<TKey|T>|array<TKey,T> $pieces
7394
     * @psalm-mutation-free
7395
     */
7396 36
    protected function implode_recursive(
7397
        $glue = '',
7398
        $pieces = [],
7399
        bool $useKeys = false
7400
    ): string {
7401 36
        if ($pieces instanceof self) {
7402 1
            $pieces = $pieces->toArray();
7403
        }
7404
7405 36
        if (\is_array($pieces)) {
7406
            /** @noinspection PhpSillyAssignmentInspection - hack for phpstan */
7407
            /** @phpstan-var array<TKey,T> $pieces */
7408 36
            $pieces = $pieces;
0 ignored issues
show
Bug introduced by
Why assign $pieces to itself?

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

This assignement can be removed without consequences.

Loading history...
7409
7410 36
            $pieces_count = \count($pieces, \COUNT_NORMAL);
7411 36
            $pieces_count_not_zero = $pieces_count > 0;
7412
7413 36
            return \implode(
7414 36
                $glue,
7415 36
                \array_map(
7416 36
                    [$this, 'implode_recursive'],
7417 36
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
7418 36
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
7419
                )
7420
            );
7421
        }
7422
7423
        if (
7424 36
            \is_scalar($pieces) === true
7425
            ||
7426 36
            (\is_object($pieces) && \method_exists($pieces, '__toString'))
7427
        ) {
7428 32
            return (string) $pieces;
7429
        }
7430
7431 8
        return '';
7432
    }
7433
7434
    /**
7435
     * @param mixed                 $needle   <p>
7436
     *                                        The searched value.
7437
     *                                        </p>
7438
     *                                        <p>
7439
     *                                        If needle is a string, the comparison is done
7440
     *                                        in a case-sensitive manner.
7441
     *                                        </p>
7442
     * @param array|\Generator|null $haystack <p>
7443
     *                                        The array.
7444
     *                                        </p>
7445
     * @param bool                  $strict   [optional] <p>
7446
     *                                        If the third parameter strict is set to true
7447
     *                                        then the in_array function will also check the
7448
     *                                        types of the
7449
     *                                        needle in the haystack.
7450
     *                                        </p>
7451
     *
7452
     * @return bool
7453
     *              <p>true if needle is found in the array, false otherwise</p>
7454
     *
7455
     * @phpstan-param (array&T)|array<TKey,T>|\Generator<TKey,T>|null $haystack
7456
     * @psalm-mutation-free
7457
     */
7458 19
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
7459
    {
7460 19
        if ($haystack === null) {
7461
            $haystack = $this->getGenerator();
7462
        }
7463
7464 19
        foreach ($haystack as $item) {
7465 15
            if (\is_array($item)) {
7466 4
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
7467
            } else {
7468
                /** @noinspection NestedPositiveIfStatementsInspection */
7469 15
                if ($strict === true) {
7470 15
                    $returnTmp = $item === $needle;
7471
                } else {
7472
                    $returnTmp = $item == $needle;
7473
                }
7474
            }
7475
7476 15
            if ($returnTmp === true) {
7477 15
                return true;
7478
            }
7479
        }
7480
7481 8
        return false;
7482
    }
7483
7484
    /**
7485
     * @param mixed $data
7486
     *
7487
     * @return array<mixed>|null
7488
     */
7489 1212
    protected function internalGetArray(&$data)
7490
    {
7491 1212
        if (\is_array($data)) {
7492 1206
            return $data;
7493
        }
7494
7495 110
        if (!$data) {
7496 7
            return [];
7497
        }
7498
7499 109
        if (\is_object($data) === true) {
7500 102
            if ($data instanceof \ArrayObject) {
7501 5
                return $data->getArrayCopy();
7502
            }
7503
7504 98
            if ($data instanceof \Generator) {
7505
                return static::createFromGeneratorImmutable($data)->toArray();
7506
            }
7507
7508 98
            if ($data instanceof \Traversable) {
7509
                return static::createFromObject($data)->toArray();
7510
            }
7511
7512 98
            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...
7513
                return (array) $data->jsonSerialize();
7514
            }
7515
7516 98
            if (\method_exists($data, '__toArray')) {
7517
                return (array) $data->__toArray();
7518
            }
7519
7520 98
            if (\method_exists($data, '__toString')) {
7521
                return [(string) $data];
7522
            }
7523
        }
7524
7525 105
        if (\is_callable($data)) {
7526
            /**
7527
             * @psalm-suppress InvalidPropertyAssignmentValue - why?
7528
             */
7529 96
            $this->generator = new ArrayyRewindableGenerator($data);
7530
7531 96
            return [];
7532
        }
7533
7534 11
        if (\is_scalar($data)) {
7535 9
            return [$data];
7536
        }
7537
7538 2
        return null;
7539
    }
7540
7541
    /**
7542
     * Internal mechanics of remove method.
7543
     *
7544
     * @param mixed $key
7545
     *
7546
     * @return bool
7547
     */
7548 22
    protected function internalRemove($key): bool
7549
    {
7550 22
        $this->generatorToArray();
7551
7552
        if (
7553 22
            $this->pathSeparator
7554
            &&
7555 22
            (string) $key === $key
7556
            &&
7557 22
            \strpos($key, $this->pathSeparator) !== false
7558
        ) {
7559
            $path = \explode($this->pathSeparator, (string) $key);
7560
7561
            if ($path !== false) {
7562
                // crawl though the keys
7563
                while (\count($path, \COUNT_NORMAL) > 1) {
7564
                    $key = \array_shift($path);
7565
7566
                    if (!$this->has($key)) {
7567
                        return false;
7568
                    }
7569
7570
                    $this->array = &$this->array[$key];
7571
                }
7572
7573
                $key = \array_shift($path);
7574
            }
7575
        }
7576
7577 22
        unset($this->array[$key]);
7578
7579 22
        return true;
7580
    }
7581
7582
    /**
7583
     * Internal mechanic of set method.
7584
     *
7585
     * @param int|string|null $key
7586
     * @param mixed           $value
7587
     * @param bool            $checkProperties
7588
     *
7589
     * @return bool
7590
     */
7591 1062
    protected function internalSet(
7592
        $key,
7593
        &$value,
7594
        bool $checkProperties = true
7595
    ): bool {
7596
        if (
7597 1062
            $checkProperties === true
7598
            &&
7599 1062
            $this->properties !== []
7600
        ) {
7601 117
            $this->checkType($key, $value);
7602
        }
7603
7604 1060
        if ($key === null) {
7605
            return false;
7606
        }
7607
7608 1060
        $this->generatorToArray();
7609
7610
        /** @phpstan-var array<int|string,mixed> $array */
7611 1060
        $array = &$this->array;
7612
7613
        /**
7614
         * https://github.com/vimeo/psalm/issues/2536
7615
         *
7616
         * @psalm-suppress PossiblyInvalidArgument
7617
         * @psalm-suppress InvalidScalarArgument
7618
         */
7619
        if (
7620 1060
            $this->pathSeparator
7621
            &&
7622 1060
            (string) $key === $key
7623
            &&
7624 1060
            \strpos($key, $this->pathSeparator) !== false
7625
        ) {
7626 9
            $path = \explode($this->pathSeparator, (string) $key);
7627
7628 9
            if ($path !== false) {
7629
                // crawl through the keys
7630 9
                while (\count($path, \COUNT_NORMAL) > 1) {
7631 9
                    $key = \array_shift($path);
7632
7633 9
                    $array = &$array[$key];
7634
                }
7635
7636 9
                $key = \array_shift($path);
7637
            }
7638
        }
7639
7640 1060
        if ($array === null) {
7641 4
            $array = [];
7642 1057
        } elseif (!\is_array($array)) {
7643 1
            throw new \RuntimeException('Can not set value at this path "' . $key . '" because (' . \gettype($array) . ')"' . \print_r($array, true) . '" is not an array.');
7644
        }
7645
7646 1060
        $array[$key] = $value;
7647
7648 1060
        return true;
7649
    }
7650
7651
    /**
7652
     * Convert a object into an array.
7653
     *
7654
     * @param mixed|object $object
7655
     *
7656
     * @return array|mixed
7657
     *
7658
     * @psalm-mutation-free
7659
     */
7660 5
    protected static function objectToArray($object)
7661
    {
7662 5
        if (!\is_object($object)) {
7663 4
            return $object;
7664
        }
7665
7666 5
        $object = \get_object_vars($object);
7667
7668
        /**
7669
         * @psalm-suppress PossiblyInvalidArgument - the parameter is always some kind of array - false-positive from psalm?
7670
         */
7671 5
        return \array_map(['static', 'objectToArray'], $object);
7672
    }
7673
7674
    /**
7675
     * @param array $data
7676
     * @param bool  $checkPropertiesInConstructor
7677
     *
7678
     * @return void
7679
     *
7680
     * @phpstan-param array<mixed,T> $data
7681
     */
7682 1210
    protected function setInitialValuesAndProperties(array &$data, bool $checkPropertiesInConstructor)
7683
    {
7684 1210
        $checkPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
7685
                                        &&
7686 1210
                                        $checkPropertiesInConstructor === true;
7687
7688 1210
        if ($this->properties !== []) {
7689 104
            foreach ($data as $key => &$valueInner) {
7690 104
                $this->internalSet(
7691 104
                    $key,
7692 104
                    $valueInner,
7693 104
                    $checkPropertiesInConstructor
7694
                );
7695
            }
7696
        } else {
7697
            if (
7698 1125
                $this->checkPropertyTypes === true
7699
                ||
7700 1125
                $checkPropertiesInConstructor === true
7701
            ) {
7702 23
                $this->properties = $this->getPropertiesFromPhpDoc();
7703
            }
7704
7705
            /** @var TypeCheckInterface[] $properties */
7706 1125
            $properties = $this->properties;
7707
7708
            if (
7709 1125
                $this->checkPropertiesMismatchInConstructor === true
7710
                &&
7711 1125
                \count($data) !== 0
7712
                &&
7713 1125
                \count(\array_diff_key($properties, $data)) > 0
7714
            ) {
7715 1
                throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($properties), true));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'Property mismatch - inp...eys($properties), true).

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

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

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

Loading history...
7716
            }
7717
7718 1124
            foreach ($data as $key => &$valueInner) {
7719 953
                $this->internalSet(
7720 953
                    $key,
7721 953
                    $valueInner,
7722 953
                    $checkPropertiesInConstructor
7723
                );
7724
            }
7725
        }
7726 1202
    }
7727
7728
    /**
7729
     * sorting keys
7730
     *
7731
     * @param array      $elements
7732
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
7733
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
7734
     *                              <strong>SORT_NATURAL</strong></p>
7735
     *
7736
     * @return $this
7737
     *               <p>(Mutable) Return this Arrayy object.</p>
7738
     *
7739
     * @phpstan-param  array<mixed|TKey,T> $elements
7740
     * @phpstan-return static<TKey,T>
7741
     */
7742 18
    protected function sorterKeys(
7743
        array &$elements,
7744
        $direction = \SORT_ASC,
7745
        int $strategy = \SORT_REGULAR
7746
    ): self {
7747 18
        $direction = $this->getDirection($direction);
7748
7749
        switch ($direction) {
7750 18
            case 'desc':
7751 18
            case \SORT_DESC:
7752 6
                \krsort($elements, $strategy);
7753
7754 6
                break;
7755 13
            case 'asc':
7756 13
            case \SORT_ASC:
7757
            default:
7758 13
                \ksort($elements, $strategy);
7759
        }
7760
7761 18
        return $this;
7762
    }
7763
7764
    /**
7765
     * @param array      $elements  <p>Warning: used as reference</p>
7766
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
7767
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
7768
     *                              <strong>SORT_NATURAL</strong></p>
7769
     * @param bool       $keepKeys
7770
     *
7771
     * @return $this
7772
     *               <p>(Mutable) Return this Arrayy object.</p>
7773
     *
7774
     * @phpstan-param array<mixed|TKey,T> $elements
7775
     * @phpstan-return static<int|TKey,T>
7776
     */
7777 24
    protected function sorting(
7778
        array &$elements,
7779
        $direction = \SORT_ASC,
7780
        int $strategy = \SORT_REGULAR,
7781
        bool $keepKeys = false
7782
    ): self {
7783 24
        $direction = $this->getDirection($direction);
7784
7785 24
        if (!$strategy) {
7786 24
            $strategy = \SORT_REGULAR;
7787
        }
7788
7789
        switch ($direction) {
7790 24
            case 'desc':
7791 24
            case \SORT_DESC:
7792 13
                if ($keepKeys) {
7793 9
                    \arsort($elements, $strategy);
7794
                } else {
7795 4
                    \rsort($elements, $strategy);
7796
                }
7797
7798 13
                break;
7799 11
            case 'asc':
7800 11
            case \SORT_ASC:
7801
            default:
7802 11
                if ($keepKeys) {
7803 4
                    \asort($elements, $strategy);
7804
                } else {
7805 7
                    \sort($elements, $strategy);
7806
                }
7807
        }
7808
7809 24
        return $this;
7810
    }
7811
7812
    /**
7813
     * @param array $array
7814
     *
7815
     * @return array
7816
     *
7817
     * @psalm-mutation-free
7818
     */
7819 25
    private function getArrayRecursiveHelperArrayy(array $array)
7820
    {
7821 25
        if ($array === []) {
7822
            return [];
7823
        }
7824
7825 25
        \array_walk_recursive(
7826 25
            $array,
7827
            /**
7828
             * @param array|self $item
7829
             *
7830
             * @return void
7831
             */
7832
            static function (&$item) {
7833 25
                if ($item instanceof self) {
7834 1
                    $item = $item->getArray();
7835
                }
7836 25
            }
7837
        );
7838
7839 25
        return $array;
7840
    }
7841
7842
    /**
7843
     * @param int|string|null $key
7844
     * @param mixed           $value
7845
     *
7846
     * @return void
7847
     */
7848 117
    private function checkType($key, $value)
7849
    {
7850
        if (
7851 117
            $key !== null
7852
            &&
7853 117
            isset($this->properties[$key]) === false
7854
            &&
7855 117
            $this->checkPropertiesMismatch === true
7856
        ) {
7857
            throw new \TypeError('The key "' . $key . '" does not exists as "@property" phpdoc. (' . \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 . '" ...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...
7858
        }
7859
7860 117
        if (isset($this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES])) {
7861 102
            $this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES]->checkType($value);
7862 24
        } elseif ($key !== null && isset($this->properties[$key])) {
7863 24
            $this->properties[$key]->checkType($value);
7864
        }
7865 115
    }
7866
}
7867