Completed
Push — master ( cb544b...3bd5ac )
by Lars
01:40
created

Arrayy::end()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

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

Loading history...
333 23
     *                          <p>An iterator for the values in the array.</p>
334 23
     */
335
    public function getIterator(): \Iterator
336
    {
337
        if ($this->generator instanceof ArrayyRewindableGenerator) {
338
            return $this->generator;
339
        }
340
341
        $iterator = $this->getIteratorClass();
342
343
        if ($iterator === ArrayyIterator::class) {
344
            return new $iterator($this->getArray(), 0, static::class);
345 23
        }
346
347 23
        return new $iterator($this->getArray());
348
    }
349
350
    /**
351
     * Gets the iterator classname for the ArrayObject.
352
     *
353
     * @return string
354
     */
355
    public function getIteratorClass(): string
356
    {
357
        return $this->iteratorClass;
358
    }
359
360
    /**
361
     * Sort the entries by key
362 4
     *
363
     * @param int $sort_flags [optional] <p>
364 4
     *                        You may modify the behavior of the sort using the optional
365
     *                        parameter sort_flags, for details
366 4
     *                        see sort.
367
     *                        </p>
368 4
     *
369
     * @return static
370
     *                <p>(Mutable) Return this Arrayy object.</p>
371
     */
372
    public function ksort(int $sort_flags = 0): self
373
    {
374
        $this->generatorToArray();
375
376
        \ksort($this->array, $sort_flags);
377
378
        return $this;
379
    }
380
381
    /**
382
     * Sort an array using a case insensitive "natural order" algorithm
383
     *
384
     * @return static
385
     *                <p>(Mutable) Return this Arrayy object.</p>
386
     */
387
    public function natcasesort(): self
388
    {
389
        $this->generatorToArray();
390
391
        \natcasesort($this->array);
392 1
393
        return $this;
394 1
    }
395
396 1
    /**
397
     * Sort entries using a "natural order" algorithm
398 1
     *
399
     * @return static
400
     *                <p>(Mutable) Return this Arrayy object.</p>
401
     */
402
    public function natsort(): self
403
    {
404
        $this->generatorToArray();
405
406
        \natsort($this->array);
407
408 126
        return $this;
409
    }
410 126
411
    /**
412 126
     * Whether or not an offset exists.
413 5
     *
414
     * @param bool|int|string $offset
415
     *
416
     * @return bool
417 121
     *
418 1
     * @noinspection PhpSillyAssignmentInspection
419
     */
420
    public function offsetExists($offset): bool
421 121
    {
422
        $this->generatorToArray();
423
424 121
        if ($this->array === []) {
425
            return false;
426
        }
427 88
428
        // php cast "bool"-index into "int"-index
429 121
        if ((bool) $offset === $offset) {
430
            $offset = (int) $offset;
431
        }
432 119
433
        /** @var int|string $offset - hint for phpstan */
434
        $offset = $offset;
0 ignored issues
show
Bug introduced by
Why assign $offset to itself?

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

This assignement can be removed without consequences.

Loading history...
435 3
436
        $tmpReturn = $this->keyExists($offset);
437
438 3
        if (
439
            $tmpReturn === true
440 3
            ||
441
            (
442 3
                $tmpReturn === false
443
                &&
444 3
                \strpos((string) $offset, $this->pathSeparator) === false
445 3
            )
446 3
        ) {
447 3
            return $tmpReturn;
448 3
        }
449
450 3
        $offsetExists = false;
451 3
452
        if (
453 3
            $this->pathSeparator
454 3
            &&
455
            (string) $offset === $offset
456
            &&
457
            \strpos($offset, $this->pathSeparator) !== false
458
        ) {
459
            $explodedPath = \explode($this->pathSeparator, (string) $offset);
460 3
            if ($explodedPath !== false) {
461
                $lastOffset = \array_pop($explodedPath);
462
                if ($lastOffset !== null) {
463
                    $containerPath = \implode($this->pathSeparator, $explodedPath);
464
465
                    $this->callAtPath(
466
                        $containerPath,
467
                        static function ($container) use ($lastOffset, &$offsetExists) {
468
                            $offsetExists = \array_key_exists($lastOffset, $container);
469
                        }
470
                    );
471 97
                }
472
            }
473 97
        }
474
475
        return $offsetExists;
476
    }
477
478
    /**
479
     * Returns the value at specified offset.
480
     *
481
     * @param int|string $offset
482 21
     *
483
     * @return mixed
484 21
     *               <p>Will return null if the offset did not exists.</p>
485
     */
486 21
    public function offsetGet($offset)
487 5
    {
488 1
        return $this->offsetExists($offset) ? $this->get($offset) : null;
489
    }
490
491 4
    /**
492
     * Assigns a value to the specified offset.
493 16
     *
494 16
     * @param int|string|null $offset
495 16
     * @param mixed           $value
496 16
     *
497
     * @return void
498
     */
499 20
    public function offsetSet($offset, $value)
500
    {
501
        $this->generatorToArray();
502
503
        if ($offset === null) {
504
            if ($this->properties !== []) {
505
                $this->checkType(null, $value);
506 12
            }
507
508 12
            $this->array[] = $value;
509
        } else {
510 12
            $this->internalSet(
511 3
                $offset,
512
                $value,
513
                true
514 10
            );
515 7
        }
516
    }
517 7
518
    /**
519
     * Unset an offset.
520
     *
521 5
     * @param int|string $offset
522
     *
523 5
     * @return void
524
     */
525 5
    public function offsetUnset($offset)
526
    {
527 2
        $this->generatorToArray();
528
529 2
        if ($this->array === []) {
530 2
            return;
531
        }
532 2
533 2
        if ($this->keyExists($offset)) {
534
            unset($this->array[$offset]);
535 2
536 2
            return;
537
        }
538
539
        if (
540
            $this->pathSeparator
541 5
            &&
542 5
            (string) $offset === $offset
543
            &&
544
            \strpos($offset, $this->pathSeparator) !== false
545
        ) {
546
            $path = \explode($this->pathSeparator, (string) $offset);
547
548
            if ($path !== false) {
549 2
                $pathToUnset = \array_pop($path);
550
551 2
                $this->callAtPath(
552
                    \implode($this->pathSeparator, $path),
553 2
                    static function (&$offset) use ($pathToUnset) {
554 2
                        unset($offset[$pathToUnset]);
555
                    }
556
                );
557
            }
558
        }
559
560
        unset($this->array[$offset]);
561
    }
562
563
    /**
564
     * Serialize the current "Arrayy"-object.
565
     *
566
     * @return string
567 1041
     */
568
    public function serialize(): string
569 1041
    {
570 1041
        $this->generatorToArray();
571
572 1041
        if (\PHP_VERSION_ID < 70400) {
573
            return parent::serialize();
574
        }
575
576
        return \serialize($this);
577
    }
578
579
    /**
580
     * Sets the iterator classname for the current "Arrayy"-object.
581
     *
582
     * @param string $class
583
     *
584
     * @throws \InvalidArgumentException
585
     *
586
     * @return void
587
     */
588
    public function setIteratorClass($class)
589
    {
590
        if (\class_exists($class)) {
591
            $this->iteratorClass = $class;
592
593
            return;
594
        }
595
596
        if (\strpos($class, '\\') === 0) {
597
            $class = '\\' . $class;
598
            if (\class_exists($class)) {
599
                $this->iteratorClass = $class;
600
601
                return;
602
            }
603
        }
604
605
        throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
606
    }
607
608
    /**
609
     * Sort the entries with a user-defined comparison function and maintain key association.
610
     *
611
     * @param callable $function
612
     *
613
     * @throws \InvalidArgumentException
614
     *
615
     * @return static
616
     *                <p>(Mutable) Return this Arrayy object.</p>
617
     */
618 View Code Duplication
    public function uasort($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
619
    {
620 5
        if (!\is_callable($function)) {
621
            throw new \InvalidArgumentException('Passed function must be callable');
622 5
        }
623
624
        $this->generatorToArray();
625
626
        \uasort($this->array, $function);
627
628
        return $this;
629
    }
630
631
    /**
632 2
     * Sort the entries by keys using a user-defined comparison function.
633
     *
634 2
     * @param callable $function
635 2
     *
636
     * @throws \InvalidArgumentException
637 2
     *
638
     * @return static
639
     *                <p>(Mutable) Return this Arrayy object.</p>
640
     */
641
    public function uksort($function): self
642
    {
643
        return $this->customSortKeys($function);
644
    }
645
646
    /**
647
     * Unserialize an string and return the instance of the "Arrayy"-class.
648
     *
649
     * @param string $string
650
     *
651
     * @return static
652 1
     */
653
    public function unserialize($string): self
654 1
    {
655
        if (\PHP_VERSION_ID < 70400) {
656 1
            parent::unserialize($string);
657
658 1
            return $this;
659
        }
660 1
661
        return \unserialize($string, ['allowed_classes' => [__CLASS__, TypeCheckPhpDoc::class]]);
662 1
    }
663 1
664
    /**
665
     * Append a (key) + values to the current array.
666 1
     *
667
     * @param array $values
668
     * @param mixed $key
669
     *
670
     * @return static
671
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
672
     */
673
    public function appendArrayValues(array $values, $key = null): self
674
    {
675
        $this->generatorToArray();
676 1
677
        if ($key !== null) {
678
            if (
679
                isset($this->array[$key])
680
                &&
681
                \is_array($this->array[$key]) === true
682
            ) {
683
                foreach ($values as $value) {
684
                    $this->array[$key][] = $value;
685
                }
686
            } else {
687 10
                foreach ($values as $value) {
688
                    $this->array[$key] = $value;
689
                }
690 10
            }
691
        } else {
692 10
            foreach ($values as $value) {
693 9
                $this->array[] = $value;
694
            }
695 9
        }
696
697
        return $this;
698
    }
699
700 9
    /**
701
     * Add a suffix to each key.
702
     *
703
     * @param mixed $prefix
704 10
     *
705
     * @return static
706
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
707
     */
708 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...
709
    {
710
        // init
711
        $result = [];
712
713
        foreach ($this->getGenerator() as $key => $item) {
714
            if ($item instanceof self) {
715 10
                $result[$prefix . $key] = $item->appendToEachKey($prefix);
716
            } elseif (\is_array($item) === true) {
717
                $result[$prefix . $key] = self::create($item, $this->iteratorClass, false)
718 10
                    ->appendToEachKey($prefix)
719
                    ->toArray();
720 10
            } else {
721 9
                $result[$prefix . $key] = $item;
722
            }
723 9
        }
724
725 9
        return self::create($result, $this->iteratorClass, false);
726 1
    }
727
728 8
    /**
729
     * Add a prefix to each value.
730
     *
731
     * @param mixed $prefix
732 10
     *
733
     * @return static
734
     *                <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
735
     */
736 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...
737
    {
738
        // init
739
        $result = [];
740
741 10
        foreach ($this->getGenerator() as $key => $item) {
742
            if ($item instanceof self) {
743 10
                $result[$key] = $item->appendToEachValue($prefix);
744
            } elseif (\is_array($item) === true) {
745 10
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
746
            } elseif (\is_object($item) === true) {
747 10
                $result[$key] = $item;
748
            } else {
749
                $result[$key] = $prefix . $item;
750
            }
751
        }
752
753
        return self::create($result, $this->iteratorClass, false);
754
    }
755
756
    /**
757
     * Sort an array in reverse order and maintain index association.
758 2
     *
759
     * @return static
760 2
     *                <p>(Mutable) Return this Arrayy object.</p>
761
     */
762 2
    public function arsort(): self
763 2
    {
764
        $this->generatorToArray();
765
766 2
        \arsort($this->array);
767 2
768 2
        return $this;
769 2
    }
770
771
    /**
772
     * Iterate over the current array and execute a callback for each loop.
773
     *
774
     * @param \Closure $closure
775
     *
776
     * @return static
777
     *                <p>(Immutable)</p>
778
     */
779
    public function at(\Closure $closure): self
780
    {
781 10
        $arrayy = clone $this;
782
783 10
        foreach ($arrayy->getGenerator() as $key => $value) {
784
            $closure($value, $key);
785 10
        }
786 2
787
        return static::create(
788
            $arrayy->toArray(),
789 8
            $this->iteratorClass,
790 3
            false
791
        );
792
    }
793 8
794
    /**
795
     * Returns the average value of the current array.
796
     *
797
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
798
     *
799
     * @return float|int
800
     *                   <p>The average value.</p>
801
     */
802
    public function average($decimals = 0)
803
    {
804
        $count = \count($this->getArray(), \COUNT_NORMAL);
805 1
806
        if (!$count) {
807
            return 0;
808 1
        }
809
810 1
        if ((int) $decimals !== $decimals) {
811
            $decimals = 0;
812
        }
813
814
        return \round(\array_sum($this->getArray()) / $count, $decimals);
815 1
    }
816 1
817 1
    /**
818 1
     * Changes all keys in an array.
819
     *
820 1
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
821
     *                  or <strong>CASE_LOWER</strong> (default)</p>
822
     *
823 1
     * @return static
824
     *                <p>(Immutable)</p>
825
     */
826 1
    public function changeKeyCase(int $case = \CASE_LOWER): self
827 1
    {
828 1
        if (
829 1
            $case !== \CASE_LOWER
830
            &&
831
            $case !== \CASE_UPPER
832
        ) {
833
            $case = \CASE_LOWER;
834
        }
835
836
        $return = [];
837
        foreach ($this->getGenerator() as $key => $value) {
838
            if ($case === \CASE_LOWER) {
839
                $key = \mb_strtolower((string) $key);
840
            } else {
841
                $key = \mb_strtoupper((string) $key);
842
            }
843 10
844
            $return[$key] = $value;
845 10
        }
846
847 10
        return static::create(
848
            $return,
849
            $this->iteratorClass,
850
            false
851
        );
852
    }
853
854
    /**
855
     * Change the path separator of the array wrapper.
856
     *
857
     * By default, the separator is: "."
858
     *
859 5
     * @param string $separator <p>Separator to set.</p>
860
     *
861 5
     * @return static
862 5
     *                <p>Mutable</p>
863 5
     */
864 5
    public function changeSeparator($separator): self
865
    {
866
        $this->pathSeparator = $separator;
867
868
        return $this;
869
    }
870
871
    /**
872
     * Create a chunked version of the current array.
873
     *
874 8
     * @param int  $size         <p>Size of each chunk.</p>
875
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
876 8
     *
877
     * @return static
878 7
     *                <p>(Immutable) A new array of chunks from the original array.</p>
879 8
     */
880
    public function chunk($size, $preserveKeys = false): self
881
    {
882
        return static::create(
883
            \array_chunk($this->getArray(), $size, $preserveKeys),
884
            $this->iteratorClass,
885
            false
886
        );
887
    }
888
889 4
    /**
890
     * Clean all falsy values from the current array.
891 4
     *
892 4
     * @return static
893
     *                <p>(Immutable)</p>
894 4
     */
895
    public function clean(): self
896
    {
897
        return $this->filter(
898
            static function ($value) {
899
                return (bool) $value;
900
            }
901
        );
902
    }
903
904
    /**
905
     * WARNING!!! -> Clear the current array.
906 23
     *
907
     * @return static
908 23
     *                <p>(Mutable) Return this Arrayy object, with an empty array.</p>
909 18
     */
910
    public function clear(): self
911
    {
912 14
        $this->array = [];
913 11
        $this->generator = null;
914 11
915 11
        return $this;
916
    }
917
918
    /**
919
     * Check if an item is in the current array.
920
     *
921
     * @param float|int|string $value
922
     * @param bool             $recursive
923
     * @param bool             $strict
924
     *
925 7
     * @return bool
926
     *
927
     * @phpstan-param T $value
928
     */
929
    public function contains($value, bool $recursive = false, bool $strict = true): bool
930
    {
931
        if ($recursive === true) {
932
            return $this->in_array_recursive($value, $this->getArray(), $strict);
933
        }
934
935
        foreach ($this->getGenerator() as $valueFromArray) {
936 26
            if ($strict) {
937
                if ($value === $valueFromArray) {
938 26
                    return true;
939 26
                }
940 22
            } else {
941 5
                /** @noinspection NestedPositiveIfStatementsInspection */
942 5
                if ($value == $valueFromArray) {
943 5
                    return true;
944
                }
945 22
            }
946 16
        }
947
948
        return false;
949
    }
950 10
951
    /**
952
     * Check if an (case-insensitive) string is in the current array.
953 13
     *
954 11
     * @param string $value
955 8
     * @param bool   $recursive
956
     *
957
     * @return bool
958
     */
959 5
    public function containsCaseInsensitive($value, $recursive = false): bool
960
    {
961
        if ($recursive === true) {
962
            foreach ($this->getGenerator() as $key => $valueTmp) {
963
                if (\is_array($valueTmp) === true) {
964
                    $return = (new self($valueTmp))->containsCaseInsensitive($value, $recursive);
965
                    if ($return === true) {
966
                        return $return;
967
                    }
968
                } elseif (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
969
                    return true;
970 4
                }
971
            }
972 4
973
            return false;
974
        }
975
976
        foreach ($this->getGenerator() as $key => $valueTmp) {
977
            if (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
978
                return true;
979
            }
980
        }
981
982
        return false;
983
    }
984 2
985
    /**
986 2
     * Check if the given key/index exists in the array.
987
     *
988 2
     * @param int|string $key <p>key/index to search for</p>
989 2
     *
990 2
     * @return bool
991 2
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
992
     */
993 2
    public function containsKey($key): bool
994
    {
995
        return $this->offsetExists($key);
996 2
    }
997 2
998 2
    /**
999
     * Check if all given needles are present in the array as key/index.
1000
     *
1001
     * @param array $needles   <p>The keys you are searching for.</p>
1002 1
     * @param bool  $recursive
1003 1
     *
1004 1
     * @return bool
1005
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1006
     */
1007 1
    public function containsKeys(array $needles, $recursive = false): bool
1008 1
    {
1009 1
        if ($recursive === true) {
1010
            return
1011
                \count(
1012
                    \array_intersect(
1013
                        $needles,
1014
                        $this->keys(true)->getArray()
1015
                    ),
1016
                    \COUNT_RECURSIVE
1017
                )
1018
                ===
1019
                \count(
1020
                    $needles,
1021 1
                    \COUNT_RECURSIVE
1022
                );
1023 1
        }
1024
1025
        return \count(
1026
            \array_intersect($needles, $this->keys()->getArray()),
1027
            \COUNT_NORMAL
1028
        )
1029
               ===
1030
               \count(
1031
                   $needles,
1032
                   \COUNT_NORMAL
1033
               );
1034
    }
1035 9
1036
    /**
1037 9
     * Check if all given needles are present in the array as key/index.
1038
     *
1039
     * @param array $needles <p>The keys you are searching for.</p>
1040
     *
1041
     * @return bool
1042
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1043
     */
1044
    public function containsKeysRecursive(array $needles): bool
1045
    {
1046
        return $this->containsKeys($needles, true);
1047
    }
1048
1049 18
    /**
1050
     * alias: for "Arrayy->contains()"
1051 18
     *
1052
     * @param float|int|string $value
1053
     *
1054
     * @return bool
1055
     *
1056
     * @see Arrayy::contains()
1057
     *
1058
     * @phpstan-param T $value
1059
     */
1060
    public function containsValue($value): bool
1061
    {
1062 1
        return $this->contains($value);
1063
    }
1064 1
1065
    /**
1066 1
     * alias: for "Arrayy->contains($value, true)"
1067
     *
1068
     * @param float|int|string $value
1069
     *
1070
     * @return bool
1071
     *
1072
     * @see Arrayy::contains()
1073
     *
1074
     * @phpstan-param T $value
1075
     */
1076
    public function containsValueRecursive($value): bool
1077
    {
1078
        return $this->contains($value, true);
1079
    }
1080
1081 7
    /**
1082
     * Check if all given needles are present in the array.
1083 7
     *
1084
     * @param array $needles
1085
     *
1086
     * @return bool
1087
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
1088
     */
1089
    public function containsValues(array $needles): bool
1090
    {
1091
        return \count(\array_intersect($needles, $this->getArray()), \COUNT_NORMAL)
1092
               ===
1093
               \count($needles, \COUNT_NORMAL);
1094
    }
1095
1096 657
    /**
1097
     * Counts all the values of an array
1098
     *
1099
     * @see http://php.net/manual/en/function.array-count-values.php
1100
     *
1101 657
     * @return static
1102 657
     *                <p>
1103 657
     *                (Immutable)
1104 657
     *                An associative Arrayy-object of values from input as
1105
     *                keys and their count as value.
1106
     *                </p>
1107
     */
1108
    public function countValues(): self
1109
    {
1110
        return self::create(\array_count_values($this->getArray()), $this->iteratorClass);
1111
    }
1112
1113
    /**
1114
     * Creates an Arrayy object.
1115
     *
1116 1
     * @param mixed  $data
1117
     * @param string $iteratorClass
1118 1
     * @param bool   $checkPropertiesInConstructor
1119
     *
1120 1
     * @return static
1121
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1122 1
     */
1123
    public static function create(
1124
        $data = [],
1125
        string $iteratorClass = ArrayyIterator::class,
1126
        bool $checkPropertiesInConstructor = true
1127
    ): self {
1128
        return new static(
1129
            $data,
1130
            $iteratorClass,
1131
            $checkPropertiesInConstructor
1132
        );
1133 5
    }
1134
1135 5
    /**
1136
     * WARNING: Creates an Arrayy object by reference.
1137
     *
1138
     * @param array $array
1139
     *
1140
     * @return static
1141
     *                <p>(Mutable) Return this Arrayy object.</p>
1142
     */
1143
    public function createByReference(array &$array = []): self
1144
    {
1145
        $array = $this->fallbackForArray($array);
1146 4
1147
        $this->array = &$array;
1148 4
1149
        return $this;
1150
    }
1151
1152
    /**
1153
     * Create an new instance from a callable function which will return an Generator.
1154
     *
1155
     * @param callable():Generator $generatorFunction
0 ignored issues
show
Documentation introduced by
The doc-type callable():Generator could not be parsed: Expected "|" or "end of type", but got "(" at position 8. (view supported doc-types)

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

Loading history...
1156
     *
1157
     * @return static
1158
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1159 5
     */
1160
    public static function createFromGeneratorFunction(callable $generatorFunction): self
1161 5
    {
1162
        return self::create($generatorFunction);
1163
    }
1164
1165
    /**
1166
     * Create an new instance filled with a copy of values from a "Generator"-object.
1167
     *
1168
     * @param \Generator $generator
1169
     *
1170
     * @return static
1171
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1172 4
     */
1173
    public static function createFromGeneratorImmutable(\Generator $generator): self
1174
    {
1175 4
        return self::create(\iterator_to_array($generator, true));
1176
    }
1177 4
1178 4
    /**
1179
     * Create an new Arrayy object via JSON.
1180
     *
1181
     * @param string $json
1182
     *
1183 4
     * @return static
1184 3
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1185
     */
1186
    public static function createFromJson(string $json): self
1187 4
    {
1188
        return static::create(\json_decode($json, true));
1189
    }
1190
1191
    /**
1192
     * Create an new instance filled with values from an object that is iterable.
1193
     *
1194
     * @param \Traversable $object <p>iterable object</p>
1195
     *
1196
     * @return static
1197
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1198 5
     */
1199
    public static function createFromObject(\Traversable $object): self
1200 5
    {
1201
        // init
1202
        $array = self::create();
1203
1204
        if ($object instanceof self) {
1205
            $objectArray = $object->getGenerator();
1206
        } else {
1207
            $objectArray = $object;
1208
        }
1209
1210
        foreach ($objectArray as $key => $value) {
1211
            $array[$key] = $value;
1212
        }
1213
1214 10
        return $array;
1215
    }
1216 10
1217 1
    /**
1218
     * Create an new instance filled with values from an object.
1219 1
     *
1220 1
     * @param object $object
1221
     *
1222
     * @return static
1223
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1224 9
     */
1225 7
    public static function createFromObjectVars($object): self
1226
    {
1227 2
        return self::create(self::objectToArray($object));
1228
    }
1229
1230
    /**
1231
     * Create an new Arrayy object via string.
1232 10
     *
1233 10
     * @param string      $str       <p>The input string.</p>
1234
     * @param string|null $delimiter <p>The boundary string.</p>
1235 10
     * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1236 10
     *                               used.</p>
1237
     *
1238 10
     * @return static
1239
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1240
     */
1241 10
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
1242
    {
1243
        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...
1244
            \preg_match_all($regEx, $str, $array);
1245
1246
            if (!empty($array)) {
1247
                $array = $array[0];
1248
            }
1249
        } else {
1250
            /** @noinspection NestedPositiveIfStatementsInspection */
1251
            if ($delimiter !== null) {
1252 1
                $array = \explode($delimiter, $str);
1253
            } else {
1254 1
                $array = [$str];
1255
            }
1256
        }
1257
1258
        // trim all string in the array
1259
        \array_walk(
1260
            $array,
1261
            static function (&$val) {
1262
                if ((string) $val === $val) {
1263
                    $val = \trim($val);
1264
                }
1265
            }
1266
        );
1267 2
1268
        return static::create($array);
1269 2
    }
1270
1271
    /**
1272
     * Create an new instance filled with a copy of values from a "Traversable"-object.
1273
     *
1274
     * @param \Traversable $traversable
1275
     *
1276
     * @return static
1277
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1278
     */
1279
    public static function createFromTraversableImmutable(\Traversable $traversable): self
1280
    {
1281
        return self::create(\iterator_to_array($traversable, true));
1282
    }
1283
1284 5
    /**
1285
     * Create an new instance containing a range of elements.
1286 5
     *
1287
     * @param mixed $low  <p>First value of the sequence.</p>
1288
     * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1289
     * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1290 5
     *
1291
     * @return static
1292 5
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1293
     */
1294 5
    public static function createWithRange($low, $high, int $step = 1): self
1295
    {
1296
        return static::create(\range($low, $high, $step));
1297
    }
1298
1299
    /**
1300
     * Gets the element of the array at the current internal iterator position.
1301
     *
1302
     * @return mixed
1303
     *
1304
     * @phpstan-return T|false
1305
     */
1306
    public function current()
1307
    {
1308
        return \current($this->array);
1309 6
    }
1310
1311 6
    /**
1312
     * Custom sort by index via "uksort".
1313
     *
1314
     * @see http://php.net/manual/en/function.uksort.php
1315 6
     *
1316
     * @param callable $function
1317 6
     *
1318
     * @throws \InvalidArgumentException
1319 6
     *
1320
     * @return static
1321
     *                <p>(Mutable) Return this Arrayy object.</p>
1322
     */
1323 View Code Duplication
    public function customSortKeys($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1324
    {
1325
        if (\is_callable($function) === false) {
1326
            throw new \InvalidArgumentException('Passed function must be callable');
1327 4
        }
1328
1329 4
        $this->generatorToArray();
1330
1331 4
        \uksort($this->array, $function);
1332 4
1333
        return $this;
1334 4
    }
1335
1336
    /**
1337
     * Custom sort by value via "usort".
1338
     *
1339
     * @see http://php.net/manual/en/function.usort.php
1340
     *
1341
     * @param callable $function
1342
     *
1343
     * @throws \InvalidArgumentException
1344 13
     *
1345
     * @return static
1346 13
     *                <p>(Mutable) Return this Arrayy object.</p>
1347 13
     */
1348 13 View Code Duplication
    public function customSortValues($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1349 13
    {
1350
        if (\is_callable($function) === false) {
1351
            throw new \InvalidArgumentException('Passed function must be callable');
1352
        }
1353
1354
        $this->generatorToArray();
1355
1356
        \usort($this->array, $function);
1357
1358
        return $this;
1359
    }
1360
1361 8
    /**
1362
     * Delete the given key or keys.
1363 8
     *
1364 8
     * @param int|int[]|string|string[] $keyOrKeys
1365 8
     *
1366 8
     * @return void
1367
     */
1368
    public function delete($keyOrKeys)
1369
    {
1370
        $keyOrKeys = (array) $keyOrKeys;
1371
1372
        foreach ($keyOrKeys as $key) {
1373
            $this->offsetUnset($key);
1374
        }
1375
    }
1376
1377
    /**
1378 8
     * Return values that are only in the current array.
1379
     *
1380 8
     * @param array ...$array
1381 8
     *
1382 8
     * @return static
1383 8
     *                <p>(Immutable)</p>
1384
     */
1385
    public function diff(...$array): self
1386
    {
1387
        return static::create(
1388
            \array_diff($this->getArray(), ...$array),
1389
            $this->iteratorClass,
1390
            false
1391
        );
1392
    }
1393
1394
    /**
1395
     * Return values that are only in the current array.
1396 1
     *
1397
     * @param array ...$array
1398
     *
1399 1
     * @return static
1400
     *                <p>(Immutable)</p>
1401
     */
1402 1
    public function diffKey(...$array): self
1403
    {
1404 1
        return static::create(
1405
            \array_diff_key($this->getArray(), ...$array),
1406
            $this->iteratorClass,
1407
            false
1408 1
        );
1409
    }
1410
1411 1
    /**
1412 1
     * Return values and Keys that are only in the current array.
1413
     *
1414
     * @param array $array
1415
     *
1416 1
     * @return static
1417 1
     *                <p>(Immutable)</p>
1418 1
     */
1419
    public function diffKeyAndValue(array $array = []): self
1420
    {
1421 1
        return static::create(
1422
            \array_diff_assoc($this->getArray(), $array),
1423
            $this->iteratorClass,
1424
            false
1425 1
        );
1426 1
    }
1427 1
1428 1
    /**
1429
     * Return values that are only in the current multi-dimensional array.
1430
     *
1431
     * @param array      $array
1432
     * @param array|null $helperVariableForRecursion <p>(only for internal usage)</p>
1433
     *
1434
     * @return static
1435
     *                <p>(Immutable)</p>
1436
     */
1437
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
1438
    {
1439
        // init
1440 8
        $result = [];
1441
1442 8
        if (
1443 8
            $helperVariableForRecursion !== null
1444 8
            &&
1445 8
            \is_array($helperVariableForRecursion) === true
1446
        ) {
1447
            $arrayForTheLoop = $helperVariableForRecursion;
1448
        } else {
1449
            $arrayForTheLoop = $this->getGenerator();
1450
        }
1451
1452
        foreach ($arrayForTheLoop as $key => $value) {
1453
            if ($value instanceof self) {
1454
                $value = $value->getArray();
1455 1
            }
1456
1457 1
            if (\array_key_exists($key, $array)) {
1458
                if ($value !== $array[$key]) {
1459 1
                    $result[$key] = $value;
1460 1
                }
1461
            } else {
1462 1
                $result[$key] = $value;
1463 1
            }
1464
        }
1465
1466
        return static::create(
1467
            $result,
1468
            $this->iteratorClass,
1469
            false
1470
        );
1471
    }
1472
1473
    /**
1474
     * Return values that are only in the new $array.
1475 5
     *
1476
     * @param array $array
1477
     *
1478 5
     * @return static
1479
     *                <p>(Immutable)</p>
1480 5
     */
1481 5
    public function diffReverse(array $array = []): self
1482
    {
1483
        return static::create(
1484 5
            \array_diff($array, $this->getArray()),
1485 5
            $this->iteratorClass,
1486 5
            false
1487 5
        );
1488
    }
1489
1490
    /**
1491
     * Divide an array into two arrays. One with keys and the other with values.
1492
     *
1493
     * @return static
1494
     *                <p>(Immutable)</p>
1495
     */
1496
    public function divide(): self
1497
    {
1498
        return static::create(
1499 4
            [
1500
                $this->keys(),
1501
                $this->values(),
1502 4
            ],
1503
            $this->iteratorClass,
1504 4
            false
1505 3
        );
1506 1
    }
1507
1508 1
    /**
1509
     * Iterate over the current array and modify the array's value.
1510
     *
1511
     * @param \Closure $closure
1512 4
     *
1513
     * @return static
1514
     *                <p>(Immutable)</p>
1515
     */
1516 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...
1517
    {
1518
        // init
1519
        $array = [];
1520
1521
        foreach ($this->getGenerator() as $key => $value) {
1522
            $array[$key] = $closure($value, $key);
1523
        }
1524 8
1525
        return static::create(
1526 8
            $array,
1527 1
            $this->iteratorClass,
1528
            false
1529
        );
1530 7
    }
1531
1532 7
    /**
1533
     * Sets the internal iterator to the last element in the array and returns this element.
1534 7
     *
1535
     * @return mixed
1536 7
     */
1537 4
    public function end()
1538 4
    {
1539
        return \end($this->array);
1540
    }
1541 7
1542 7
    /**
1543 7
     * Check if a value is in the current array using a closure.
1544 7
     *
1545
     * @param \Closure $closure
1546
     *
1547
     * @return bool
1548
     *              <p>Returns true if the given value is found, false otherwise.</p>
1549
     */
1550
    public function exists(\Closure $closure): bool
1551
    {
1552
        // init
1553
        $isExists = false;
1554
1555
        foreach ($this->getGenerator() as $key => $value) {
1556
            if ($closure($value, $key)) {
1557
                $isExists = true;
1558
1559
                break;
1560
            }
1561
        }
1562
1563
        return $isExists;
1564
    }
1565
1566
    /**
1567
     * Fill the array until "$num" with "$default" values.
1568
     *
1569
     * @param int   $num
1570
     * @param mixed $default
1571
     *
1572
     * @return static
1573
     *                <p>(Immutable)</p>
1574
     */
1575
    public function fillWithDefaults(int $num, $default = null): self
1576 12
    {
1577
        if ($num < 0) {
1578 12
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1579 1
        }
1580
1581
        $this->generatorToArray();
1582 12
1583 12
        $tmpArray = $this->array;
1584 12
1585 12
        $count = \count($tmpArray);
1586
1587
        while ($count < $num) {
1588
            $tmpArray[] = $default;
1589
            ++$count;
1590
        }
1591
1592
        return static::create(
1593
            $tmpArray,
1594
            $this->iteratorClass,
1595
            false
1596
        );
1597
    }
1598
1599
    /**
1600
     * Find all items in an array that pass the truth test.
1601
     *
1602
     * @param \Closure|null $closure [optional] <p>
1603
     *                               The callback function to use
1604
     *                               </p>
1605
     *                               <p>
1606
     *                               If no callback is supplied, all entries of
1607
     *                               input equal to false (see
1608
     *                               converting to
1609
     *                               boolean) will be removed.
1610
     *                               </p>
1611
     * @param int           $flag    [optional] <p>
1612 1
     *                               Flag determining what arguments are sent to <i>callback</i>:
1613
     *                               </p><ul>
1614 1
     *                               <li>
1615 1
     *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1616
     *                               to <i>callback</i> instead of the value</span>
1617
     *                               </li>
1618
     *                               <li>
1619
     *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1620 1
     *                               arguments to <i>callback</i> instead of the value</span>
1621 1
     *                               </li>
1622
     *                               </ul>
1623
     *
1624 1
     * @return static
1625
     *                <p>(Immutable)</p>
1626
     */
1627 1
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH)
1628
    {
1629
        if (!$closure) {
1630 1
            return $this->clean();
1631
        }
1632 1
1633 1
        return static::create(
1634
            \array_filter($this->getArray(), $closure, $flag),
1635
            $this->iteratorClass,
1636 1
            false
1637
        );
1638
    }
1639 1
1640
    /**
1641
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
1642 1
     * property within that.
1643
     *
1644 1
     * @param string          $property
1645 1
     * @param string|string[] $value
1646
     * @param string          $comparisonOp
1647
     *                                      <p>
1648 1
     *                                      'eq' (equals),<br />
1649
     *                                      'gt' (greater),<br />
1650
     *                                      'gte' || 'ge' (greater or equals),<br />
1651 1
     *                                      'lt' (less),<br />
1652
     *                                      'lte' || 'le' (less or equals),<br />
1653
     *                                      'ne' (not equals),<br />
1654 1
     *                                      'contains',<br />
1655
     *                                      'notContains',<br />
1656
     *                                      'newer' (via strtotime),<br />
1657 1
     *                                      'older' (via strtotime),<br />
1658 1
     *                                      </p>
1659 1
     *
1660
     * @return static
1661 1
     *                <p>(Immutable)</p>
1662 1
     */
1663 1
    public function filterBy(string $property, $value, string $comparisonOp = null): self
1664 1
    {
1665
        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...
1666 1
            $comparisonOp = \is_array($value) === true ? 'contains' : 'eq';
1667 1
        }
1668 1
1669
        $ops = [
1670 1
            'eq' => static function ($item, $prop, $value): bool {
1671 1
                return $item[$prop] === $value;
1672
            },
1673
            'gt' => static function ($item, $prop, $value): bool {
1674
                return $item[$prop] > $value;
1675 1
            },
1676 1
            'ge' => static function ($item, $prop, $value): bool {
1677 1
                return $item[$prop] >= $value;
1678 1
            },
1679
            'gte' => static function ($item, $prop, $value): bool {
1680
                return $item[$prop] >= $value;
1681
            },
1682
            'lt' => static function ($item, $prop, $value): bool {
1683
                return $item[$prop] < $value;
1684
            },
1685
            'le' => static function ($item, $prop, $value): bool {
1686
                return $item[$prop] <= $value;
1687
            },
1688
            'lte' => static function ($item, $prop, $value): bool {
1689
                return $item[$prop] <= $value;
1690
            },
1691 8
            'ne' => static function ($item, $prop, $value): bool {
1692
                return $item[$prop] !== $value;
1693 8
            },
1694 6
            'contains' => static function ($item, $prop, $value): bool {
1695 5
                return \in_array($item[$prop], (array) $value, true);
1696
            },
1697
            'notContains' => static function ($item, $prop, $value): bool {
1698
                return !\in_array($item[$prop], (array) $value, true);
1699 3
            },
1700
            'newer' => static function ($item, $prop, $value): bool {
1701
                return \strtotime($item[$prop]) > \strtotime($value);
1702
            },
1703
            'older' => static function ($item, $prop, $value): bool {
1704
                return \strtotime($item[$prop]) < \strtotime($value);
1705
            },
1706
        ];
1707
1708
        $result = \array_values(
1709
            \array_filter(
1710
                $this->getArray(),
1711
                static function ($item) use (
1712 1
                    $property,
1713
                    $value,
1714 1
                    $ops,
1715
                    $comparisonOp
1716
                ) {
1717
                    $item = (array) $item;
1718
                    $itemArrayy = static::create($item);
1719
                    $item[$property] = $itemArrayy->get($property, []);
1720
1721
                    return $ops[$comparisonOp]($item, $property, $value);
1722
                }
1723 21
            )
1724
        );
1725 21
1726 21
        return static::create(
1727 3
            $result,
1728
            $this->iteratorClass,
1729
            false
1730 18
        );
1731
    }
1732
1733
    /**
1734
     * Find the first item in an array that passes the truth test,
1735
     *  otherwise return false
1736
     *
1737
     * @param \Closure $closure
1738
     *
1739 28
     * @return false|mixed
1740
     *                     <p>Return false if we did not find the value.</p>
1741 28
     */
1742
    public function find(\Closure $closure)
1743 28
    {
1744
        foreach ($this->getGenerator() as $key => $value) {
1745
            if ($closure($value, $key)) {
1746
                return $value;
1747
            }
1748
        }
1749
1750
        return false;
1751
    }
1752
1753
    /**
1754
     * find by ...
1755 37
     *
1756
     * @param string          $property
1757 37
     * @param string|string[] $value
1758
     * @param string          $comparisonOp
1759 37
     *
1760 14
     * @return static
1761
     *                <p>(Immutable)</p>
1762 23
     */
1763 23
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
1764
    {
1765
        return $this->filterBy($property, $value, $comparisonOp);
1766 37
    }
1767 37
1768 37
    /**
1769 37
     * Get the first value from the current array.
1770
     *
1771
     * @return mixed
1772
     *               <p>Return null if there wasn't a element.</p>
1773
     */
1774
    public function first()
1775
    {
1776
        $key_first = $this->firstKey();
1777
        if ($key_first === null) {
1778
            return null;
1779
        }
1780
1781
        return $this->get($key_first);
1782 3
    }
1783
1784 3
    /**
1785
     * Get the first key from the current array.
1786 3
     *
1787
     * @return mixed
1788
     *               <p>Return null if there wasn't a element.</p>
1789 3
     */
1790 3
    public function firstKey()
1791
    {
1792
        $this->generatorToArray();
1793 3
1794 3
        return \array_key_first($this->array);
1795 3
    }
1796 3
1797
    /**
1798
     * Get the first value(s) from the current array.
1799
     * And will return an empty array if there was no first entry.
1800
     *
1801
     * @param int|null $number <p>How many values you will take?</p>
1802
     *
1803
     * @return static
1804
     *                <p>(Immutable)</p>
1805
     */
1806 View Code Duplication
    public function firstsImmutable(int $number = null): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1807
    {
1808
        $arrayTmp = $this->getArray();
1809 34
1810
        if ($number === null) {
1811 34
            $array = (array) \array_shift($arrayTmp);
1812
        } else {
1813 34
            $number = (int) $number;
1814 19
            $array = \array_splice($arrayTmp, 0, $number);
1815
        }
1816 15
1817 15
        return static::create(
1818
            $array,
1819
            $this->iteratorClass,
1820 34
            false
1821
        );
1822
    }
1823
1824
    /**
1825
     * Get the first value(s) from the current array.
1826
     * And will return an empty array if there was no first entry.
1827
     *
1828
     * @param int|null $number <p>How many values you will take?</p>
1829 1
     *
1830
     * @return static
1831 1
     *                <p>(Immutable)</p>
1832 1
     */
1833 1 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...
1834 1
    {
1835
        $arrayTmp = $this->keys()->getArray();
1836
1837
        if ($number === null) {
1838
            $array = (array) \array_shift($arrayTmp);
1839
        } else {
1840
            $number = (int) $number;
1841
            $array = \array_splice($arrayTmp, 0, $number);
1842
        }
1843
1844
        return static::create(
1845
            $array,
1846
            $this->iteratorClass,
1847
            false
1848 168
        );
1849
    }
1850 168
1851 4
    /**
1852
     * Get and rmove the first value(s) from the current array.
1853 165
     * And will return an empty array if there was no first entry.
1854
     *
1855 165
     * @param int|null $number <p>How many values you will take?</p>
1856
     *
1857
     * @return static
1858 168
     *                <p>(Mutable)</p>
1859 1
     */
1860 1
    public function firstsMutable(int $number = null): self
1861 1
    {
1862 1
        $this->generatorToArray();
1863
1864
        if ($number === null) {
1865
            $this->array = (array) \array_shift($this->array);
1866
        } else {
1867 168
            $number = (int) $number;
1868 3
            $this->array = \array_splice($this->array, 0, $number);
1869
        }
1870
1871 168
        return $this;
1872 158
    }
1873 11
1874 11
    /**
1875 11
     * Exchanges all keys with their associated values in an array.
1876 11
     *
1877
     * @return static
1878
     *                <p>(Immutable)</p>
1879
     */
1880 150
    public function flip(): self
1881
    {
1882
        return static::create(
1883
            \array_flip($this->getArray()),
1884 24
            $this->iteratorClass,
1885
            false
1886 24
        );
1887
    }
1888 24
1889
    /**
1890 24
     * Tests whether the given predicate p holds for all elements of this array.
1891
     *
1892 7
     * @param \Closure $closure the predicate
1893 7
     *
1894 7
     * @return bool
1895
     *              <p>TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.</p>
1896 7
     */
1897
    public function forAll(\Closure $closure): bool
1898
    {
1899 7
        foreach ($this->getGenerator() as $key => $element) {
1900
            if (!$closure($key, $element)) {
1901 7
                return false;
1902
            }
1903
        }
1904 7
1905
        return true;
1906 7
    }
1907
1908 7
    /**
1909
     * Get a value from an array (optional using dot-notation).
1910
     *
1911
     * @param mixed $key      <p>The key to look for.</p>
1912 6
     * @param mixed $fallback <p>Value to fallback to.</p>
1913
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
1914 6
     *                        class.</p>
1915
     *
1916 1
     * @return mixed|static
1917
     */
1918 1
    public function get($key, $fallback = null, array $array = null)
1919
    {
1920
        if ($array !== null) {
1921 5
            $usedArray = $array;
1922
        } else {
1923
            $this->generatorToArray();
1924
1925
            $usedArray = $this->array;
1926 24
        }
1927 17
1928
        if ($key === null) {
1929
            return static::create(
1930 7
                $usedArray,
1931 1
                $this->iteratorClass,
1932 1
                false
1933 1
            );
1934 1
        }
1935
1936
        // php cast "bool"-index into "int"-index
1937
        if ((bool) $key === $key) {
1938 7
            $key = (int) $key;
1939
        }
1940
1941
        if (\array_key_exists($key, $usedArray) === true) {
1942
            if (\is_array($usedArray[$key]) === true) {
1943
                return static::create(
1944
                    $usedArray[$key],
1945
                    $this->iteratorClass,
1946
                    false
1947
                );
1948 1
            }
1949
1950 1
            return $usedArray[$key];
1951
        }
1952
1953
        // crawl through array, get key according to object or not
1954
        $usePath = false;
1955
        if (
1956
            $this->pathSeparator
1957
            &&
1958
            (string) $key === $key
1959
            &&
1960 839
            \strpos($key, $this->pathSeparator) !== false
1961
        ) {
1962
            $segments = \explode($this->pathSeparator, (string) $key);
1963 839
            if ($segments !== false) {
1964
                $usePath = true;
1965 839
1966 1
                foreach ($segments as $segment) {
1967 1
                    if (
1968 1
                        (
1969
                            \is_array($usedArray) === true
1970
                            ||
1971 1
                            $usedArray instanceof \ArrayAccess
1972
                        )
1973
                        &&
1974 839
                        isset($usedArray[$segment])
1975 730
                    ) {
1976
                        $usedArray = $usedArray[$segment];
1977
1978
                        continue;
1979 839
                    }
1980
1981
                    if (
1982
                        \is_object($usedArray) === true
1983
                        &&
1984
                        \property_exists($usedArray, $segment)
1985
                    ) {
1986
                        $usedArray = $usedArray->{$segment};
1987
1988
                        continue;
1989
                    }
1990
1991
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
1992
                }
1993
            }
1994
        }
1995 1
1996
        if (!$usePath && !isset($usedArray[$key])) {
1997 1
            return $fallback instanceof \Closure ? $fallback() : $fallback;
1998 1
        }
1999 1
2000 1
        if (\is_array($usedArray) === true) {
2001
            return static::create(
2002
                $usedArray,
2003
                $this->iteratorClass,
2004
                false
2005
            );
2006
        }
2007
2008
        return $usedArray;
2009 917
    }
2010
2011 917
    /**
2012 39
     * alias: for "Arrayy->getArray()"
2013
     *
2014
     * @return array
2015 917
     *
2016 873
     * @see Arrayy::getArray()
2017
     */
2018
    public function getAll(): array
2019
    {
2020
        return $this->getArray();
2021
    }
2022
2023
    /**
2024
     * Get the current array from the "Arrayy"-object.
2025
     *
2026 2
     * @param bool $convertAllArrayyElements
2027
     *
2028 2
     * @return array
2029
     */
2030
    public function getArray($convertAllArrayyElements = false): array
2031
    {
2032
        // init
2033
        $array = [];
2034
2035
        if ($convertAllArrayyElements) {
2036 4
            foreach ($this->getGenerator() as $key => $value) {
2037
                if ($value instanceof self) {
2038 4
                    $value = $value->getArray(true);
2039
                }
2040
2041
                $array[$key] = $value;
2042
            }
2043
        } else {
2044
            foreach ($this->getGenerator() as $key => $value) {
2045
                $array[$key] = $value;
2046
            }
2047
        }
2048
2049 4
        return $array;
2050
    }
2051 4
2052
    /**
2053
     * Returns the values from a single column of the input array, identified by
2054
     * the $columnKey, can be used to extract data-columns from multi-arrays.
2055
     *
2056
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
2057
     * array by the values from the $indexKey column in the input array.
2058
     *
2059
     * @param mixed $columnKey
2060
     * @param mixed $indexKey
2061
     *
2062 3
     * @return static
2063
     *                <p>(Immutable)</p>
2064 3
     */
2065
    public function getColumn($columnKey = null, $indexKey = null): self
2066
    {
2067
        return static::create(
2068
            \array_column($this->getArray(), $columnKey, $indexKey),
2069
            $this->iteratorClass,
2070
            false
2071
        );
2072
    }
2073
2074
    /**
2075
     * Get the current array from the "Arrayy"-object as generator.
2076
     *
2077 8
     * @return \Generator
2078
     */
2079 8
    public function getGenerator(): \Generator
2080
    {
2081
        if ($this->generator instanceof ArrayyRewindableGenerator) {
2082
            yield from $this->generator;
2083
        }
2084
2085
        yield from $this->array;
2086
    }
2087
2088
    /**
2089
     * alias: for "Arrayy->keys()"
2090 3
     *
2091
     * @return static
2092 3
     *                <p>(Immutable)</p>
2093
     *
2094
     * @see Arrayy::keys()
2095
     */
2096
    public function getKeys()
2097
    {
2098
        return $this->keys();
2099
    }
2100
2101
    /**
2102
     * Get the current array from the "Arrayy"-object as object.
2103
     *
2104
     * @return \stdClass
2105 6
     */
2106
    public function getObject(): \stdClass
2107 6
    {
2108
        return self::arrayToObject($this->getArray());
2109
    }
2110
2111
    /**
2112
     * alias: for "Arrayy->randomImmutable()"
2113
     *
2114
     * @return static
2115
     *                <p>(Immutable)</p>
2116
     *
2117
     * @see Arrayy::randomImmutable()
2118
     */
2119 4
    public function getRandom(): self
2120
    {
2121
        return $this->randomImmutable();
2122 4
    }
2123
2124
    /**
2125 4
     * alias: for "Arrayy->randomKey()"
2126 4
     *
2127 3
     * @return mixed
2128
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2129 1
     *
2130
     * @see Arrayy::randomKey()
2131
     */
2132 4
    public function getRandomKey()
2133
    {
2134 4
        return $this->randomKey();
2135
    }
2136
2137
    /**
2138 4
     * alias: for "Arrayy->randomKeys()"
2139 4
     *
2140
     * @param int $number
2141
     *
2142
     * @return static
2143 4
     *                <p>(Immutable)</p>
2144 3
     *
2145 2
     * @see Arrayy::randomKeys()
2146 2
     */
2147
    public function getRandomKeys(int $number): self
2148 1
    {
2149 1
        return $this->randomKeys($number);
2150
    }
2151
2152
    /**
2153
     * alias: for "Arrayy->randomValue()"
2154 4
     *
2155 4
     * @return mixed
2156 4
     *               <p>Get a random value or null if there wasn't a value.</p>
2157 4
     *
2158
     * @see Arrayy::randomValue()
2159
     */
2160
    public function getRandomValue()
2161
    {
2162
        return $this->randomValue();
2163
    }
2164
2165
    /**
2166
     * alias: for "Arrayy->randomValues()"
2167
     *
2168
     * @param int $number
2169
     *
2170 1
     * @return static
2171
     *                <p>(Immutable)</p>
2172 1
     *
2173
     * @see Arrayy::randomValues()
2174
     */
2175
    public function getRandomValues(int $number): self
2176
    {
2177
        return $this->randomValues($number);
2178
    }
2179
2180
    /**
2181
     * Gets all values.
2182 23
     *
2183
     * @return static
2184 23
     *                <p>The values of all elements in this array, in the order they
2185
     *                appear in the array.</p>
2186 23
     */
2187
    public function getValues()
2188 1
    {
2189
        $this->generatorToArray();
2190
2191 23
        return static::create(
2192
            \array_values($this->array),
2193
            $this->iteratorClass,
2194
            false
2195
        );
2196
    }
2197
2198
    /**
2199
     * Gets all values via Generator.
2200
     *
2201 28
     * @return \Generator
2202
     *                    <p>The values of all elements in this array, in the order they
2203 28
     *                    appear in the array as Generator.</p>
2204
     */
2205
    public function getValuesYield(): \Generator
2206
    {
2207
        yield from $this->getGenerator();
2208
    }
2209
2210
    /**
2211
     * Group values from a array according to the results of a closure.
2212
     *
2213 8
     * @param callable|string $grouper  <p>A callable function name.</p>
2214
     * @param bool            $saveKeys
2215 8
     *
2216
     * @return static
2217
     *                <p>(Immutable)</p>
2218
     */
2219
    public function group($grouper, bool $saveKeys = false): self
2220
    {
2221
        // init
2222
        $result = [];
2223
2224
        // Iterate over values, group by property/results from closure.
2225
        foreach ($this->getGenerator() as $key => $value) {
2226
            if (\is_callable($grouper) === true) {
2227
                $groupKey = $grouper($value, $key);
2228 4
            } else {
2229
                $groupKey = $this->get($grouper);
2230
            }
2231 4
2232
            $newValue = $this->get($groupKey, null, $result);
2233 4
2234 4
            if ($groupKey instanceof self) {
2235 3
                $groupKey = $groupKey->getArray();
2236
            }
2237
2238
            if ($newValue instanceof self) {
2239 4
                $newValue = $newValue->getArray();
2240 4
            }
2241 4
2242 4
            // Add to results.
2243
            if ($groupKey !== null) {
2244
                if ($saveKeys) {
2245
                    $result[$groupKey] = $newValue;
2246
                    $result[$groupKey][$key] = $value;
2247
                } else {
2248
                    $result[$groupKey] = $newValue;
2249
                    $result[$groupKey][] = $value;
2250
                }
2251
            }
2252
        }
2253
2254
        return static::create(
2255 4
            $result,
2256
            $this->iteratorClass,
2257 4
            false
2258
        );
2259
    }
2260
2261
    /**
2262
     * Check if an array has a given key.
2263
     *
2264
     * @param mixed $key
2265
     *
2266
     * @return bool
2267
     */
2268 12
    public function has($key): bool
2269
    {
2270 12
        static $UN_FOUND = null;
2271
2272
        if ($UN_FOUND === null) {
2273
            // Generate unique string to use as marker.
2274
            $UN_FOUND = \uniqid('arrayy', true);
2275
        }
2276
2277
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2278
    }
2279
2280
    /**
2281 1
     * Check if an array has a given value.
2282
     *
2283 1
     * INFO: if you need to search recursive please use ```contains()```
2284 1
     *
2285 1
     * @param mixed $value
2286 1
     *
2287
     * @return bool
2288
     */
2289
    public function hasValue($value): bool
2290
    {
2291
        return $this->contains($value);
2292
    }
2293
2294
    /**
2295
     * Implodes the values of this array.
2296
     *
2297
     * @param string $glue
2298
     *
2299 4
     * @return string
2300
     */
2301 4
    public function implode(string $glue = ''): string
2302 1
    {
2303 1
        return $this->implode_recursive($glue, $this->getArray(), false);
2304 1
    }
2305 1
2306
    /**
2307 1
     * Implodes the keys of this array.
2308 1
     *
2309
     * @param string $glue
2310 1
     *
2311 1
     * @return string
2312
     */
2313
    public function implodeKeys(string $glue = ''): string
2314
    {
2315 3
        return $this->implode_recursive($glue, $this->getArray(), true);
2316 3
    }
2317 3
2318 3
    /**
2319
     * Given a list and an iterate-function that returns
2320
     * a key for each element in the list (or a property name),
2321
     * returns an object with an index of each item.
2322
     *
2323
     * @param mixed $key
2324
     *
2325
     * @return static
2326
     *                <p>(Immutable)</p>
2327
     */
2328
    public function indexBy($key): self
2329 1
    {
2330
        // init
2331 1
        $results = [];
2332
2333
        foreach ($this->getGenerator() as $a) {
2334
            if (\array_key_exists($key, $a) === true) {
2335
                $results[$a[$key]] = $a;
2336
            }
2337
        }
2338
2339
        return static::create(
2340
            $results,
2341
            $this->iteratorClass,
2342
            false
2343 1
        );
2344
    }
2345
2346 1
    /**
2347 1
     * alias: for "Arrayy->searchIndex()"
2348 1
     *
2349 1
     * @param mixed $value <p>The value to search for.</p>
2350 1
     *
2351
     * @return false|mixed
2352
     *
2353
     * @see Arrayy::searchIndex()
2354
     */
2355 1
    public function indexOf($value)
2356 1
    {
2357
        return $this->searchIndex($value);
2358 1
    }
2359
2360
    /**
2361 1
     * Get everything but the last..$to items.
2362 1
     *
2363 1
     * @param int $to
2364 1
     *
2365
     * @return static
2366
     *                <p>(Immutable)</p>
2367
     */
2368
    public function initial(int $to = 1): self
2369
    {
2370
        return $this->firstsImmutable(\count($this->getArray(), \COUNT_NORMAL) - $to);
2371
    }
2372
2373
    /**
2374
     * Return an array with all elements found in input array.
2375
     *
2376 15
     * @param array $search
2377
     * @param bool  $keepKeys
2378 15
     *
2379 3
     * @return static
2380
     *                <p>(Immutable)</p>
2381
     */
2382 13
    public function intersection(array $search, bool $keepKeys = false): self
2383 13
    {
2384 11
        if ($keepKeys) {
2385
            return static::create(
2386
                \array_uintersect(
2387
                    $this->array,
2388 3
                    $search,
2389
                    static function ($a, $b) {
2390
                        return $a === $b ? 0 : -1;
2391
                    }
2392
                ),
2393
                $this->iteratorClass,
2394
                false
2395
            );
2396
        }
2397
2398
        return static::create(
2399 38
            \array_values(\array_intersect($this->getArray(), $search)),
2400
            $this->iteratorClass,
2401 38
            false
2402
        );
2403
    }
2404
2405 38
    /**
2406 38
     * Return an array with all elements found in input array.
2407
     *
2408
     * @param array ...$array
2409
     *
2410
     * @return static
2411
     *                <p>(Immutable)</p>
2412
     */
2413
    public function intersectionMulti(...$array): self
2414
    {
2415
        return static::create(
2416
            \array_values(\array_intersect($this->getArray(), ...$array)),
2417
            $this->iteratorClass,
2418
            false
2419
        );
2420
    }
2421
2422
    /**
2423
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
2424
     *
2425 1
     * @param array $search
2426
     *
2427 1
     * @return bool
2428
     */
2429
    public function intersects(array $search): bool
2430
    {
2431
        return \count($this->intersection($search)->array, \COUNT_NORMAL) > 0;
2432
    }
2433
2434
    /**
2435 22
     * Invoke a function on all of an array's values.
2436
     *
2437
     * @param callable $callable
2438 22
     * @param mixed    $arguments
2439
     *
2440 22
     * @return static
2441
     *                <p>(Immutable)</p>
2442
     */
2443
    public function invoke($callable, $arguments = []): self
2444
    {
2445
        // If one argument given for each iteration, create an array for it.
2446
        if (\is_array($arguments) === false) {
2447
            $arguments = \array_fill(
2448
                0,
2449
                \count($this->getArray(), \COUNT_NORMAL),
2450 5
                $arguments
2451
            );
2452 5
        }
2453 2
2454
        // If the callable has arguments, pass them.
2455
        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...
2456 4
            $array = \array_map($callable, $this->getArray(), $arguments);
2457 4
        } else {
2458 2
            $array = $this->map($callable);
2459
        }
2460
2461
        return static::create(
2462 2
            $array,
2463
            $this->iteratorClass,
2464
            false
2465
        );
2466
    }
2467
2468
    /**
2469
     * Check whether array is associative or not.
2470
     *
2471
     * @param bool $recursive
2472 1
     *
2473
     * @return bool
2474
     *              <p>Returns true if associative, false otherwise.</p>
2475
     */
2476 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...
2477 1
    {
2478
        if ($this->isEmpty()) {
2479
            return false;
2480
        }
2481
2482
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2483
            if ((string) $key !== $key) {
2484
                return false;
2485 1
            }
2486
        }
2487 1
2488
        return true;
2489
    }
2490
2491
    /**
2492
     * Check if a given key or keys are empty.
2493
     *
2494
     * @param int|int[]|string|string[]|null $keys
2495
     *
2496
     * @return bool
2497
     *              <p>Returns true if empty, false otherwise.</p>
2498
     */
2499
    public function isEmpty($keys = null): bool
2500
    {
2501
        if ($this->generator) {
2502
            return $this->getArray() === [];
2503
        }
2504
2505
        if ($keys === null) {
2506
            return $this->array === [];
2507
        }
2508 123
2509
        foreach ((array) $keys as $key) {
2510 123
            if (!empty($this->get($key))) {
2511
                return false;
2512
            }
2513
        }
2514
2515
        return true;
2516
    }
2517
2518
    /**
2519
     * Check if the current array is equal to the given "$array" or not.
2520
     *
2521
     * @param array $array
2522
     *
2523
     * @return bool
2524
     */
2525
    public function isEqual(array $array): bool
2526
    {
2527
        return $this->getArray() === $array;
2528
    }
2529 29
2530
    /**
2531
     * Check if the current array is a multi-array.
2532
     *
2533
     * @return bool
2534
     */
2535
    public function isMultiArray(): bool
2536
    {
2537 29
        return !(
2538 4
            \count($this->getArray(), \COUNT_NORMAL)
2539 4
            ===
2540 4
            \count($this->getArray(), \COUNT_RECURSIVE)
2541 4
        );
2542
    }
2543
2544 4
    /**
2545 4
     * Check whether array is numeric or not.
2546 4
     *
2547 4
     * @return bool
2548
     *              <p>Returns true if numeric, false otherwise.</p>
2549
     */
2550 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...
2551
    {
2552
        if ($this->isEmpty()) {
2553 28
            return false;
2554
        }
2555 28
2556 26
        foreach ($this->keys()->getGenerator() as $key) {
2557
            if ((int) $key !== $key) {
2558 28
                return false;
2559
            }
2560
        }
2561 1
2562
        return true;
2563 1
    }
2564
2565
    /**
2566 1
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2567
     *
2568 1
     * @param bool $recursive
2569
     *
2570 1
     * @return bool
2571
     */
2572
    public function isSequential(bool $recursive = false): bool
2573
    {
2574 1
2575
        // recursive
2576 1
2577
        if ($recursive === true) {
2578 1
            return $this->array_keys_recursive($this->getArray())
2579
                   ===
2580
                   \range(0, \count($this->getArray(), \COUNT_RECURSIVE) - 1);
2581
        }
2582 1
2583
        // non recursive
2584 1
2585
        return \array_keys($this->getArray())
2586
               ===
2587 1
               \range(0, \count($this->getArray(), \COUNT_NORMAL) - 1);
2588
    }
2589
2590 1
    /**
2591
     * @return array
2592
     */
2593 28
    public function jsonSerialize(): array
2594 28
    {
2595 28
        return $this->getArray();
2596 28
    }
2597
2598
    /**
2599
     * Gets the key/index of the element at the current internal iterator position.
2600
     *
2601
     * @return int|string|null
2602
     */
2603
    public function key()
2604
    {
2605
        return \key($this->array);
2606
    }
2607
2608
    /**
2609
     * Checks if the given key exists in the provided array.
2610
     *
2611
     * INFO: This method only use "array_key_exists()" if you want to use "dot"-notation,
2612 4
     *       then you need to use "Arrayy->offsetExists()".
2613
     *
2614 4
     * @param int|string $key the key to look for
2615
     *
2616 4
     * @return bool
2617
     */
2618 4
    public function keyExists($key): bool
2619
    {
2620
        return \array_key_exists($key, $this->array);
2621
    }
2622
2623
    /**
2624
     * Get all keys from the current array.
2625
     *
2626
     * @param bool       $recursive     [optional] <p>
2627 17
     *                                  Get all keys, also from all sub-arrays from an multi-dimensional array.
2628
     *                                  </p>
2629 17
     * @param mixed|null $search_values [optional] <p>
2630 17
     *                                  If specified, then only keys containing these values are returned.
2631 2
     *                                  </p>
2632
     * @param bool       $strict        [optional] <p>
2633
     *                                  Determines if strict comparison (===) should be used during the search.
2634 15
     *                                  </p>
2635
     *
2636
     * @return static
2637
     *                <p>(Immutable) An array of all the keys in input.</p>
2638
     */
2639
    public function keys(
2640
        bool $recursive = false,
2641
        $search_values = null,
2642
        bool $strict = true
2643 21
    ): self {
2644
2645 21
        // recursive
2646
2647 21
        if ($recursive === true) {
2648
            $array = $this->array_keys_recursive(
2649
                null,
2650
                $search_values,
2651
                $strict
2652
            );
2653
2654
            return static::create(
2655
                $array,
2656
                $this->iteratorClass,
2657
                false
2658 13
            );
2659
        }
2660 13
2661 1
        // non recursive
2662 1
2663 1
        if ($search_values === null) {
2664 1
            $arrayFunction = /**
2665
             * @return \Generator
2666
             *
2667
             * @phpstan-return \Generator<int, mixed, mixed, void>
2668 12
             */
2669 8
            function (): \Generator {
2670
                foreach ($this->getGenerator() as $key => $value) {
2671 8
                    yield $key;
2672 1
                }
2673
            };
2674 7
        } else {
2675
            $arrayFunction = /**
2676
             * @return \Generator
2677 8
             *
2678 8
             * @phpstan-return \Generator<int, mixed, mixed, void>
2679 8
             */
2680 8
            function () use ($search_values, $strict): \Generator {
2681
                $is_array_tmp = \is_array($search_values);
2682
2683 4
                foreach ($this->getGenerator() as $key => $value) {
2684 4 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...
2685
                        (
2686
                            $is_array_tmp === false
2687 12
                            &&
2688
                            $strict === true
2689
                            &&
2690
                            $search_values === $value
2691
                        )
2692
                        ||
2693
                        (
2694
                            $is_array_tmp === false
2695
                            &&
2696
                            $strict === false
2697
                            &&
2698 13
                            $search_values == $value
2699
                        )
2700 13
                        ||
2701 1
                        (
2702
                            $is_array_tmp === true
2703
                            &&
2704 12
                            \in_array($value, $search_values, $strict)
2705 8
                        )
2706
                    ) {
2707 8
                        yield $key;
2708 1
                    }
2709
                }
2710 7
            };
2711
        }
2712
2713 8
        return static::create(
2714 8
            $arrayFunction,
2715 8
            $this->iteratorClass,
2716 8
            false
2717 8
        );
2718
    }
2719 4
2720 4
    /**
2721
     * Sort an array by key in reverse order.
2722
     *
2723 12
     * @param int $sort_flags [optional] <p>
2724
     *                        You may modify the behavior of the sort using the optional
2725 12
     *                        parameter sort_flags, for details
2726
     *                        see sort.
2727
     *                        </p>
2728
     *
2729
     * @return static
2730
     *                <p>(Mutable) Return this Arrayy object.</p>
2731
     */
2732
    public function krsort(int $sort_flags = 0): self
2733
    {
2734
        $this->generatorToArray();
2735
2736
        \krsort($this->array, $sort_flags);
2737
2738
        return $this;
2739 20
    }
2740
2741 20
    /**
2742
     * Get the last value from the current array.
2743
     *
2744
     * @return mixed
2745
     *               <p>Return null if there wasn't a element.</p>
2746
     */
2747
    public function last()
2748
    {
2749
        $key_last = $this->lastKey();
2750
        if ($key_last === null) {
2751
            return null;
2752
        }
2753
2754
        return $this->get($key_last);
2755 5
    }
2756
2757 5
    /**
2758
     * Get the last key from the current array.
2759 5
     *
2760
     * @return mixed
2761 5
     *               <p>Return null if there wasn't a element.</p>
2762 4
     */
2763 3
    public function lastKey()
2764
    {
2765
        $this->generatorToArray();
2766 3
2767
        return \array_key_last($this->array);
2768
    }
2769
2770 4
    /**
2771
     * Get the last value(s) from the current array.
2772
     *
2773 4
     * @param int|null $number
2774
     *
2775
     * @return static
2776
     *                <p>(Immutable)</p>
2777 5
     */
2778 5
    public function lastsImmutable(int $number = null): self
2779 5
    {
2780
        if ($this->isEmpty()) {
2781
            return static::create(
2782
                [],
2783
                $this->iteratorClass,
2784
                false
2785
            );
2786
        }
2787
2788
        if ($number === null) {
2789
            $poppedValue = $this->last();
2790 15
2791
            if ($poppedValue === null) {
2792 15
                $poppedValue = [$poppedValue];
2793 2
            } else {
2794
                $poppedValue = (array) $poppedValue;
2795
            }
2796 13
2797 13
            $arrayy = static::create(
2798
                $poppedValue,
2799 13
                $this->iteratorClass,
2800 7
                false
2801
            );
2802
        } else {
2803
            $number = (int) $number;
2804 7
            $arrayy = $this->rest(-$number);
2805
        }
2806
2807
        return $arrayy;
2808
    }
2809
2810
    /**
2811
     * Get the last value(s) from the current array.
2812
     *
2813
     * @param int|null $number
2814 14
     *
2815
     * @return static
2816 14
     *                <p>(Mutable)</p>
2817 2
     */
2818
    public function lastsMutable(int $number = null): self
2819
    {
2820 12
        if ($this->isEmpty()) {
2821 12
            return $this;
2822
        }
2823 12
2824 9
        if ($number === null) {
2825
            $poppedValue = $this->last();
2826
2827
            if ($poppedValue === null) {
2828 4
                $poppedValue = [$poppedValue];
2829
            } else {
2830
                $poppedValue = (array) $poppedValue;
2831
            }
2832
2833
            $this->array = static::create(
2834
                $poppedValue,
2835
                $this->iteratorClass,
2836 10
                false
2837
            )->getArray();
2838 10
        } else {
2839 1
            $number = (int) $number;
2840
            $this->array = $this->rest(-$number)->getArray();
2841
        }
2842 9
2843
        $this->generator = null;
2844
2845
        return $this;
2846
    }
2847
2848
    /**
2849
     * Count the values from the current array.
2850
     *
2851
     * alias: for "Arrayy->count()"
2852
     *
2853
     * @param int $mode
2854
     *
2855
     * @return int
2856 25
     *
2857
     * @see Arrayy::count()
2858 25
     */
2859 4
    public function length(int $mode = \COUNT_NORMAL): int
2860
    {
2861 21
        return $this->count($mode);
2862
    }
2863
2864 25
    /**
2865 25
     * Apply the given function to the every element of the array,
2866 25
     * collecting the results.
2867 25
     *
2868
     * @param callable $callable
2869
     * @param bool     $useKeyAsSecondParameter
2870
     * @param mixed    ...$arguments
2871
     *
2872
     * @return static
2873
     *                <p>(Immutable) Arrayy object with modified elements.</p>
2874
     */
2875
    public function map(callable $callable, bool $useKeyAsSecondParameter = false, ...$arguments)
2876
    {
2877
        $useArguments = \func_num_args() > 2;
2878
2879
        return static::create(
2880
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
2881
                foreach ($this->getGenerator() as $key => $value) {
2882
                    if ($useArguments) {
2883 16
                        if ($useKeyAsSecondParameter) {
2884
                            yield $key => $callable($value, $key, ...$arguments);
2885 16
                        } else {
2886 4
                            yield $key => $callable($value, ...$arguments);
2887
                        }
2888 12
                    } else {
2889
                        /** @noinspection NestedPositiveIfStatementsInspection */
2890
                        if ($useKeyAsSecondParameter) {
2891 16
                            yield $key => $callable($value, $key);
2892 16
                        } else {
2893 16
                            yield $key => $callable($value);
2894 16
                        }
2895
                    }
2896
                }
2897
            },
2898
            $this->iteratorClass,
2899
            false
2900
        );
2901
    }
2902
2903
    /**
2904
     * Check if all items in current array match a truth test.
2905
     *
2906
     * @param \Closure $closure
2907
     *
2908
     * @return bool
2909 16
     */
2910 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...
2911 16
    {
2912 4
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2913
            return false;
2914 12
        }
2915
2916
        foreach ($this->getGenerator() as $key => $value) {
2917 16
            $value = $closure($value, $key);
2918 16
2919 16
            if ($value === false) {
2920 16
                return false;
2921
            }
2922
        }
2923
2924
        return true;
2925
    }
2926
2927
    /**
2928
     * Check if any item in the current array matches a truth test.
2929
     *
2930
     * @param \Closure $closure
2931
     *
2932
     * @return bool
2933
     */
2934 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...
2935
    {
2936 17
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2937
            return false;
2938 17
        }
2939 4
2940
        foreach ($this->getGenerator() as $key => $value) {
2941 13
            $value = $closure($value, $key);
2942
2943
            if ($value === true) {
2944 17
                return true;
2945 17
            }
2946 17
        }
2947 17
2948
        return false;
2949
    }
2950
2951
    /**
2952
     * Get the max value from an array.
2953
     *
2954 15
     * @return mixed
2955
     */
2956 15 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...
2957
    {
2958
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2959
            return false;
2960
        }
2961
2962
        return \max($this->getArray());
2963
    }
2964 10
2965
    /**
2966 10
     * Merge the new $array into the current array.
2967 1
     *
2968
     * - keep key,value from the current array, also if the index is in the new $array
2969
     *
2970 9
     * @param array $array
2971
     * @param bool  $recursive
2972
     *
2973
     * @return static
2974
     *                <p>(Immutable)</p>
2975
     */
2976 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...
2977
    {
2978
        if ($recursive === true) {
2979 3
            $result = \array_replace_recursive($this->getArray(), $array);
2980
        } else {
2981 3
            $result = \array_replace($this->getArray(), $array);
2982
        }
2983
2984
        return static::create(
2985
            $result,
2986
            $this->iteratorClass,
2987
            false
2988
        );
2989
    }
2990
2991
    /**
2992 3
     * Merge the new $array into the current array.
2993
     *
2994 3
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2995
     * - create new indexes
2996
     *
2997
     * @param array $array
2998
     * @param bool  $recursive
2999
     *
3000
     * @return static
3001
     *                <p>(Immutable)</p>
3002
     */
3003 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...
3004
    {
3005
        if ($recursive === true) {
3006
            $result = \array_merge_recursive($this->getArray(), $array);
3007
        } else {
3008 1
            $result = \array_merge($this->getArray(), $array);
3009
        }
3010 1
3011
        return static::create(
3012 1
            $result,
3013 1
            $this->iteratorClass,
3014 1
            false
3015 1
        );
3016 1
    }
3017 1
3018 1
    /**
3019 1
     * Merge the the current array into the $array.
3020 1
     *
3021
     * - use key,value from the new $array, also if the index is in the current array
3022 1
     *
3023 1
     * @param array $array
3024 1
     * @param bool  $recursive
3025 1
     *
3026 1
     * @return static
3027
     *                <p>(Immutable)</p>
3028 1
     */
3029 1 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...
3030
    {
3031
        if ($recursive === true) {
3032
            $result = \array_replace_recursive($array, $this->getArray());
3033
        } else {
3034
            $result = \array_replace($array, $this->getArray());
3035 1
        }
3036 1
3037 1
        return static::create(
3038 1
            $result,
3039
            $this->iteratorClass,
3040
            false
3041
        );
3042
    }
3043
3044
    /**
3045
     * Merge the current array into the new $array.
3046
     *
3047
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
3048
     * - create new indexes
3049
     *
3050
     * @param array $array
3051
     * @param bool  $recursive
3052
     *
3053 1
     * @return static
3054
     *                <p>(Immutable)</p>
3055 1
     */
3056 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...
3057 1
    {
3058 1
        if ($recursive === true) {
3059 1
            $result = \array_merge_recursive($array, $this->getArray());
3060 1
        } else {
3061
            $result = \array_merge($array, $this->getArray());
3062
        }
3063 1
3064 1
        return static::create(
3065 1
            $result,
3066 1
            $this->iteratorClass,
3067
            false
3068
        );
3069
    }
3070
3071
    /**
3072
     * @return ArrayyMeta|static
3073
     */
3074
    public static function meta()
3075
    {
3076
        return (new ArrayyMeta())->getMetaObject(static::class);
3077
    }
3078
3079
    /**
3080
     * Get the min value from an array.
3081 1
     *
3082
     * @return mixed
3083 1
     */
3084 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...
3085 1
    {
3086 1
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
3087 1
            return false;
3088 1
        }
3089
3090
        return \min($this->getArray());
3091 1
    }
3092 1
3093 1
    /**
3094 1
     * Get the most used value from the array.
3095
     *
3096
     * @return mixed
3097
     *               <p>Return null if there wasn't a element.</p>
3098
     */
3099
    public function mostUsedValue()
3100
    {
3101
        return $this->countValues()->arsort()->firstKey();
3102
    }
3103
3104
    /**
3105
     * Get the most used value from the array.
3106
     *
3107
     * @param int|null $number <p>How many values you will take?</p>
3108
     *
3109
     * @return static
3110
     *                <p>(Immutable)</p>
3111
     */
3112
    public function mostUsedValues(int $number = null): self
3113
    {
3114
        return $this->countValues()->arsort()->firstsKeys($number);
3115
    }
3116
3117
    /**
3118
     * Move an array element to a new index.
3119
     *
3120
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
3121
     *
3122
     * @param int|string $from
3123
     * @param int        $to
3124
     *
3125
     * @return static
3126 5
     *                <p>(Immutable)</p>
3127
     */
3128 5
    public function moveElement($from, $to): self
3129 5
    {
3130 5
        $array = $this->getArray();
3131 5
3132
        if ((int) $from === $from) {
3133
            $tmp = \array_splice($array, $from, 1);
3134
            \array_splice($array, (int) $to, 0, $tmp);
3135
            $output = $array;
3136
        } elseif ((string) $from === $from) {
3137
            $indexToMove = \array_search($from, \array_keys($array), true);
3138
            $itemToMove = $array[$from];
3139
            if ($indexToMove !== false) {
3140
                \array_splice($array, $indexToMove, 1);
3141 5
            }
3142
            $i = 0;
3143 5
            $output = [];
3144
            foreach ($array as $key => $item) {
3145 5
                if ($i === $to) {
3146
                    $output[$from] = $itemToMove;
3147
                }
3148
                $output[$key] = $item;
3149
                ++$i;
3150
            }
3151
        } else {
3152
            $output = [];
3153
        }
3154
3155
        return static::create(
3156
            $output,
3157 11
            $this->iteratorClass,
3158
            false
3159 11
        );
3160
    }
3161 11
3162 3
    /**
3163
     * Move an array element to the first place.
3164
     *
3165 9
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3166 8
     *       loss the keys of an indexed array.
3167
     *
3168 2
     * @param int|string $key
3169
     *
3170
     * @return static
3171 9
     *                <p>(Immutable)</p>
3172
     */
3173 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...
3174
    {
3175
        $array = $this->getArray();
3176
3177
        if ($this->offsetExists($key)) {
3178
            $tmpValue = $this->get($key);
3179
            unset($array[$key]);
3180
            $array = [$key => $tmpValue] + $array;
3181
        }
3182 10
3183
        return static::create(
3184
            $array,
3185 10
            $this->iteratorClass,
3186
            false
3187 10
        );
3188 9
    }
3189
3190 9
    /**
3191
     * Move an array element to the last place.
3192
     *
3193
     * INFO: Instead of "Arrayy->moveElement()" this method will NOT
3194
     *       loss the keys of an indexed array.
3195
     *
3196
     * @param int|string $key
3197
     *
3198 9
     * @return static
3199
     *                <p>(Immutable)</p>
3200
     */
3201 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...
3202 10
    {
3203 10
        $array = $this->getArray();
3204 10
3205 10
        if ($this->offsetExists($key)) {
3206
            $tmpValue = $this->get($key);
3207
            unset($array[$key]);
3208
            $array += [$key => $tmpValue];
3209
        }
3210
3211
        return static::create(
3212
            $array,
3213
            $this->iteratorClass,
3214
            false
3215
        );
3216
    }
3217 10
3218
    /**
3219
     * Moves the internal iterator position to the next element and returns this element.
3220 10
     *
3221
     * @return mixed
3222 10
     */
3223 9
    public function next()
3224
    {
3225 9
        return \next($this->array);
3226
    }
3227
3228
    /**
3229
     * Get a subset of the items from the given array.
3230
     *
3231
     * @param mixed[] $keys
3232 9
     *
3233 1
     * @return static
3234
     *                <p>(Immutable)</p>
3235 8
     */
3236
    public function only(array $keys): self
3237
    {
3238
        $array = $this->getArray();
3239 10
3240 10
        return static::create(
3241 10
            \array_intersect_key($array, \array_flip($keys)),
3242 10
            $this->iteratorClass,
3243
            false
3244
        );
3245
    }
3246
3247
    /**
3248
     * Pad array to the specified size with a given value.
3249
     *
3250
     * @param int   $size  <p>Size of the result array.</p>
3251
     * @param mixed $value <p>Empty value by default.</p>
3252
     *
3253
     * @return static
3254
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
3255 1
     */
3256
    public function pad(int $size, $value): self
3257 1
    {
3258
        return static::create(
3259
            \array_pad($this->getArray(), $size, $value),
3260
            $this->iteratorClass,
3261
            false
3262
        );
3263
    }
3264 1
3265 1
    /**
3266 1
     * Partitions this array in two array according to a predicate.
3267 1
     * Keys are preserved in the resulting array.
3268 1
     *
3269
     * @param \Closure $closure
3270
     *                          <p>The predicate on which to partition.</p>
3271 1
     *
3272 1
     * @return array<int, Arrayy>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

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

Loading history...
3273
     *                    <p>An array with two elements. The first element contains the array
3274
     *                    of elements where the predicate returned TRUE, the second element
3275 1
     *                    contains the array of elements where the predicate returned FALSE.</p>
3276
     */
3277
    public function partition(\Closure $closure): array
3278
    {
3279
        // init
3280
        $matches = [];
3281
        $noMatches = [];
3282
3283
        foreach ($this->array as $key => $element) {
3284
            if ($closure($key, $element)) {
3285
                $matches[$key] = $element;
3286
            } else {
3287
                $noMatches[$key] = $element;
3288 5
            }
3289
        }
3290 5
3291
        return [self::create($matches), self::create($noMatches)];
3292
    }
3293 5
3294
    /**
3295 5
     * Pop a specified value off the end of the current array.
3296
     *
3297 1
     * @return mixed
3298 1
     *               <p>(Mutable) The popped element from the current array.</p>
3299
     */
3300
    public function pop()
3301
    {
3302 5
        $this->generatorToArray();
3303
3304 5
        return \array_pop($this->array);
3305
    }
3306
3307
    /**
3308
     * Prepend a (key) + value to the current array.
3309
     *
3310
     * @param mixed $value
3311
     * @param mixed $key
3312
     *
3313
     * @return static
3314
     *                <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
3315 19
     */
3316
    public function prepend($value, $key = null): self
3317 19
    {
3318
        $this->generatorToArray();
3319 19
3320 1
        if ($this->properties !== []) {
3321 1
            $this->checkType($key, $value);
3322 1
        }
3323 1
3324
        if ($key === null) {
3325
            \array_unshift($this->array, $value);
3326
        } else {
3327 18
            $this->array = [$key => $value] + $this->array;
3328
        }
3329 13
3330
        return $this;
3331 13
    }
3332 13
3333 13
    /**
3334 13
     * Add a suffix to each key.
3335
     *
3336
     * @param mixed $suffix
3337
     *
3338 6
     * @return static
3339
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
3340 6
     */
3341 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...
3342 6
    {
3343 6
        // init
3344 6
        $result = [];
3345 6
3346 6
        foreach ($this->getGenerator() as $key => $item) {
3347
            if ($item instanceof self) {
3348
                $result[$key] = $item->prependToEachKey($suffix);
3349
            } elseif (\is_array($item) === true) {
3350
                $result[$key] = self::create(
3351
                    $item,
3352
                    $this->iteratorClass,
3353
                    false
3354
                )->prependToEachKey($suffix)
3355
                    ->toArray();
3356
            } else {
3357 4
                $result[$key . $suffix] = $item;
3358
            }
3359 4
        }
3360
3361 4
        return self::create(
3362
            $result,
3363
            $this->iteratorClass,
3364
            false
3365 4
        );
3366
    }
3367
3368
    /**
3369
     * Add a suffix to each value.
3370
     *
3371
     * @param mixed $suffix
3372
     *
3373
     * @return static
3374
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
3375
     */
3376 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...
3377
    {
3378 13
        // init
3379
        $result = [];
3380 13
3381
        foreach ($this->getGenerator() as $key => $item) {
3382 13
            if ($item instanceof self) {
3383
                $result[$key] = $item->prependToEachValue($suffix);
3384 13
            } elseif (\is_array($item) === true) {
3385 2
                $result[$key] = self::create(
3386 2
                    $item,
3387 2
                    $this->iteratorClass,
3388 2
                    false
3389 2
                )->prependToEachValue($suffix)
3390
                    ->toArray();
3391
            } elseif (\is_object($item) === true) {
3392
                $result[$key] = $item;
3393
            } else {
3394 11
                $result[$key] = $item . $suffix;
3395
            }
3396 11
        }
3397 11
3398 11
        return self::create(
3399 11
            $result,
3400
            $this->iteratorClass,
3401
            false
3402
        );
3403
    }
3404
3405
    /**
3406
     * Return the value of a given key and
3407
     * delete the key.
3408
     *
3409
     * @param int|int[]|string|string[]|null $keyOrKeys
3410
     * @param mixed                          $fallback
3411 17
     *
3412
     * @return mixed
3413 17
     */
3414
    public function pull($keyOrKeys = null, $fallback = null)
3415 17
    {
3416
        if ($keyOrKeys === null) {
3417
            $array = $this->getArray();
3418
            $this->clear();
3419
3420
            return $array;
3421
        }
3422
3423 17
        if (\is_array($keyOrKeys) === true) {
3424
            $valueOrValues = [];
3425 7
            foreach ($keyOrKeys as $key) {
3426 7
                $valueOrValues[] = $this->get($key, $fallback);
3427
                $this->offsetUnset($key);
3428 7
            }
3429
        } else {
3430
            $valueOrValues = $this->get($keyOrKeys, $fallback);
3431
            $this->offsetUnset($keyOrKeys);
3432 11
        }
3433
3434 11
        return $valueOrValues;
3435
    }
3436
3437
    /**
3438
     * Push one or more values onto the end of array at once.
3439
     *
3440
     * @param array ...$args
3441
     *
3442
     * @return static
3443 4
     *                <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
3444
     *
3445 4
     * @noinspection ReturnTypeCanBeDeclaredInspection
3446
     */
3447 4
    public function push(...$args)
3448
    {
3449
        $this->generatorToArray();
3450
3451 4
        if (
3452
            $this->checkPropertyTypes
3453
            &&
3454
            $this->properties !== []
3455
        ) {
3456
            foreach ($args as $key => $value) {
3457
                $this->checkType($key, $value);
3458
            }
3459
        }
3460
3461
        \array_push(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_push() as the parameter $array expects a reference.
Loading history...
3462 7
3463
        return $this;
3464 7
    }
3465
3466
    /**
3467
     * Get a random value from the current array.
3468
     *
3469
     * @param int|null $number <p>How many values you will take?</p>
3470
     *
3471
     * @return static
3472
     *                <p>(Immutable)</p>
3473
     */
3474
    public function randomImmutable(int $number = null): self
3475
    {
3476
        $this->generatorToArray();
3477
3478 9 View Code Duplication
        if (\count($this->array, \COUNT_NORMAL) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3479
            return static::create(
3480
                [],
3481 9
                $this->iteratorClass,
3482
                false
3483 9
            );
3484 9
        }
3485 2
3486 1 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...
3487
            /** @noinspection NonSecureArrayRandUsageInspection */
3488
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3489
3490
            return static::create(
3491 9
                $arrayRandValue,
3492
                $this->iteratorClass,
3493
                false
3494
            );
3495
        }
3496
3497
        $arrayTmp = $this->array;
3498
        /** @noinspection NonSecureShuffleUsageInspection */
3499
        \shuffle($arrayTmp);
3500
3501
        return static::create(
3502
            $arrayTmp,
3503 18
            $this->iteratorClass,
3504
            false
3505 18
        )->firstsImmutable($number);
3506 1
    }
3507
3508 1
    /**
3509 1
     * Pick a random key/index from the keys of this array.
3510
     *
3511
     * @throws \RangeException If array is empty
3512 1
     *
3513 1
     * @return mixed
3514 1
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
3515 1
     */
3516
    public function randomKey()
3517
    {
3518
        $result = $this->randomKeys(1);
3519 18
3520
        if (!isset($result[0])) {
3521 18
            $result[0] = null;
3522
        }
3523
3524 18
        return $result[0];
3525
    }
3526
3527 18
    /**
3528 18
     * Pick a given number of random keys/indexes out of this array.
3529 18
     *
3530 18
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
3531
     *
3532
     * @throws \RangeException If array is empty
3533
     *
3534
     * @return static
3535
     *                <p>(Immutable)</p>
3536
     */
3537
    public function randomKeys(int $number): self
3538
    {
3539
        $this->generatorToArray();
3540 14
3541
        $count = \count($this->array, \COUNT_NORMAL);
3542
3543 14
        if ($number === 0 || $number > $count) {
3544
            throw new \RangeException(
3545 14
                \sprintf(
3546 12
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
3547 5
                    $number,
3548
                    $count
3549 12
                )
3550
            );
3551
        }
3552
3553 14
        $result = (array) \array_rand($this->array, $number);
3554
3555 14
        return static::create(
3556
            $result,
3557 14
            $this->iteratorClass,
3558
            false
3559
        );
3560
    }
3561
3562
    /**
3563
     * Get a random value from the current array.
3564
     *
3565
     * @param int|null $number <p>How many values you will take?</p>
3566 9
     *
3567
     * @return static
3568 9
     *                <p>(Mutable)</p>
3569
     */
3570 9
    public function randomMutable(int $number = null): self
3571
    {
3572 9
        $this->generatorToArray();
3573
3574 View Code Duplication
        if (\count($this->array, \COUNT_NORMAL) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3575
            return static::create(
3576
                [],
3577
                $this->iteratorClass,
3578
                false
3579
            );
3580
        }
3581
3582 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...
3583 1
            /** @noinspection NonSecureArrayRandUsageInspection */
3584
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3585
            $this->array = $arrayRandValue;
3586 1
3587
            return $this;
3588 1
        }
3589 1
3590 1
        /** @noinspection NonSecureShuffleUsageInspection */
3591
        \shuffle($this->array);
3592
3593
        return $this->firstsMutable($number);
3594 1
    }
3595 1
3596 1
    /**
3597 1
     * Pick a random value from the values of this array.
3598
     *
3599
     * @return mixed
3600
     *               <p>Get a random value or null if there wasn't a value.</p>
3601
     */
3602
    public function randomValue()
3603
    {
3604
        $result = $this->randomImmutable();
3605
3606
        if (!isset($result[0])) {
3607
            $result[0] = null;
3608
        }
3609 18
3610
        return $result[0];
3611
    }
3612 18
3613
    /**
3614
     * Pick a given number of random values out of this array.
3615
     *
3616
     * @param int $number
3617
     *
3618
     * @return static
3619
     *                <p>(Mutable)</p>
3620
     */
3621
    public function randomValues(int $number): self
3622
    {
3623
        return $this->randomMutable($number);
3624 18
    }
3625
3626 18
    /**
3627 18
     * Get a random value from an array, with the ability to skew the results.
3628 18
     *
3629 18
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3630
     *
3631
     * @param array    $array
3632
     * @param int|null $number <p>How many values you will take?</p>
3633
     *
3634
     * @return static
3635
     *                <p>(Immutable)</p>
3636
     */
3637
    public function randomWeighted(array $array, int $number = null): self
3638
    {
3639 7
        // init
3640
        $options = [];
3641 7
3642
        foreach ($array as $option => $weight) {
3643 7
            if ($this->searchIndex($option) !== false) {
3644
                for ($i = 0; $i < $weight; ++$i) {
3645 7
                    $options[] = $option;
3646 7
                }
3647 7
            }
3648 7
        }
3649
3650
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3651
    }
3652
3653
    /**
3654
     * Reduce the current array via callable e.g. anonymous-function.
3655
     *
3656
     * @param callable $callable
3657
     * @param mixed    $init
3658 7
     *
3659
     * @return static
3660 7
     *                <p>(Immutable)</p>
3661
     */
3662 7
    public function reduce($callable, $init = []): self
3663
    {
3664 7
        if ($this->generator) {
3665 7
            $result = $init;
3666 7
3667 7
            foreach ($this->getGenerator() as $value) {
3668
                $result = $callable($result, $value);
3669
            }
3670
3671
            return static::create(
3672
                $result,
3673
                $this->iteratorClass,
3674
                false
3675
            );
3676
        }
3677
3678
        $result = \array_reduce($this->array, $callable, $init);
3679 7
3680
        if ($result === null) {
3681 7
            $this->array = [];
3682
        } else {
3683
            $this->array = (array) $result;
3684 7
        }
3685
3686 7
        return static::create(
3687 6
            $this->array,
3688 6
            $this->iteratorClass,
3689
            false
3690
        );
3691 6
    }
3692
3693
    /**
3694
     * @param bool $unique
3695 7
     *
3696 7
     * @return static
3697
     *                <p>(Immutable)</p>
3698
     */
3699 7
    public function reduce_dimension(bool $unique = true): self
3700 7
    {
3701 7
        // init
3702 7
        $result = [];
3703
3704
        foreach ($this->getGenerator() as $val) {
3705
            if (\is_array($val) === true) {
3706
                $result[] = (new static($val))->reduce_dimension($unique)->getArray();
3707
            } else {
3708
                $result[] = [$val];
3709
            }
3710
        }
3711
3712
        $result = $result === [] ? [] : \array_merge(...$result);
3713
3714 1
        $resultArrayy = new static($result);
3715
3716 1
        return $unique ? $resultArrayy->unique() : $resultArrayy;
3717 1
    }
3718
3719
    /**
3720 1
     * Create a numerically re-indexed Arrayy object.
3721 1
     *
3722 1
     * @return static
3723 1
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
3724
     */
3725
    public function reindex(): self
3726
    {
3727
        $this->generatorToArray();
3728
3729
        $this->array = \array_values($this->array);
3730
3731
        return $this;
3732
    }
3733
3734
    /**
3735
     * Return all items that fail the truth test.
3736
     *
3737 2
     * @param \Closure $closure
3738
     *
3739 2
     * @return static
3740
     *                <p>(Immutable)</p>
3741 2
     */
3742 2 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...
3743
    {
3744
        // init
3745
        $filtered = [];
3746
3747
        foreach ($this->getGenerator() as $key => $value) {
3748
            if (!$closure($value, $key)) {
3749
                $filtered[$key] = $value;
3750
            }
3751
        }
3752
3753 2
        return static::create(
3754
            $filtered,
3755 2
            $this->iteratorClass,
3756 2
            false
3757 2
        );
3758 2
    }
3759
3760
    /**
3761
     * Remove a value from the current array (optional using dot-notation).
3762
     *
3763
     * @param mixed $key
3764
     *
3765
     * @return static
3766
     *                <p>(Mutable)</p>
3767
     */
3768
    public function remove($key)
3769
    {
3770 2
        // recursive call
3771
        if (\is_array($key) === true) {
3772 2
            foreach ($key as $k) {
3773 2
                $this->internalRemove($k);
3774 2
            }
3775 2
3776
            return static::create(
3777
                $this->getArray(),
3778
                $this->iteratorClass,
3779
                false
3780
            );
3781
        }
3782
3783
        $this->internalRemove($key);
3784
3785
        return static::create(
3786
            $this->getArray(),
3787 1
            $this->iteratorClass,
3788
            false
3789 1
        );
3790 1
    }
3791
3792 1
    /**
3793 1
     * alias: for "Arrayy->count()"
3794 1
     *
3795 1
     * @param mixed $element
3796
     *
3797
     * @return static
3798
     */
3799
    public function removeElement($element)
3800
    {
3801
        return $this->removeValue($element);
3802
    }
3803
3804
    /**
3805
     * Remove the first value from the current array.
3806
     *
3807
     * @return static
3808 3
     *                <p>(Immutable)</p>
3809
     */
3810 3 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...
3811 3
    {
3812
        $tmpArray = $this->getArray();
3813 3
3814 3
        \array_shift($tmpArray);
3815
3816
        return static::create(
3817 3
            $tmpArray,
3818 3
            $this->iteratorClass,
3819 3
            false
3820 3
        );
3821
    }
3822
3823
    /**
3824
     * Remove the last value from the current array.
3825
     *
3826
     * @return static
3827
     *                <p>(Immutable)</p>
3828
     */
3829 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...
3830
    {
3831
        $tmpArray = $this->getArray();
3832
3833 1
        \array_pop($tmpArray);
3834
3835 1
        return static::create(
3836
            $tmpArray,
3837 1
            $this->iteratorClass,
3838 1
            false
3839
        );
3840
    }
3841
3842
    /**
3843
     * Removes a particular value from an array (numeric or associative).
3844
     *
3845
     * @param mixed $value
3846
     *
3847
     * @return static
3848
     *                <p>(Immutable)</p>
3849
     */
3850 15
    public function removeValue($value): self
3851
    {
3852 15
        $this->generatorToArray();
3853
3854 15
        // init
3855 15
        $isSequentialArray = $this->isSequential();
3856 15
3857 15
        foreach ($this->array as $key => $item) {
3858
            if ($item === $value) {
3859
                unset($this->array[$key]);
3860
            }
3861
        }
3862
3863
        if ($isSequentialArray) {
3864
            $this->array = \array_values($this->array);
3865
        }
3866
3867
        return static::create(
3868
            $this->array,
3869 1
            $this->iteratorClass,
3870
            false
3871 1
        );
3872
    }
3873 1
3874
    /**
3875 1
     * Generate array of repeated arrays.
3876 1
     *
3877 1
     * @param int $times <p>How many times has to be repeated.</p>
3878 1
     *
3879
     * @return static
3880
     *                <p>(Immutable)</p>
3881
     */
3882
    public function repeat($times): self
3883
    {
3884
        if ($times === 0) {
3885
            return static::create([], $this->iteratorClass);
3886
        }
3887
3888 9
        return static::create(
3889
            \array_fill(0, (int) $times, $this->getArray()),
3890 9
            $this->iteratorClass,
3891
            false
3892 9
        );
3893
    }
3894 9
3895
    /**
3896
     * Replace a key with a new key/value pair.
3897
     *
3898
     * @param mixed $replace
3899
     * @param mixed $key
3900
     * @param mixed $value
3901
     *
3902
     * @return static
3903
     *                <p>(Immutable)</p>
3904
     */
3905
    public function replace($replace, $key, $value): self
3906
    {
3907
        $that = clone $this;
3908
3909 4
        return $that->remove($replace)
3910
            ->set($key, $value);
3911 4
    }
3912
3913 4
    /**
3914
     * Create an array using the current array as values and the other array as keys.
3915 4
     *
3916
     * @param array $keys <p>An array of keys.</p>
3917
     *
3918
     * @return static
3919
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
3920
     */
3921
    public function replaceAllKeys(array $keys): self
3922
    {
3923
        return static::create(
3924
            \array_combine($keys, $this->getArray()),
3925
            $this->iteratorClass,
3926 21
            false
3927
        );
3928 21
    }
3929 20
3930 10
    /**
3931
     * Create an array using the current array as keys and the other array as values.
3932
     *
3933
     * @param array $array <p>An array o values.</p>
3934 11
     *
3935
     * @return static
3936
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3937
     */
3938
    public function replaceAllValues(array $array): self
3939
    {
3940
        return static::create(
3941
            \array_combine($this->array, $array),
3942
            $this->iteratorClass,
3943
            false
3944
        );
3945 9
    }
3946
3947 9
    /**
3948
     * Replace the keys in an array with another set.
3949
     *
3950 9
     * @param array $keys <p>An array of keys matching the array's size</p>
3951
     *
3952 9
     * @return static
3953
     *                <p>(Immutable)</p>
3954
     */
3955
    public function replaceKeys(array $keys): self
3956
    {
3957
        $values = \array_values($this->getArray());
3958
        $result = \array_combine($keys, $values);
3959
3960
        return static::create(
3961 9
            $result,
3962 1
            $this->iteratorClass,
3963
            false
3964
        );
3965 9
    }
3966 7
3967
    /**
3968
     * Replace the first matched value in an array.
3969 9
     *
3970 9
     * @param mixed $search      <p>The value to replace.</p>
3971 9
     * @param mixed $replacement <p>The value to replace.</p>
3972 9
     *
3973
     * @return static
3974
     *                <p>(Immutable)</p>
3975
     */
3976
    public function replaceOneValue($search, $replacement = ''): self
3977
    {
3978
        $array = $this->getArray();
3979
        $key = \array_search($search, $array, true);
3980
3981
        if ($key !== false) {
3982
            $array[$key] = $replacement;
3983
        }
3984
3985 18
        return static::create(
3986
            $array,
3987 18
            $this->iteratorClass,
3988
            false
3989 18
        );
3990
    }
3991 18
3992
    /**
3993
     * Replace values in the current array.
3994
     *
3995
     * @param mixed $search      <p>The value to replace.</p>
3996
     * @param mixed $replacement <p>What to replace it with.</p>
3997
     *
3998
     * @return static
3999
     *                <p>(Immutable)</p>
4000
     */
4001
    public function replaceValues($search, $replacement = ''): self
4002
    {
4003
        return $this->each(
4004
            static function ($value) use ($search, $replacement) {
4005 11
                return \str_replace($search, $replacement, $value);
4006
            }
4007 11
        );
4008
    }
4009
4010 11
    /**
4011 4
     * Get the last elements from index $from until the end of this array.
4012
     *
4013
     * @param int $from
4014 11
     *
4015
     * @return static
4016
     *                <p>(Immutable)</p>
4017
     */
4018 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...
4019
    {
4020
        $tmpArray = $this->getArray();
4021
4022
        return static::create(
4023 5
            \array_splice($tmpArray, $from),
4024
            $this->iteratorClass,
4025 5
            false
4026
        );
4027 5
    }
4028
4029
    /**
4030
     * Return the array in the reverse order.
4031
     *
4032
     * @return static
4033
     *                <p>(Mutable) Return this Arrayy object.</p>
4034
     */
4035
    public function reverse(): self
4036
    {
4037
        $this->generatorToArray();
4038
4039 2
        $this->array = \array_reverse($this->array);
4040
4041 2
        return $this;
4042 2
    }
4043
4044
    /**
4045 2
     * Sort an array in reverse order.
4046
     *
4047 2
     * @param int $sort_flags [optional] <p>
4048
     *                        You may modify the behavior of the sort using the optional
4049 1
     *                        parameter sort_flags, for details
4050 1
     *                        see sort.
4051 1
     *                        </p>
4052
     *
4053 1
     * @return static
4054
     *                <p>(Mutable) Return this Arrayy object.</p>
4055
     */
4056
    public function rsort(int $sort_flags = 0): self
4057
    {
4058 1
        $this->generatorToArray();
4059 1
4060 1
        \rsort($this->array, $sort_flags);
4061 1
4062
        return $this;
4063
    }
4064
4065
    /**
4066 1
     * Search for the first index of the current array via $value.
4067
     *
4068
     * @param mixed $value
4069 2
     *
4070
     * @return false|float|int|string
4071 2
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
4072
     */
4073
    public function searchIndex($value)
4074
    {
4075
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
4076 2
            if ($value === $valueFromArray) {
4077 2
                return $keyFromArray;
4078 2
            }
4079 2
        }
4080
4081
        return false;
4082
    }
4083
4084
    /**
4085
     * Search for the value of the current array via $index.
4086
     *
4087
     * @param mixed $index
4088
     *
4089
     * @return static
4090
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
4091
     */
4092 20
    public function searchValue($index): self
4093
    {
4094 20
        $this->generatorToArray();
4095
4096
        // init
4097
        $return = [];
4098
4099
        if ($this->array === []) {
4100
            return static::create(
4101
                [],
4102
                $this->iteratorClass,
4103
                false
4104 1
            );
4105
        }
4106
4107 1
        // php cast "bool"-index into "int"-index
4108
        if ((bool) $index === $index) {
4109 1
            $index = (int) $index;
4110 1
        }
4111 1
4112 1
        if ($this->offsetExists($index)) {
4113
            $return = [$this->array[$index]];
4114
        }
4115
4116 1
        return static::create(
4117
            $return,
4118
            $this->iteratorClass,
4119
            false
4120
        );
4121
    }
4122
4123
    /**
4124
     * Set a value for the current array (optional using dot-notation).
4125
     *
4126
     * @param string $key   <p>The key to set.</p>
4127
     * @param mixed  $value <p>Its value.</p>
4128 1
     *
4129
     * @return static
4130 1
     *                <p>(Mutable)</p>
4131 1
     */
4132 1
    public function set($key, $value): self
4133 1
    {
4134
        $this->generatorToArray();
4135
4136
        $this->internalSet($key, $value);
4137 1
4138
        return $this;
4139 1
    }
4140 1
4141 1
    /**
4142 1
     * Get a value from a array and set it if it was not.
4143
     *
4144
     * WARNING: this method only set the value, if the $key is not already set
4145
     *
4146 1
     * @param mixed $key      <p>The key</p>
4147
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
4148
     *
4149
     * @return mixed
4150
     *               <p>(Mutable)</p>
4151
     */
4152
    public function setAndGet($key, $fallback = null)
4153
    {
4154
        $this->generatorToArray();
4155
4156 1
        // If the key doesn't exist, set it.
4157
        if (!$this->has($key)) {
4158
            $this->array = $this->set($key, $fallback)->getArray();
4159 1
        }
4160
4161 1
        return $this->get($key);
4162 1
    }
4163 1
4164 1
    /**
4165
     * Shifts a specified value off the beginning of array.
4166
     *
4167
     * @return mixed
4168 1
     *               <p>(Mutable) A shifted element from the current array.</p>
4169
     */
4170
    public function shift()
4171
    {
4172
        $this->generatorToArray();
4173
4174
        return \array_shift($this->array);
4175
    }
4176
4177
    /**
4178 1
     * Shuffle the current array.
4179
     *
4180
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
4181 1
     * @param array $array  [optional]
4182
     *
4183 1
     * @return static
4184 1
     *                <p>(Immutable)</p>
4185 1
     */
4186 1
    public function shuffle(bool $secure = false, array $array = null): self
4187
    {
4188
        if ($array === null) {
4189
            $array = $this->getArray();
4190 1
        }
4191
4192
        if ($secure !== true) {
4193
            /** @noinspection NonSecureShuffleUsageInspection */
4194
            \shuffle($array);
4195
        } else {
4196
            $size = \count($array, \COUNT_NORMAL);
4197
            $keys = \array_keys($array);
4198
            for ($i = $size - 1; $i > 0; --$i) {
4199
                try {
4200
                    $r = \random_int(0, $i);
4201
                } catch (\Exception $e) {
4202
                    /** @noinspection RandomApiMigrationInspection */
4203
                    $r = \mt_rand(0, $i);
4204
                }
4205
                if ($r !== $i) {
4206
                    $temp = $array[$keys[$r]];
4207
                    $array[$keys[$r]] = $array[$keys[$i]];
4208
                    $array[$keys[$i]] = $temp;
4209
                }
4210
            }
4211
4212
            // reset indices
4213
            $array = \array_values($array);
4214
        }
4215
4216
        foreach ($array as $key => $value) {
4217
            // check if recursive is needed
4218
            if (\is_array($value) === true) {
4219
                $array[$key] = $this->shuffle($secure, $value);
4220
            }
4221
        }
4222 10
4223
        return static::create(
4224 10
            $array,
4225
            $this->iteratorClass,
4226
            false
4227
        );
4228
    }
4229
4230
    /**
4231
     * Count the values from the current array.
4232
     *
4233
     * alias: for "Arrayy->count()"
4234
     *
4235
     * @param int $mode
4236
     *
4237 5
     * @return int
4238
     */
4239 5
    public function size(int $mode = \COUNT_NORMAL): int
4240 5
    {
4241 5
        return $this->count($mode);
4242 5
    }
4243 5
4244 5
    /**
4245
     * Checks whether array has exactly $size items.
4246 5
     *
4247 5
     * @param int $size
4248
     *
4249
     * @return bool
4250
     */
4251 View Code Duplication
    public function sizeIs(int $size): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4252
    {
4253
        // init
4254
        $itemsTempCount = 0;
4255
4256
        foreach ($this->getGenerator() as $key => $value) {
4257
            ++$itemsTempCount;
4258
            if ($itemsTempCount > $size) {
4259
                return false;
4260
            }
4261
        }
4262 20
4263
        return $itemsTempCount === $size;
4264 20
    }
4265
4266 20
    /**
4267 20
     * Checks whether array has between $fromSize to $toSize items. $toSize can be
4268 20
     * smaller than $fromSize.
4269 20
     *
4270 20
     * @param int $fromSize
4271
     * @param int $toSize
4272
     *
4273
     * @return bool
4274
     */
4275
    public function sizeIsBetween(int $fromSize, int $toSize): bool
4276
    {
4277
        if ($fromSize > $toSize) {
4278
            $tmp = $toSize;
4279
            $toSize = $fromSize;
4280
            $fromSize = $tmp;
4281
        }
4282
4283
        // init
4284
        $itemsTempCount = 0;
4285
4286
        foreach ($this->getGenerator() as $key => $value) {
4287 18
            ++$itemsTempCount;
4288
            if ($itemsTempCount > $toSize) {
4289 18
                return false;
4290
            }
4291 18
        }
4292
4293 18
        return $fromSize < $itemsTempCount && $itemsTempCount < $toSize;
4294
    }
4295
4296
    /**
4297
     * Checks whether array has more than $size items.
4298
     *
4299
     * @param int $size
4300
     *
4301
     * @return bool
4302
     */
4303 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...
4304
    {
4305
        // init
4306 1
        $itemsTempCount = 0;
4307
4308 1
        foreach ($this->getGenerator() as $key => $value) {
4309
            ++$itemsTempCount;
4310
            if ($itemsTempCount > $size) {
4311
                return true;
4312
            }
4313
        }
4314
4315
        return $itemsTempCount > $size;
4316
    }
4317
4318
    /**
4319
     * Checks whether array has less than $size items.
4320
     *
4321 1
     * @param int $size
4322
     *
4323 1
     * @return bool
4324
     */
4325 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...
4326
    {
4327
        // init
4328
        $itemsTempCount = 0;
4329
4330
        foreach ($this->getGenerator() as $key => $value) {
4331
            ++$itemsTempCount;
4332
            if ($itemsTempCount > $size) {
4333
                return false;
4334
            }
4335
        }
4336
4337
        return $itemsTempCount < $size;
4338
    }
4339
4340
    /**
4341 1
     * Counts all elements in an array, or something in an object.
4342
     *
4343 1
     * <p>
4344 1
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
4345
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
4346
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
4347 1
     * implemented and used in PHP.
4348 1
     * </p>
4349 1
     *
4350 1
     * @return int
4351 1
     *             <p>
4352
     *             The number of elements in var, which is
4353
     *             typically an array, since anything else will have one
4354 1
     *             element.
4355
     *             </p>
4356 1
     *             <p>
4357 1
     *             If var is not an array or an object with
4358
     *             implemented Countable interface,
4359
     *             1 will be returned.
4360 1
     *             There is one exception, if var is &null;,
4361 1
     *             0 will be returned.
4362
     *             </p>
4363
     *             <p>
4364 1
     *             Caution: count may return 0 for a variable that isn't set,
4365
     *             but it may also return 0 for a variable that has been initialized with an
4366 1
     *             empty array. Use isset to test if a variable is set.
4367
     *             </p>
4368
     */
4369
    public function sizeRecursive(): int
4370 1
    {
4371
        return \count($this->getArray(), \COUNT_RECURSIVE);
4372 1
    }
4373 1
4374 1
    /**
4375 1
     * Extract a slice of the array.
4376
     *
4377
     * @param int      $offset       <p>Slice begin index.</p>
4378
     * @param int|null $length       <p>Length of the slice.</p>
4379
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
4380
     *
4381
     * @return static
4382
     *                <p>A slice of the original array with length $length.</p>
4383
     */
4384
    public function slice(int $offset, int $length = null, bool $preserveKeys = false)
4385
    {
4386
        return static::create(
4387
            \array_slice(
4388 1
                $this->getArray(),
4389
                $offset,
4390 1
                $length,
4391
                $preserveKeys
4392 1
            ),
4393
            $this->iteratorClass,
4394 1
            false
4395 1
        );
4396
    }
4397 1
4398 1
    /**
4399
     * Sort the current array and optional you can keep the keys.
4400
     *
4401 1
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4402 1
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
4403 1
     *                              <strong>SORT_NATURAL</strong></p>
4404 1
     * @param bool       $keepKeys
4405
     *
4406
     * @return static
4407
     *                <p>(Mutable) Return this Arrayy object.</p>
4408
     */
4409
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4410
    {
4411
        $this->generatorToArray();
4412
4413
        return $this->sorting(
4414 1
            $this->array,
4415
            $direction,
4416 1
            $strategy,
4417
            $keepKeys
4418 1
        );
4419 1
    }
4420
4421
    /**
4422 1
     * Sort the current array by key.
4423 1
     *
4424
     * @see http://php.net/manual/en/function.ksort.php
4425
     * @see http://php.net/manual/en/function.krsort.php
4426
     *
4427
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4428
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4429
     *                              <strong>SORT_NATURAL</strong></p>
4430
     *
4431
     * @return static
4432
     *                <p>(Mutable) Return this Arrayy object.</p>
4433
     */
4434
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4435
    {
4436 1
        $this->generatorToArray();
4437
4438 1
        $this->sorterKeys($this->array, $direction, $strategy);
4439
4440 1
        return $this;
4441
    }
4442 1
4443 1
    /**
4444 1
     * Sort the current array by value.
4445 1
     *
4446
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4447
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4448
     *                              <strong>SORT_NATURAL</strong></p>
4449
     *
4450
     * @return static
4451
     *                <p>(Mutable)</p>
4452
     */
4453
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4454
    {
4455
        return $this->sort($direction, $strategy, true);
4456 236
    }
4457
4458 236
    /**
4459
     * Sort the current array by value.
4460
     *
4461
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4462
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4463
     *                              <strong>SORT_NATURAL</strong></p>
4464
     *
4465
     * @return static
4466
     *                <p>(Mutable)</p>
4467
     */
4468
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4469 7
    {
4470
        return $this->sort($direction, $strategy, false);
4471 7
    }
4472 7
4473
    /**
4474
     * Sort a array by value, by a closure or by a property.
4475
     *
4476 7
     * - If the sorter is null, the array is sorted naturally.
4477
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
4478
     *
4479
     * @param callable|string|null $sorter
4480
     * @param int|string           $direction <p>use <strong>SORT_ASC</strong> (default) or
4481
     *                                        <strong>SORT_DESC</strong></p>
4482
     * @param int                  $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4483
     *                                        <strong>SORT_NATURAL</strong></p>
4484
     *
4485
     * @return static
4486
     *                <p>(Immutable)</p>
4487 19
     */
4488
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4489 19
    {
4490
        $array = $this->getArray();
4491
        $direction = $this->getDirection($direction);
4492
4493
        // Transform all values into their results.
4494
        if ($sorter) {
4495
            $arrayy = static::create(
4496
                $array,
4497
                $this->iteratorClass,
4498 13
                false
4499
            );
4500
4501
            $results = $arrayy->each(
4502 13
                function ($value) use ($sorter) {
4503
                    if (\is_callable($sorter) === true) {
4504 12
                        return $sorter($value);
4505 12
                    }
4506
4507
                    return $this->get($sorter);
4508 12
                }
4509 13
            );
4510 13
4511 13
            $results = $results->getArray();
4512 13
        } else {
4513
            $results = $array;
4514 13
        }
4515
4516
        // Sort by the results and replace by original values
4517
        \array_multisort($results, $direction, $strategy, $array);
4518
4519
        return static::create(
4520
            $array,
4521
            $this->iteratorClass,
4522
            false
4523 11
        );
4524
    }
4525
4526
    /**
4527
     * @param int      $offset
4528 11
     * @param int|null $length
4529
     * @param array    $replacement
4530 11
     *
4531 11
     * @return static
4532
     *                <p>(Immutable)</p>
4533 10
     */
4534 10
    public function splice(int $offset, int $length = null, $replacement = []): self
4535
    {
4536
        $tmpArray = $this->getArray();
4537 10
4538 11
        \array_splice($tmpArray, $offset, $length ?? $this->count(), $replacement);
4539 11
4540
        return static::create(
4541 11
            $tmpArray,
4542
            $this->iteratorClass,
4543 11
            false
4544
        );
4545
    }
4546 11
4547
    /**
4548
     * Split an array in the given amount of pieces.
4549 11
     *
4550
     * @param int  $numberOfPieces
4551
     * @param bool $keepKeys
4552
     *
4553
     * @return static
4554
     *                <p>(Immutable)</p>
4555
     */
4556
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
4557
    {
4558
        $this->generatorToArray();
4559
4560 10
        $arrayCount = \count($this->array, \COUNT_NORMAL);
4561
4562 10
        if ($arrayCount === 0) {
4563
            $result = [];
4564
        } else {
4565
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
4566
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
4567
        }
4568
4569
        return static::create(
4570
            $result,
4571
            $this->iteratorClass,
4572
            false
4573 4
        );
4574
    }
4575 4
4576
    /**
4577 4
     * Stripe all empty items.
4578
     *
4579 4
     * @return static
4580
     *                <p>(Immutable)</p>
4581
     */
4582
    public function stripEmpty(): self
4583
    {
4584
        return $this->filter(
4585
            static function ($item) {
4586
                if ($item === null) {
4587
                    return false;
4588 2
                }
4589
4590 2
                return (bool) \trim((string) $item);
4591
            }
4592
        );
4593 2
    }
4594 2
4595
    /**
4596 2
     * Swap two values between positions by key.
4597 2
     *
4598 2
     * @param int|string $swapA <p>a key in the array</p>
4599
     * @param int|string $swapB <p>a key in the array</p>
4600
     *
4601
     * @return static
4602
     *                <p>(Immutable)</p>
4603
     */
4604
    public function swap($swapA, $swapB): self
4605
    {
4606
        $array = $this->getArray();
4607
4608
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
4609
4610
        return static::create(
4611 12
            $array,
4612
            $this->iteratorClass,
4613 12
            false
4614
        );
4615 12
    }
4616 6
4617
    /**
4618 6
     * alias: for "Arrayy->getArray()"
4619
     *
4620
     * @param bool $convertAllArrayyElements
4621 12
     *
4622
     * @return array
4623
     *
4624
     * @see Arrayy::getArray()
4625
     */
4626
    public function toArray(bool $convertAllArrayyElements = false): array
4627
    {
4628 1048
        return $this->getArray($convertAllArrayyElements);
4629
    }
4630 1048
4631
    /**
4632 1048
     * Convert the current array to JSON.
4633
     *
4634 1048
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
4635 73
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
4636 73
     *
4637 73
     * @return string
4638 73
     */
4639 73
    public function toJson(int $options = 0, int $depth = 512): string
4640
    {
4641
        $return = \json_encode($this->getArray(), $options, $depth);
4642
        if ($return === false) {
4643
            return '';
4644 985
        }
4645
4646 985
        return $return;
4647
    }
4648 16
4649
    /**
4650
     * Implodes array to a string with specified separator.
4651
     *
4652 985
     * @param string $separator [optional] <p>The element's separator.</p>
4653
     *
4654 985
     * @return string
4655
     *                <p>The string representation of array, separated by ",".</p>
4656 985
     */
4657
    public function toString(string $separator = ','): string
4658 1
    {
4659
        return $this->implode($separator);
4660
    }
4661 984
4662 854
    /**
4663 854
     * Return a duplicate free copy of the current array.
4664 854
     *
4665 854
     * @return static
4666
     *                <p>(Mutable)</p>
4667
     */
4668
    public function unique(): self
4669 1041
    {
4670
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
4671
4672
        $this->array = $this->reduce(
4673
            static function ($resultArray, $value) {
4674
                if (!\in_array($value, $resultArray, true)) {
4675
                    $resultArray[] = $value;
4676
                }
4677
4678 4
                return $resultArray;
4679
            },
4680
            []
4681 4
        )->getArray();
4682
        $this->generator = null;
4683 4
4684 1
        return $this;
4685
    }
4686
4687 3
    /**
4688 3
     * Return a duplicate free copy of the current array. (with the old keys)
4689 1
     *
4690
     * @return static
4691 3
     *                <p>(Mutable)</p>
4692
     */
4693
    public function uniqueKeepIndex(): self
4694
    {
4695 3
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
4696
4697
        // init
4698
        $array = $this->getArray();
4699
4700
        $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...
4701
            \array_keys($array),
4702
            static function ($resultArray, $key) use ($array) {
4703
                if (!\in_array($array[$key], $resultArray, true)) {
4704
                    $resultArray[$key] = $array[$key];
4705
                }
4706
4707
                return $resultArray;
4708
            },
4709
            []
4710
        );
4711
        $this->generator = null;
4712
4713 11
        if ($this->array === null) {
4714
            $this->array = [];
4715
        } else {
4716
            $this->array = (array) $this->array;
4717
        }
4718
4719 11
        return $this;
4720 11
    }
4721
4722 11
    /**
4723 4
     * alias: for "Arrayy->unique()"
4724
     *
4725
     * @return static
4726 11
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
4727 11
     *
4728 11
     * @see Arrayy::unique()
4729
     */
4730
    public function uniqueNewIndex(): self
4731 11
    {
4732 4
        return $this->unique();
4733
    }
4734
4735
    /**
4736 1
     * Prepends one or more values to the beginning of array at once.
4737
     *
4738 1
     * @param array ...$args
4739
     *
4740
     * @return static
4741 1
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
4742
     */
4743 1
    public function unshift(...$args): self
4744
    {
4745 1
        $this->generatorToArray();
4746
4747
        \array_unshift(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_unshift() as the parameter $array expects a reference.
Loading history...
4748
4749 1
        return $this;
4750
    }
4751 1
4752
    /**
4753 1
     * Get all values from a array.
4754
     *
4755
     * @return static
4756
     *                <p>(Immutable)</p>
4757 1
     */
4758
    public function values(): self
4759 1
    {
4760
        return static::create(
4761
            function () {
4762 1
                /** @noinspection YieldFromCanBeUsedInspection */
4763
                foreach ($this->getGenerator() as $value) {
4764
                    yield $value;
4765
                }
4766 1
            },
4767 1
            $this->iteratorClass,
4768
            false
4769
        );
4770
    }
4771
4772 11
    /**
4773
     * Apply the given function to every element in the array, discarding the results.
4774
     *
4775
     * @param callable $callable
4776
     * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
4777
     *
4778
     * @return static
4779
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
4780 4
     */
4781
    public function walk($callable, bool $recursive = false): self
4782 4
    {
4783
        $this->generatorToArray();
4784 4
4785 4
        if ($recursive === true) {
4786
            \array_walk_recursive($this->array, $callable);
4787
        } else {
4788 4
            \array_walk($this->array, $callable);
4789 4
        }
4790
4791
        return $this;
4792
    }
4793 4
4794
    /**
4795 4
     * Convert an array into a object.
4796
     *
4797
     * @param array $array PHP array
4798
     *
4799 4
     * @return \stdClass
4800 1
     */
4801 1
    protected static function arrayToObject(array $array = []): \stdClass
4802 1
    {
4803 1
        // init
4804
        $object = new \stdClass();
4805
4806 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
4807
            return $object;
4808 4
        }
4809
4810
        foreach ($array as $name => $value) {
4811
            if (\is_array($value) === true) {
4812
                $object->{$name} = self::arrayToObject($value);
4813
            } else {
4814
                $object->{$name} = $value;
4815
            }
4816
        }
4817
4818
        return $object;
4819
    }
4820
4821
    /**
4822
     * @param array|\Generator|null $input         <p>
4823
     *                                             An array containing keys to return.
4824
     *                                             </p>
4825
     * @param mixed|null            $search_values [optional] <p>
4826
     *                                             If specified, then only keys containing these values are returned.
4827 1050
     *                                             </p>
4828
     * @param bool                  $strict        [optional] <p>
4829 1050
     *                                             Determines if strict comparison (===) should be used during the
4830
     *                                             search.
4831 1050
     *                                             </p>
4832 2
     *
4833
     * @return array
4834
     *               <p>an array of all the keys in input</p>
4835 1048
     */
4836
    protected function array_keys_recursive(
4837
        $input = null,
4838
        $search_values = null,
4839
        bool $strict = true
4840
    ): array {
4841
        // init
4842
        $keys = [];
4843
        $keysTmp = [];
4844
4845 39
        if ($input === null) {
4846
            $input = $this->getGenerator();
4847 39
        }
4848 10
4849
        if ($search_values === null) {
4850 10
            foreach ($input as $key => $value) {
4851 2
                $keys[] = $key;
4852
4853 8
                // check if recursive is needed
4854
                if (\is_array($value) === true) {
4855
                    $keysTmp[] = $this->array_keys_recursive($value);
4856
                }
4857
            }
4858 39
        } else {
4859
            $is_array_tmp = \is_array($search_values);
4860 39
4861
            foreach ($input as $key => $value) {
4862 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...
4863
                    (
4864
                        $is_array_tmp === false
4865 39
                        &&
4866
                        $strict === true
4867
                        &&
4868
                        $search_values === $value
4869
                    )
4870
                    ||
4871
                    (
4872
                        $is_array_tmp === false
4873
                        &&
4874
                        $strict === false
4875 36
                        &&
4876
                        $search_values == $value
4877 36
                    )
4878 1
                    ||
4879
                    (
4880
                        $is_array_tmp === true
4881 36
                        &&
4882 36
                        \in_array($value, $search_values, $strict)
4883 36
                    )
4884
                ) {
4885 36
                    $keys[] = $key;
4886 36
                }
4887 36
4888 36
                // check if recursive is needed
4889 36
                if (\is_array($value) === true) {
4890 36
                    $keysTmp[] = $this->array_keys_recursive($value);
4891
                }
4892
            }
4893
        }
4894
4895
        return $keysTmp === [] ? $keys : \array_merge($keys, ...$keysTmp);
4896 36
    }
4897
4898 36
    /**
4899
     * @param mixed      $path
4900 32
     * @param callable   $callable
4901
     * @param array|null $currentOffset
4902
     *
4903 8
     * @return void
4904
     */
4905
    protected function callAtPath($path, $callable, &$currentOffset = null)
4906
    {
4907
        $this->generatorToArray();
4908
4909
        if ($currentOffset === null) {
4910
            $currentOffset = &$this->array;
4911
        }
4912
4913
        $explodedPath = \explode($this->pathSeparator, $path);
4914
        if ($explodedPath === false) {
4915
            return;
4916
        }
4917
4918
        $nextPath = \array_shift($explodedPath);
4919
4920
        if (!isset($currentOffset[$nextPath])) {
4921
            return;
4922
        }
4923
4924
        if (!empty($explodedPath)) {
4925
            $this->callAtPath(
4926
                \implode($this->pathSeparator, $explodedPath),
4927 18
                $callable,
4928
                $currentOffset[$nextPath]
4929 18
            );
4930
        } else {
4931
            $callable($currentOffset[$nextPath]);
4932
        }
4933 18
    }
4934 14
4935 3
    /**
4936
     * create a fallback for array
4937
     *
4938 14
     * 1. use the current array, if it's a array
4939 14
     * 2. fallback to empty array, if there is nothing
4940
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
4941
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
4942
     * 5. call "__toArray()" on object, if the method exists
4943
     * 6. cast a string or object with "__toString()" into an array
4944
     * 7. throw a "InvalidArgumentException"-Exception
4945 14
     *
4946 10
     * @param mixed $data
4947
     *
4948
     * @throws \InvalidArgumentException
4949
     *
4950 8
     * @return array
4951
     */
4952
    protected function fallbackForArray(&$data): array
4953
    {
4954
        $data = $this->internalGetArray($data);
4955
4956
        if ($data === null) {
4957
            throw new \InvalidArgumentException('Passed value should be a array');
4958 1050
        }
4959
4960 1050
        return $data;
4961 1047
    }
4962
4963
    /**
4964 51
     * @return bool
4965 6
     *
4966
     * @noinspection ReturnTypeCanBeDeclaredInspection
4967
     */
4968 50
    protected function generatorToArray()
4969 45
    {
4970 4
        if ($this->generator) {
4971
            $this->array = $this->getArray();
4972
            $this->generator = null;
4973 42
4974
            return true;
4975
        }
4976
4977 42
        return false;
4978
    }
4979
4980
    /**
4981 42
     * Get correct PHP constant for direction.
4982
     *
4983
     * @param int|string $direction
4984
     *
4985 42
     * @return int
4986
     */
4987
    protected function getDirection($direction): int
4988
    {
4989 42
        if ((string) $direction === $direction) {
4990
            $direction = \strtolower($direction);
4991
4992
            if ($direction === 'desc') {
4993
                $direction = \SORT_DESC;
4994 47
            } else {
4995 40
                $direction = \SORT_ASC;
4996
            }
4997 40
        }
4998
4999
        if (
5000 9
            $direction !== \SORT_DESC
5001 7
            &&
5002
            $direction !== \SORT_ASC
5003
        ) {
5004 2
            $direction = \SORT_ASC;
5005
        }
5006
5007
        return $direction;
5008
    }
5009
5010
    /**
5011
     * @return TypeCheckPhpDoc[]
5012
     *
5013
     * @noinspection ReturnTypeCanBeDeclaredInspection
5014 18
     */
5015
    protected function getPropertiesFromPhpDoc()
5016 18
    {
5017
        static $PROPERTY_CACHE = [];
5018
        $cacheKey = 'Class::' . static::class;
5019 18
5020
        if (isset($PROPERTY_CACHE[$cacheKey])) {
5021 18
            return $PROPERTY_CACHE[$cacheKey];
5022
        }
5023 18
5024
        // init
5025
        $properties = [];
5026
5027
        $reflector = new \ReflectionClass($this);
5028
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
5029
        $docComment = $reflector->getDocComment();
5030
        if ($docComment) {
5031
            $docblock = $factory->create($docComment);
5032
            /** @var \phpDocumentor\Reflection\DocBlock\Tags\Property $tag */
5033
            foreach ($docblock->getTagsByName('property') as $tag) {
5034
                $properties[$tag->getVariableName()] = TypeCheckPhpDoc::fromPhpDocumentorProperty($tag);
5035
            }
5036
        }
5037
5038
        return $PROPERTY_CACHE[$cacheKey] = $properties;
5039
    }
5040
5041
    /**
5042
     * @param mixed $glue
5043 18
     * @param mixed $pieces
5044
     * @param bool  $useKeys
5045 18
     *
5046
     * @return string
5047
     */
5048
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
5049
    {
5050
        if ($pieces instanceof self) {
5051
            $pieces = $pieces->getArray();
5052
        }
5053
5054
        if (\is_array($pieces) === true) {
5055
            $pieces_count = \count($pieces, \COUNT_NORMAL);
5056
            $pieces_count_not_zero = $pieces_count > 0;
5057 924
5058
            return \implode(
5059
                $glue,
5060 924
                \array_map(
5061
                    [$this, 'implode_recursive'],
5062 924
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
5063
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
5064 82
                )
5065
            );
5066
        }
5067 922
5068
        if (
5069
            \is_scalar($pieces) === true
5070
            ||
5071 922
            (\is_object($pieces) && \method_exists($pieces, '__toString'))
5072
        ) {
5073 922
            return (string) $pieces;
5074
        }
5075
5076 922
        return '';
5077
    }
5078 922
5079
    /**
5080 922
     * @param mixed                 $needle   <p>
5081
     *                                        The searched value.
5082 3
     *                                        </p>
5083
     *                                        <p>
5084 3
     *                                        If needle is a string, the comparison is done
5085
     *                                        in a case-sensitive manner.
5086 3
     *                                        </p>
5087 3
     * @param array|\Generator|null $haystack <p>
5088
     *                                        The array.
5089 3
     *                                        </p>
5090
     * @param bool                  $strict   [optional] <p>
5091
     *                                        If the third parameter strict is set to true
5092 3
     *                                        then the in_array function will also check the
5093
     *                                        types of the
5094
     *                                        needle in the haystack.
5095
     *                                        </p>
5096 922
     *
5097
     * @return bool
5098 922
     *              <p>true if needle is found in the array, false otherwise</p>
5099
     */
5100
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
5101
    {
5102
        if ($haystack === null) {
5103
            $haystack = $this->getGenerator();
5104
        }
5105
5106
        foreach ($haystack as $item) {
5107
            if (\is_array($item) === true) {
5108 5
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
5109
            } else {
5110 5
                /** @noinspection NestedPositiveIfStatementsInspection */
5111 4
                if ($strict === true) {
5112
                    $returnTmp = $item === $needle;
5113
                } else {
5114 5
                    $returnTmp = $item == $needle;
5115 5
                }
5116
            }
5117
5118 5
            if ($returnTmp === true) {
5119
                return true;
5120
            }
5121
        }
5122
5123
        return false;
5124
    }
5125
5126
    /**
5127
     * @param mixed $data
5128
     *
5129
     * @return array|null
5130
     */
5131
    protected function internalGetArray(&$data)
5132 18
    {
5133
        if (\is_array($data) === true) {
5134 18
            return $data;
5135
        }
5136 18
5137 18
        if (!$data) {
5138
            return [];
5139 6
        }
5140
5141 6
        if (\is_object($data) === true) {
5142 13
            if ($data instanceof \ArrayObject) {
5143 13
                return $data->getArrayCopy();
5144
            }
5145 13
5146
            if ($data instanceof \Generator) {
5147
                return static::createFromGeneratorImmutable($data)->getArray();
5148 18
            }
5149
5150
            if ($data instanceof \Traversable) {
5151
                return static::createFromObject($data)->getArray();
5152
            }
5153
5154
            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...
5155
                return (array) $data->jsonSerialize();
5156
            }
5157
5158
            if (\method_exists($data, '__toArray')) {
5159
                return (array) $data->__toArray();
5160
            }
5161 20
5162
            if (\method_exists($data, '__toString')) {
5163 20
                return [(string) $data];
5164
            }
5165 20
        }
5166 20
5167
        if (\is_callable($data)) {
5168
            $this->generator = new ArrayyRewindableGenerator($data);
5169 20
5170 20
            return [];
5171
        }
5172 9
5173 5
        if (\is_scalar($data)) {
5174
            return [$data];
5175 4
        }
5176
5177
        return null;
5178 9
    }
5179 11
5180 11
    /**
5181
     * Internal mechanics of remove method.
5182 11
     *
5183 4
     * @param mixed $key
5184
     *
5185 7
     * @return bool
5186
     */
5187
    protected function internalRemove($key): bool
5188
    {
5189 20
        $this->generatorToArray();
5190
5191
        if (
5192
            $this->pathSeparator
5193
            &&
5194
            (string) $key === $key
5195
            &&
5196
            \strpos($key, $this->pathSeparator) !== false
5197 16
        ) {
5198
            $path = \explode($this->pathSeparator, (string) $key);
5199 16
5200 16
            if ($path !== false) {
5201
                // crawl though the keys
5202 16
                while (\count($path, \COUNT_NORMAL) > 1) {
5203 15
                    $key = \array_shift($path);
5204
5205
                    if (!$this->has($key)) {
5206
                        return false;
5207 2
                    }
5208
5209 2
                    $this->array = &$this->array[$key];
5210 2
                }
5211 2
5212 2
                $key = \array_shift($path);
5213 2
            }
5214
        }
5215 2
5216 2
        unset($this->array[$key]);
5217
5218
        return true;
5219
    }
5220 2
5221
    /**
5222
     * Internal mechanic of set method.
5223
     *
5224
     * @param int|string|null $key
5225
     * @param mixed           $value
5226
     * @param bool            $checkProperties
5227
     *
5228 967
     * @return bool
5229
     */
5230 967
    protected function internalSet(
5231 2
        $key,
5232 2
        &$value,
5233
        $checkProperties = true
5234 2
    ): bool {
5235
        if (
5236
            $checkProperties === true
5237 967
            &&
5238
            $this->properties !== []
5239
        ) {
5240
            $this->checkType($key, $value);
5241
        }
5242
5243
        if ($key === null) {
5244 82
            return false;
5245
        }
5246
5247 82
        $this->generatorToArray();
5248
5249 82
        $array = &$this->array;
5250
5251
        if (
5252
            $this->pathSeparator
5253
            &&
5254 82
            (string) $key === $key
5255 71
            &&
5256 17
            \strpos($key, $this->pathSeparator) !== false
5257 17
        ) {
5258
            $path = \explode($this->pathSeparator, (string) $key);
5259 80
5260
            if ($path !== false) {
5261
                // crawl through the keys
5262
                while (\count($path, \COUNT_NORMAL) > 1) {
5263
                    $key = \array_shift($path);
5264
5265
                    $array = &$array[$key];
5266
                }
5267
5268
                $key = \array_shift($path);
5269
            }
5270
        }
5271
5272
        $array[$key] = $value;
5273
5274
        return true;
5275
    }
5276
5277
    /**
5278
     * Convert a object into an array.
5279
     *
5280
     * @param object $object
5281
     *
5282
     * @return mixed
5283
     */
5284
    protected static function objectToArray($object)
5285
    {
5286
        if (!\is_object($object)) {
5287
            return $object;
5288
        }
5289
5290
        if (\is_object($object)) {
5291
            $object = \get_object_vars($object);
5292
        }
5293
5294
        return \array_map(['static', 'objectToArray'], $object);
5295
    }
5296
5297
    /**
5298
     * @param array $data
5299
     * @param bool  $checkPropertiesInConstructor
5300
     *
5301
     * @return void
5302
     */
5303
    protected function setInitialValuesAndProperties(array &$data, bool $checkPropertiesInConstructor)
5304
    {
5305
        $checkPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
5306
                                        &&
5307
                                        $checkPropertiesInConstructor === true;
5308
5309
        if ($this->properties !== []) {
5310
            foreach ($data as $key => &$valueInner) {
5311
                $this->internalSet(
5312
                    $key,
5313
                    $valueInner,
5314
                    $checkPropertiesInConstructor
5315
                );
5316
            }
5317
        } else {
5318
            if (
5319
                $this->checkPropertyTypes === true
5320
                ||
5321
                $checkPropertiesInConstructor === true
5322
            ) {
5323
                $this->properties = $this->getPropertiesFromPhpDoc();
5324
            }
5325
5326
            if (
5327
                $this->checkPropertiesMismatchInConstructor === true
5328
                &&
5329
                \count($data) !== 0
5330
                &&
5331
                \count(\array_diff_key($this->properties, $data)) > 0
5332
            ) {
5333
                throw new \TypeError('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($this->properties), true));
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'Property mismatch - inp...his->properties), true).

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

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

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

Loading history...
5334
            }
5335
5336
            foreach ($data as $key => &$valueInner) {
5337
                $this->internalSet(
5338
                    $key,
5339
                    $valueInner,
5340
                    $checkPropertiesInConstructor
5341
                );
5342
            }
5343
        }
5344
    }
5345
5346
    /**
5347
     * sorting keys
5348
     *
5349
     * @param array      $elements
5350
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5351
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5352
     *                              <strong>SORT_NATURAL</strong></p>
5353
     *
5354
     * @return static
5355
     *                <p>(Mutable) Return this Arrayy object.</p>
5356
     */
5357
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
5358
    {
5359
        $direction = $this->getDirection($direction);
5360
5361
        switch ($direction) {
5362
            case 'desc':
5363
            case \SORT_DESC:
5364
                \krsort($elements, $strategy);
5365
5366
                break;
5367
            case 'asc':
5368
            case \SORT_ASC:
5369
            default:
5370
                \ksort($elements, $strategy);
5371
        }
5372
5373
        return $this;
5374
    }
5375
5376
    /**
5377
     * @param array      $elements  <p>Warning: used as reference</p>
5378
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
5379
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
5380
     *                              <strong>SORT_NATURAL</strong></p>
5381
     * @param bool       $keepKeys
5382
     *
5383
     * @return static
5384
     *                <p>(Mutable) Return this Arrayy object.</p>
5385
     */
5386
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
5387
    {
5388
        $direction = $this->getDirection($direction);
5389
5390
        if (!$strategy) {
5391
            $strategy = \SORT_REGULAR;
5392
        }
5393
5394
        switch ($direction) {
5395
            case 'desc':
5396
            case \SORT_DESC:
5397
                if ($keepKeys) {
5398
                    \arsort($elements, $strategy);
5399
                } else {
5400
                    \rsort($elements, $strategy);
5401
                }
5402
5403
                break;
5404
            case 'asc':
5405
            case \SORT_ASC:
5406
            default:
5407
                if ($keepKeys) {
5408
                    \asort($elements, $strategy);
5409
                } else {
5410
                    \sort($elements, $strategy);
5411
                }
5412
        }
5413
5414
        return $this;
5415
    }
5416
5417
    /**
5418
     * @param int|string|null $key
5419
     * @param mixed           $value
5420
     *
5421
     * @return void
5422
     */
5423
    private function checkType($key, $value)
5424
    {
5425
        if (
5426
            isset($this->properties[$key]) === false
5427
            &&
5428
            $this->checkPropertiesMismatch === true
5429
        ) {
5430
            throw new \TypeError('The key ' . $key . ' does not exists in "properties". Maybe because @property was not used for the class (' . \get_class($this) . ').');
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with 'The key ' . $key . ' do...get_class($this) . ').'.

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

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

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

Loading history...
5431
        }
5432
5433
        if (isset($this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES])) {
5434
            $this->properties[self::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES]->checkType($value);
5435
        } elseif (isset($this->properties[$key])) {
5436
            $this->properties[$key]->checkType($value);
5437
        }
5438
    }
5439
}
5440