Completed
Push — master ( 2d3df6...81ca88 )
by Lars
02:08
created

Arrayy::findBy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arrayy;
6
7
/** @noinspection ClassReImplementsParentInterfaceInspection */
8
/** @noinspection PhpComposerExtensionStubsInspection */
9
10
/**
11
 * Methods to manage arrays.
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 */
16
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \JsonSerializable, \Countable
17
{
18
    /**
19
     * @var array
20
     */
21
    protected $array = [];
22
23
    /**
24
     * @var ArrayyRewindableGenerator|null
25
     */
26
    protected $generator;
27
28
    /**
29
     * @var string
30
     */
31
    protected $iteratorClass = ArrayyIterator::class;
32
33
    /**
34
     * @var string
35
     */
36
    protected $pathSeparator = '.';
37
38
    /**
39
     * @var bool
40
     */
41
    protected $checkPropertyTypes = false;
42
43
    /**
44
     * @var bool
45
     */
46
    protected $checkForMissingPropertiesInConstructor = false;
47
48
    /**
49
     * @var bool
50
     */
51
    protected $checkPropertiesMismatchInConstructor = false;
52
53
    /**
54
     * @var Property[]
55
     */
56
    protected $properties = [];
57
58
    /** @noinspection MagicMethodsValidityInspection */
59
    /** @noinspection PhpMissingParentConstructorInspection */
60
61
    /**
62
     * Initializes
63
     *
64
     * @param mixed  $data                                   <p>
65
     *                                                       Should be an array or a generator, otherwise it will try
66
     *                                                       to convert it into an array.
67
     *                                                       </p>
68
     * @param string $iteratorClass                          optional <p>
69
     *                                                       You can overwrite the ArrayyIterator, but mostly you don't
70
     *                                                       need this option.
71
     *                                                       </p>
72
     * @param bool   $checkForMissingPropertiesInConstructor optional <p>
73
     *                                                       You need to extend the "Arrayy"-class and you need to set
74
     *                                                       the $checkPropertiesMismatchInConstructor class property
75
     *                                                       to
76
     *                                                       true, otherwise this option didn't not work anyway.
77
     *                                                       </p>
78
     */
79 940
    public function __construct(
80
        $data = [],
81
        string $iteratorClass = ArrayyIterator::class,
82
        bool $checkForMissingPropertiesInConstructor = true
83
    ) {
84 940
        $data = $this->fallbackForArray($data);
85
86
        // used only for serialize + unserialize, all other methods are overwritten
87 938
        parent::__construct([], 0, $iteratorClass);
88
89 938
        $checkForMissingPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
90
                                                  &&
91 938
                                                  $checkForMissingPropertiesInConstructor === true;
92
93
        if (
94 938
            $this->checkPropertyTypes === true
95
            ||
96 938
            $checkForMissingPropertiesInConstructor === true
97
        ) {
98 15
            $this->properties = $this->getPropertiesFromPhpDoc();
99
        }
100
101
        if (
102 938
            $this->checkPropertiesMismatchInConstructor === true
103
            &&
104 938
            \count($data) !== 0
105
            &&
106 938
            \count(\array_diff_key($this->properties, $data)) > 0
107
        ) {
108 1
            throw new \InvalidArgumentException('Property mismatch - input: ' . \print_r(\array_keys($data), true) . ' | expected: ' . \print_r(\array_keys($this->properties), true));
109
        }
110
111
        /** @noinspection AlterInForeachInspection */
112 937
        foreach ($data as $key => &$value) {
113 818
            $this->internalSet(
114 818
                $key,
115 818
                $value,
116 818
                $checkForMissingPropertiesInConstructor
117
            );
118
        }
119
120 933
        $this->setIteratorClass($iteratorClass);
121 933
    }
122
123
    /**
124
     * Call object as function.
125
     *
126
     * @param mixed $key
127
     *
128
     * @return mixed
129
     */
130 1
    public function __invoke($key = null)
131
    {
132 1
        if ($key !== null) {
133 1
            $this->generatorToArray();
134
135 1
            return $this->array[$key] ?? false;
136
        }
137
138
        return $this->getArray();
139
    }
140
141
    /**
142
     * Whether or not an element exists by key.
143
     *
144
     * @param mixed $key
145
     *
146
     * @return bool
147
     *              <p>True is the key/index exists, otherwise false.</p>
148
     */
149
    public function __isset($key): bool
150
    {
151
        return $this->offsetExists($key);
152
    }
153
154
    /**
155
     * Assigns a value to the specified element.
156
     *
157
     * @param mixed $key
158
     * @param mixed $value
159
     */
160 2
    public function __set($key, $value)
161
    {
162 2
        $this->internalSet($key, $value);
163 2
    }
164
165
    /**
166
     * magic to string
167
     *
168
     * @return string
169
     */
170 15
    public function __toString(): string
171
    {
172 15
        return $this->toString();
173
    }
174
175
    /**
176
     * Unset element by key.
177
     *
178
     * @param mixed $key
179
     */
180
    public function __unset($key)
181
    {
182
        $this->internalRemove($key);
183
    }
184
185
    /**
186
     * Get a value by key.
187
     *
188
     * @param mixed $key
189
     *
190
     * @return mixed
191
     *               <p>Get a Value from the current array.</p>
192
     */
193 4
    public function &__get($key)
194
    {
195 4
        $return = $this->get($key);
196
197 4
        if (\is_array($return)) {
198
            return static::create($return, $this->iteratorClass, false);
199
        }
200
201 4
        return $return;
202
    }
203
204
    /**
205
     * alias: for "Arrayy->append()"
206
     *
207
     * @param mixed $value
208
     *
209
     * @return static
210
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
211
     *
212
     * @see Arrayy::append()
213
     */
214 3
    public function add($value): self
215
    {
216 3
        return $this->append($value);
217
    }
218
219
    /**
220
     * Append a (key) + value to the current array.
221
     *
222
     * @param mixed $value
223
     * @param mixed $key
224
     *
225
     * @return static
226
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
227
     */
228 11
    public function append($value, $key = null): self
229
    {
230 11
        $this->generatorToArray();
231
232 11
        if ($key !== null) {
233
            if (
234
                isset($this->array[$key])
235
                &&
236
                \is_array($this->array[$key])
237
            ) {
238
                $this->array[$key][] = $value;
239
            } else {
240
                $this->array[$key] = $value;
241
            }
242
        } else {
243 11
            $this->array[] = $value;
244
        }
245
246 11
        return $this;
247
    }
248
249
    /**
250
     * Sort the entries by value.
251
     *
252
     * @param int $sort_flags [optional] <p>
253
     *                        You may modify the behavior of the sort using the optional
254
     *                        parameter sort_flags, for details
255
     *                        see sort.
256
     *                        </p>
257
     *
258
     * @return static
259
     *                <p>(Mutable) Return this Arrayy object.</p>
260
     */
261 4
    public function asort(int $sort_flags = 0): self
262
    {
263 4
        $this->generatorToArray();
264
265 4
        \asort($this->array, $sort_flags);
266
267 4
        return $this;
268
    }
269
270
    /**
271
     * Counts all elements in an array, or something in an object.
272
     *
273
     * <p>
274
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
275
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
276
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
277
     * implemented and used in PHP.
278
     * </p>
279
     *
280
     * @see http://php.net/manual/en/function.count.php
281
     *
282
     * @param int $mode [optional] If the optional mode parameter is set to
283
     *                  COUNT_RECURSIVE (or 1), count
284
     *                  will recursively count the array. This is particularly useful for
285
     *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
286
     *
287
     * @return int
288
     *             <p>
289
     *             The number of elements in var, which is
290
     *             typically an array, since anything else will have one
291
     *             element.
292
     *             </p>
293
     *             <p>
294
     *             If var is not an array or an object with
295
     *             implemented Countable interface,
296
     *             1 will be returned.
297
     *             There is one exception, if var is &null;,
298
     *             0 will be returned.
299
     *             </p>
300
     *             <p>
301
     *             Caution: count may return 0 for a variable that isn't set,
302
     *             but it may also return 0 for a variable that has been initialized with an
303
     *             empty array. Use isset to test if a variable is set.
304
     *             </p>
305
     */
306 46
    public function count(int $mode = \COUNT_NORMAL): int
307
    {
308 46
        return \count($this->getArray(), $mode);
309
    }
310
311
    /**
312
     * Exchange the array for another one.
313
     *
314
     * @param array|static $data
315
     *
316
     * @return array
317
     */
318 1
    public function exchangeArray($data): array
319
    {
320 1
        $this->array = $this->fallbackForArray($data);
321
322 1
        return $this->array;
323
    }
324
325
    /**
326
     * Creates a copy of the ArrayyObject.
327
     *
328
     * @return array
329
     */
330 1
    public function getArrayCopy(): array
331
    {
332 1
        $this->generatorToArray();
333
334 1
        return $this->array;
335
    }
336
337
    /**
338
     * Returns a new iterator, thus implementing the \Iterator interface.
339
     *
340
     * @return \Iterator
341
     *                   <p>An iterator for the values in the array.</p>
342
     */
343 23
    public function getIterator(): \Iterator
344
    {
345 23
        if ($this->generator instanceof ArrayyRewindableGenerator) {
346 1
            return $this->generator;
347
        }
348
349 22
        $iterator = $this->getIteratorClass();
350
351 22
        if ($iterator === ArrayyIterator::class) {
352 22
            return new $iterator($this->getArray(), 0, static::class, false);
353
        }
354
355
        return new $iterator($this->getArray());
356
    }
357
358
    /**
359
     * Gets the iterator classname for the ArrayObject.
360
     *
361
     * @return string
362
     */
363 22
    public function getIteratorClass(): string
364
    {
365 22
        return $this->iteratorClass;
366
    }
367
368
    /**
369
     * Sort the entries by key
370
     *
371
     * @param int $sort_flags [optional] <p>
372
     *                        You may modify the behavior of the sort using the optional
373
     *                        parameter sort_flags, for details
374
     *                        see sort.
375
     *                        </p>
376
     *
377
     * @return static
378
     *                <p>(Mutable) Return this Arrayy object.</p>
379
     */
380 4
    public function ksort(int $sort_flags = 0): self
381
    {
382 4
        $this->generatorToArray();
383
384 4
        \ksort($this->array, $sort_flags);
385
386 4
        return $this;
387
    }
388
389
    /**
390
     * Sort an array using a case insensitive "natural order" algorithm
391
     *
392
     * @return static
393
     *                <p>(Mutable) Return this Arrayy object.</p>
394
     */
395
    public function natcasesort(): self
396
    {
397
        $this->generatorToArray();
398
399
        \natcasesort($this->array);
400
401
        return $this;
402
    }
403
404
    /**
405
     * Sort entries using a "natural order" algorithm
406
     *
407
     * @return static
408
     *                <p>(Mutable) Return this Arrayy object.</p>
409
     */
410 1
    public function natsort(): self
411
    {
412 1
        $this->generatorToArray();
413
414 1
        \natsort($this->array);
415
416 1
        return $this;
417
    }
418
419
    /**
420
     * Whether or not an offset exists.
421
     *
422
     * @param bool|int|string $offset
423
     *
424
     * @return bool
425
     */
426 46
    public function offsetExists($offset): bool
427
    {
428 46
        $this->generatorToArray();
429
430 46
        if ($this->array === []) {
431 4
            return false;
432
        }
433
434
        // php cast "bool"-index into "int"-index
435 42
        if (\is_bool($offset)) {
436 1
            $offset = (int) $offset;
437
        }
438
439 42
        $tmpReturn = \array_key_exists($offset, $this->array);
440
441
        if (
442 42
            $tmpReturn === true
443
            ||
444
            (
445 16
                $tmpReturn === false
446
                &&
447 42
                \strpos((string) $offset, $this->pathSeparator) === false
448
            )
449
        ) {
450 40
            return $tmpReturn;
451
        }
452
453 3
        $offsetExists = false;
454
455
        if (
456 3
            $this->pathSeparator
457
            &&
458 3
            \is_string($offset)
459
            &&
460 3
            \strpos($offset, $this->pathSeparator) !== false
461
        ) {
462 3
            $explodedPath = \explode($this->pathSeparator, (string) $offset);
463 3
            if ($explodedPath !== false) {
464 3
                $lastOffset = \array_pop($explodedPath);
465 3
                if ($lastOffset !== null) {
466 3
                    $containerPath = \implode($this->pathSeparator, $explodedPath);
467
468 3
                    $this->callAtPath(
469 3
                        $containerPath,
470 3
                        static function ($container) use ($lastOffset, &$offsetExists) {
471 3
                            $offsetExists = \array_key_exists($lastOffset, $container);
472 3
                        }
473
                    );
474
                }
475
            }
476
        }
477
478 3
        return $offsetExists;
479
    }
480
481
    /**
482
     * Returns the value at specified offset.
483
     *
484
     * @param int|string $offset
485
     *
486
     * @return mixed
487
     *               <p>Will return null if the offset did not exists.</p>
488
     */
489 30
    public function offsetGet($offset)
490
    {
491 30
        return $this->offsetExists($offset) ? $this->get($offset) : null;
492
    }
493
494
    /**
495
     * Assigns a value to the specified offset.
496
     *
497
     * @param int|string|null $offset
498
     * @param mixed           $value
499
     */
500 20
    public function offsetSet($offset, $value)
501
    {
502 20
        $this->generatorToArray();
503
504 20
        if ($offset === null) {
505 4
            $this->array[] = $value;
506
        } else {
507 16
            $this->internalSet($offset, $value);
508
        }
509 20
    }
510
511
    /**
512
     * Unset an offset.
513
     *
514
     * @param int|string $offset
515
     */
516 7
    public function offsetUnset($offset)
517
    {
518 7
        $this->generatorToArray();
519
520 7
        if ($this->array === []) {
521 1
            return;
522
        }
523
524 6
        if (\array_key_exists($offset, $this->array)) {
525 4
            unset($this->array[$offset]);
526
527 4
            return;
528
        }
529
530
        if (
531 3
            $this->pathSeparator
532
            &&
533 3
            \is_string($offset)
534
            &&
535 3
            \strpos($offset, $this->pathSeparator) !== false
536
        ) {
537 2
            $path = \explode($this->pathSeparator, (string) $offset);
538
539 2
            if ($path !== false) {
540 2
                $pathToUnset = \array_pop($path);
541
542 2
                $this->callAtPath(
543 2
                    \implode($this->pathSeparator, $path),
544 2
                    static function (&$offset) use ($pathToUnset) {
545 2
                        unset($offset[$pathToUnset]);
546 2
                    }
547
                );
548
            }
549
        }
550
551 3
        unset($this->array[$offset]);
552 3
    }
553
554
    /** @noinspection SenselessProxyMethodInspection | can not add return type, because of the "Serializable" interface */
555
556
    /**
557
     * Serialize the current "Arrayy"-object.
558
     *
559
     * @return string
560
     */
561 2
    public function serialize(): string
562
    {
563 2
        $this->generatorToArray();
564
565 2
        return parent::serialize();
566
    }
567
568
    /**
569
     * Sets the iterator classname for the current "Arrayy"-object.
570
     *
571
     * @param string $class
572
     *
573
     * @throws \InvalidArgumentException
574
     */
575 933
    public function setIteratorClass($class)
576
    {
577 933
        if (\class_exists($class)) {
578 933
            $this->iteratorClass = $class;
579
580 933
            return;
581
        }
582
583
        if (\strpos($class, '\\') === 0) {
584
            $class = '\\' . $class;
585
            if (\class_exists($class)) {
586
                $this->iteratorClass = $class;
587
588
                return;
589
            }
590
        }
591
592
        throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
593
    }
594
595
    /**
596
     * Sort the entries with a user-defined comparison function and maintain key association.
597
     *
598
     * @param callable $function
599
     *
600
     * @throws \InvalidArgumentException
601
     *
602
     * @return static
603
     *                <p>(Mutable) Return this Arrayy object.</p>
604
     */
605 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...
606
    {
607
        if (!\is_callable($function)) {
608
            throw new \InvalidArgumentException(
609
                'Passed function must be callable'
610
            );
611
        }
612
613
        $this->generatorToArray();
614
615
        \uasort($this->array, $function);
616
617
        return $this;
618
    }
619
620
    /**
621
     * Sort the entries by keys using a user-defined comparison function.
622
     *
623
     * @param callable $function
624
     *
625
     * @throws \InvalidArgumentException
626
     *
627
     * @return static
628
     *                <p>(Mutable) Return this Arrayy object.</p>
629
     */
630 5
    public function uksort($function): self
631
    {
632 5
        return $this->customSortKeys($function);
633
    }
634
635
    /**
636
     * Unserialize an string and return the instance of the "Arrayy"-class.
637
     *
638
     * @param string $string
639
     *
640
     * @return static
641
     */
642 2
    public function unserialize($string): self
643
    {
644 2
        parent::unserialize($string);
645
646 2
        return $this;
647
    }
648
649
    /**
650
     * Append a (key) + values to the current array.
651
     *
652
     * @param array $values
653
     * @param mixed $key
654
     *
655
     * @return static
656
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
657
     */
658 1
    public function appendArrayValues(array $values, $key = null): self
659
    {
660 1
        $this->generatorToArray();
661
662 1
        if ($key !== null) {
663
            if (
664 1
                isset($this->array[$key])
665
                &&
666 1
                \is_array($this->array[$key])
667
            ) {
668 1
                foreach ($values as $value) {
669 1
                    $this->array[$key][] = $value;
670
                }
671
            } else {
672
                foreach ($values as $value) {
673 1
                    $this->array[$key] = $value;
674
                }
675
            }
676
        } else {
677
            foreach ($values as $value) {
678
                $this->array[] = $value;
679
            }
680
        }
681
682 1
        return $this;
683
    }
684
685
    /**
686
     * Add a suffix to each key.
687
     *
688
     * @param mixed $prefix
689
     *
690
     * @return static
691
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
692
     */
693 10 View Code Duplication
    public function appendToEachKey($prefix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
694
    {
695
        // init
696 10
        $result = [];
697
698 10
        foreach ($this->getGenerator() as $key => $item) {
699 9
            if ($item instanceof self) {
700
                $result[$prefix . $key] = $item->appendToEachKey($prefix);
701 9
            } elseif (\is_array($item)) {
702
                $result[$prefix . $key] = self::create($item, $this->iteratorClass, false)
703
                    ->appendToEachKey($prefix)
704
                    ->toArray();
705
            } else {
706 9
                $result[$prefix . $key] = $item;
707
            }
708
        }
709
710 10
        return self::create($result, $this->iteratorClass, false);
711
    }
712
713
    /**
714
     * Add a prefix to each value.
715
     *
716
     * @param mixed $prefix
717
     *
718
     * @return static
719
     *                <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
720
     */
721 10 View Code Duplication
    public function appendToEachValue($prefix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
722
    {
723
        // init
724 10
        $result = [];
725
726 10
        foreach ($this->getGenerator() as $key => $item) {
727 9
            if ($item instanceof self) {
728
                $result[$key] = $item->appendToEachValue($prefix);
729 9
            } elseif (\is_array($item)) {
730
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
731 9
            } elseif (\is_object($item)) {
732 1
                $result[$key] = $item;
733
            } else {
734 9
                $result[$key] = $prefix . $item;
735
            }
736
        }
737
738 10
        return self::create($result, $this->iteratorClass, false);
739
    }
740
741
    /**
742
     * Sort an array in reverse order and maintain index association.
743
     *
744
     * @return static
745
     *                <p>(Mutable) Return this Arrayy object.</p>
746
     */
747 4
    public function arsort(): self
748
    {
749 4
        $this->generatorToArray();
750
751 4
        \arsort($this->array);
752
753 4
        return $this;
754
    }
755
756
    /**
757
     * Iterate over the current array and execute a callback for each loop.
758
     *
759
     * @param \Closure $closure
760
     *
761
     * @return static
762
     *                <p>(Immutable)</p>
763
     */
764 2
    public function at(\Closure $closure): self
765
    {
766 2
        $arrayy = clone $this;
767
768 2
        foreach ($arrayy->getGenerator() as $key => $value) {
769 2
            $closure($value, $key);
770
        }
771
772 2
        return static::create(
773 2
            $arrayy->toArray(),
774 2
            $this->iteratorClass,
775 2
            false
776
        );
777
    }
778
779
    /**
780
     * Returns the average value of the current array.
781
     *
782
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
783
     *
784
     * @return float|int
785
     *                   <p>The average value.</p>
786
     */
787 10
    public function average($decimals = 0)
788
    {
789 10
        $count = \count($this->getArray(), \COUNT_NORMAL);
790
791 10
        if (!$count) {
792 2
            return 0;
793
        }
794
795 8
        if (!\is_int($decimals)) {
796 3
            $decimals = 0;
797
        }
798
799 8
        return \round(\array_sum($this->getArray()) / $count, $decimals);
800
    }
801
802
    /**
803
     * Changes all keys in an array.
804
     *
805
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
806
     *                  or <strong>CASE_LOWER</strong> (default)</p>
807
     *
808
     * @return static
809
     *                <p>(Immutable)</p>
810
     */
811 1
    public function changeKeyCase(int $case = \CASE_LOWER): self
812
    {
813
        if (
814 1
            $case !== \CASE_LOWER
815
            &&
816 1
            $case !== \CASE_UPPER
817
        ) {
818
            $case = \CASE_LOWER;
819
        }
820
821 1
        $return = [];
822 1
        foreach ($this->getGenerator() as $key => $value) {
823 1
            if ($case === \CASE_LOWER) {
824
                /** @noinspection PhpComposerExtensionStubsInspection */
825 1
                $key = \mb_strtolower((string) $key);
826
            } else {
827
                /** @noinspection PhpComposerExtensionStubsInspection */
828 1
                $key = \mb_strtoupper((string) $key);
829
            }
830
831 1
            $return[$key] = $value;
832
        }
833
834 1
        return static::create(
835 1
            $return,
836 1
            $this->iteratorClass,
837 1
            false
838
        );
839
    }
840
841
    /**
842
     * Change the path separator of the array wrapper.
843
     *
844
     * By default, the separator is: "."
845
     *
846
     * @param string $separator <p>Separator to set.</p>
847
     *
848
     * @return static
849
     *                <p>Mutable</p>
850
     */
851 10
    public function changeSeparator($separator): self
852
    {
853 10
        $this->pathSeparator = $separator;
854
855 10
        return $this;
856
    }
857
858
    /**
859
     * Create a chunked version of the current array.
860
     *
861
     * @param int  $size         <p>Size of each chunk.</p>
862
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
863
     *
864
     * @return static
865
     *                <p>(Immutable) A new array of chunks from the original array.</p>
866
     */
867 4
    public function chunk($size, $preserveKeys = false): self
868
    {
869 4
        return static::create(
870 4
            \array_chunk($this->getArray(), $size, $preserveKeys),
871 4
            $this->iteratorClass,
872 4
            false
873
        );
874
    }
875
876
    /**
877
     * Clean all falsy values from the current array.
878
     *
879
     * @return static
880
     *                <p>(Immutable)</p>
881
     */
882 8
    public function clean(): self
883
    {
884 8
        return $this->filter(
885 8
            static function ($value) {
886 7
                return (bool) $value;
887 8
            }
888
        );
889
    }
890
891
    /**
892
     * WARNING!!! -> Clear the current array.
893
     *
894
     * @return static
895
     *                <p>(Mutable) Return this Arrayy object, with an empty array.</p>
896
     */
897 4
    public function clear(): self
898
    {
899 4
        $this->array = [];
900 4
        $this->generator = null;
901
902 4
        return $this;
903
    }
904
905
    /**
906
     * Check if an item is in the current array.
907
     *
908
     * @param float|int|string $value
909
     * @param bool             $recursive
910
     * @param bool             $strict
911
     *
912
     * @return bool
913
     */
914 22
    public function contains($value, bool $recursive = false, bool $strict = true): bool
915
    {
916 22
        if ($recursive === true) {
917 18
            return $this->in_array_recursive($value, $this->getArray(), $strict);
918
        }
919
920 13
        foreach ($this->getGenerator() as $valueFromArray) {
921 10
            if ($strict) {
922 10
                if ($value === $valueFromArray) {
923 10
                    return true;
924
                }
925
            } else {
926
                /** @noinspection NestedPositiveIfStatementsInspection */
927
                if ($value == $valueFromArray) {
928 6
                    return true;
929
                }
930
            }
931
        }
932
933 6
        return false;
934
    }
935
936
    /**
937
     * Check if an (case-insensitive) string is in the current array.
938
     *
939
     * @param string $value
940
     * @param bool   $recursive
941
     *
942
     * @return bool
943
     */
944 26
    public function containsCaseInsensitive($value, $recursive = false): bool
945
    {
946 26
        if ($recursive === true) {
947 26
            foreach ($this->getGenerator() as $key => $valueTmp) {
948 22
                if (\is_array($valueTmp)) {
949 5
                    $return = (new self($valueTmp))->containsCaseInsensitive($value, $recursive);
950 5
                    if ($return === true) {
951 5
                        return $return;
952
                    }
953 22
                } elseif (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
954 22
                    return true;
955
                }
956
            }
957
958 10
            return false;
959
        }
960
961 13
        foreach ($this->getGenerator() as $key => $valueTmp) {
962 11
            if (\mb_strtoupper((string) $valueTmp) === \mb_strtoupper((string) $value)) {
963 11
                return true;
964
            }
965
        }
966
967 5
        return false;
968
    }
969
970
    /**
971
     * Check if the given key/index exists in the array.
972
     *
973
     * @param int|string $key <p>key/index to search for</p>
974
     *
975
     * @return bool
976
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
977
     */
978 4
    public function containsKey($key): bool
979
    {
980 4
        return $this->offsetExists($key);
981
    }
982
983
    /**
984
     * Check if all given needles are present in the array as key/index.
985
     *
986
     * @param array $needles   <p>The keys you are searching for.</p>
987
     * @param bool  $recursive
988
     *
989
     * @return bool
990
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
991
     */
992 2
    public function containsKeys(array $needles, $recursive = false): bool
993
    {
994 2
        if ($recursive === true) {
995 2
            return \count(
996 2
                       \array_intersect($needles, $this->keys(true)->getArray()),
997 2
                       \COUNT_RECURSIVE
998
                   )
999
                   ===
1000 2
                   \count(
1001 2
                       $needles,
1002 2
                       \COUNT_RECURSIVE
1003
                   );
1004
        }
1005
1006 1
        return \count(
1007 1
                   \array_intersect($needles, $this->keys()->getArray()),
1008 1
                   \COUNT_NORMAL
1009
               )
1010
               ===
1011 1
               \count(
1012 1
                   $needles,
1013 1
                   \COUNT_NORMAL
1014
               );
1015
    }
1016
1017
    /**
1018
     * Check if all given needles are present in the array as key/index.
1019
     *
1020
     * @param array $needles <p>The keys you are searching for.</p>
1021
     *
1022
     * @return bool
1023
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1024
     */
1025 1
    public function containsKeysRecursive(array $needles): bool
1026
    {
1027 1
        return $this->containsKeys($needles, true);
1028
    }
1029
1030
    /**
1031
     * alias: for "Arrayy->contains()"
1032
     *
1033
     * @param float|int|string $value
1034
     *
1035
     * @return bool
1036
     *
1037
     * @see Arrayy::contains()
1038
     */
1039 9
    public function containsValue($value): bool
1040
    {
1041 9
        return $this->contains($value);
1042
    }
1043
1044
    /**
1045
     * alias: for "Arrayy->contains($value, true)"
1046
     *
1047
     * @param float|int|string $value
1048
     *
1049
     * @return bool
1050
     *
1051
     * @see Arrayy::contains()
1052
     */
1053 18
    public function containsValueRecursive($value): bool
1054
    {
1055 18
        return $this->contains($value, true);
1056
    }
1057
1058
    /**
1059
     * Check if all given needles are present in the array.
1060
     *
1061
     * @param array $needles
1062
     *
1063
     * @return bool
1064
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
1065
     */
1066 1
    public function containsValues(array $needles): bool
1067
    {
1068 1
        return \count(\array_intersect($needles, $this->getArray()), \COUNT_NORMAL)
1069
               ===
1070 1
               \count($needles, \COUNT_NORMAL);
1071
    }
1072
1073
    /**
1074
     * Counts all the values of an array
1075
     *
1076
     * @see http://php.net/manual/en/function.array-count-values.php
1077
     *
1078
     * @return static
1079
     *                <p>
1080
     *                (Immutable)
1081
     *                An associative Arrayy-object of values from input as
1082
     *                keys and their count as value.
1083
     *                </p>
1084
     */
1085 1
    public function countValues(): self
1086
    {
1087 1
        return new static(\array_count_values($this->getArray()));
1088
    }
1089
1090
    /**
1091
     * Creates an Arrayy object.
1092
     *
1093
     * @param mixed  $array
1094
     * @param string $iteratorClass
1095
     * @param bool   $checkForMissingPropertiesInConstructor
1096
     *
1097
     * @return static
1098
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1099
     */
1100 556
    public static function create($array = [], string $iteratorClass = ArrayyIterator::class, bool $checkForMissingPropertiesInConstructor = true): self
1101
    {
1102 556
        return new static(
1103 556
            $array,
1104 556
            $iteratorClass,
1105 556
            $checkForMissingPropertiesInConstructor
1106
        );
1107
    }
1108
1109
    /**
1110
     * WARNING: Creates an Arrayy object by reference.
1111
     *
1112
     * @param array $array
1113
     *
1114
     * @return static
1115
     *                <p>(Mutable) Return this Arrayy object.</p>
1116
     */
1117 1
    public function createByReference(array &$array = []): self
1118
    {
1119 1
        $array = $this->fallbackForArray($array);
1120
1121 1
        $this->array = &$array;
1122
1123 1
        return $this;
1124
    }
1125
1126
    /**
1127
     * Create an new instance from a callable function which will return an Generator.
1128
     *
1129
     * @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...
1130
     *
1131
     * @return static
1132
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1133
     */
1134 5
    public static function createFromGeneratorFunction(callable $generatorFunction): self
1135
    {
1136 5
        $arrayy = new static($generatorFunction);
1137
1138 5
        return $arrayy;
1139
    }
1140
1141
    /**
1142
     * Create an new instance filled with a copy of values from a "Traversable"-object.
1143
     *
1144
     * @param \Traversable $traversable
1145
     *
1146
     * @return static
1147
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1148
     */
1149
    public static function createFromTraversableImmutable(\Traversable $traversable): self
1150
    {
1151
        return new static(\iterator_to_array($traversable, true));
1152
    }
1153
1154
    /**
1155
     * Create an new instance filled with a copy of values from a "Generator"-object.
1156
     *
1157
     * @param \Generator $generator
1158
     *
1159
     * @return static
1160
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1161
     */
1162 4
    public static function createFromGeneratorImmutable(\Generator $generator): self
1163
    {
1164 4
        return new static(\iterator_to_array($generator, true));
1165
    }
1166
1167
    /**
1168
     * Create an new Arrayy object via JSON.
1169
     *
1170
     * @param string $json
1171
     *
1172
     * @return static
1173
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1174
     */
1175 5
    public static function createFromJson(string $json): self
1176
    {
1177
        /** @noinspection PhpComposerExtensionStubsInspection */
1178 5
        return static::create(\json_decode($json, true));
1179
    }
1180
1181
    /**
1182
     * Create an new instance filled with values from an object that is iterable.
1183
     *
1184
     * @param \Traversable $object <p>iterable object</p>
1185
     *
1186
     * @return static
1187
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1188
     */
1189 4
    public static function createFromObject(\Traversable $object): self
1190
    {
1191
        // init
1192 4
        $array = new static();
1193
1194 4
        if ($object instanceof self) {
1195 4
            $objectArray = $object->getGenerator();
1196
        } else {
1197
            $objectArray = $object;
1198
        }
1199
1200 4
        foreach ($objectArray as $key => $value) {
1201 3
            $array[$key] = $value;
1202
        }
1203
1204 4
        return $array;
1205
    }
1206
1207
    /**
1208
     * Create an new instance filled with values from an object.
1209
     *
1210
     * @param object $object
1211
     *
1212
     * @return static
1213
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1214
     */
1215 5
    public static function createFromObjectVars($object): self
1216
    {
1217 5
        return new static(self::objectToArray($object));
1218
    }
1219
1220
    /**
1221
     * Create an new Arrayy object via string.
1222
     *
1223
     * @param string      $str       <p>The input string.</p>
1224
     * @param string|null $delimiter <p>The boundary string.</p>
1225
     * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1226
     *                               used.</p>
1227
     *
1228
     * @return static
1229
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1230
     */
1231 10
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
1232
    {
1233 10
        if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1234 1
            \preg_match_all($regEx, $str, $array);
1235
1236 1
            if (!empty($array)) {
1237 1
                $array = $array[0];
1238
            }
1239
        } else {
1240
            /** @noinspection NestedPositiveIfStatementsInspection */
1241 9
            if ($delimiter !== null) {
1242 7
                $array = \explode($delimiter, $str);
1243
            } else {
1244 2
                $array = [$str];
1245
            }
1246
        }
1247
1248
        // trim all string in the array
1249 10
        \array_walk(
1250
            $array,
1251 10
            static function (&$val) {
1252 10
                if (\is_string($val)) {
1253 10
                    $val = \trim($val);
1254
                }
1255 10
            }
1256
        );
1257
1258 10
        return static::create($array);
1259
    }
1260
1261
    /**
1262
     * Create an new instance containing a range of elements.
1263
     *
1264
     * @param mixed $low  <p>First value of the sequence.</p>
1265
     * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1266
     * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1267
     *
1268
     * @return static
1269
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1270
     */
1271 2
    public static function createWithRange($low, $high, int $step = 1): self
1272
    {
1273 2
        return static::create(\range($low, $high, $step));
1274
    }
1275
1276
    /**
1277
     * Custom sort by index via "uksort".
1278
     *
1279
     * @see http://php.net/manual/en/function.uksort.php
1280
     *
1281
     * @param callable $function
1282
     *
1283
     * @throws \InvalidArgumentException
1284
     *
1285
     * @return static
1286
     *                <p>(Mutable) Return this Arrayy object.</p>
1287
     */
1288 5 View Code Duplication
    public function customSortKeys($function): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1289
    {
1290 5
        if (!\is_callable($function)) {
1291
            throw new \InvalidArgumentException(
1292
                'Passed function must be callable'
1293
            );
1294
        }
1295
1296 5
        $this->generatorToArray();
1297
1298 5
        \uksort($this->array, $function);
1299
1300 5
        return $this;
1301
    }
1302
1303
    /**
1304
     * Custom sort by value via "usort".
1305
     *
1306
     * @see http://php.net/manual/en/function.usort.php
1307
     *
1308
     * @param callable $function
1309
     *
1310
     * @throws \InvalidArgumentException
1311
     *
1312
     * @return static
1313
     *                <p>(Mutable) Return this Arrayy object.</p>
1314
     */
1315 5 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...
1316
    {
1317 5
        if (!\is_callable($function)) {
1318
            throw new \InvalidArgumentException(
1319
                'Passed function must be callable'
1320
            );
1321
        }
1322
1323 5
        $this->generatorToArray();
1324
1325 5
        \usort($this->array, $function);
1326
1327 5
        return $this;
1328
    }
1329
1330
    /**
1331
     * Return values that are only in the current array.
1332
     *
1333
     * @param array $array
1334
     *
1335
     * @return static
1336
     *                <p>(Immutable)</p>
1337
     */
1338 12
    public function diff(array $array = []): self
1339
    {
1340 12
        return static::create(
1341 12
            \array_diff($this->getArray(), $array),
1342 12
            $this->iteratorClass,
1343 12
            false
1344
        );
1345
    }
1346
1347
    /**
1348
     * Return values that are only in the current multi-dimensional array.
1349
     *
1350
     * @param array      $array
1351
     * @param array|null $helperVariableForRecursion <p>(only for internal usage)</p>
1352
     *
1353
     * @return static
1354
     *                <p>(Immutable)</p>
1355
     */
1356 1
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
1357
    {
1358
        // init
1359 1
        $result = [];
1360
1361
        if (
1362 1
            $helperVariableForRecursion !== null
1363
            &&
1364 1
            \is_array($helperVariableForRecursion)
1365
        ) {
1366
            $arrayForTheLoop = $helperVariableForRecursion;
1367
        } else {
1368 1
            $arrayForTheLoop = $this->getGenerator();
1369
        }
1370
1371 1
        foreach ($arrayForTheLoop as $key => $value) {
1372 1
            if ($value instanceof self) {
1373
                $value = $value->getArray();
1374
            }
1375
1376 1
            if (\array_key_exists($key, $array)) {
1377 1
                if ($value !== $array[$key]) {
1378 1
                    $result[$key] = $value;
1379
                }
1380
            } else {
1381 1
                $result[$key] = $value;
1382
            }
1383
        }
1384
1385 1
        return static::create(
1386 1
            $result,
1387 1
            $this->iteratorClass,
1388 1
            false
1389
        );
1390
    }
1391
1392
    /**
1393
     * Return values that are only in the new $array.
1394
     *
1395
     * @param array $array
1396
     *
1397
     * @return static
1398
     *                <p>(Immutable)</p>
1399
     */
1400 8
    public function diffReverse(array $array = []): self
1401
    {
1402 8
        return static::create(
1403 8
            \array_diff($array, $this->getArray()),
1404 8
            $this->iteratorClass,
1405 8
            false
1406
        );
1407
    }
1408
1409
    /**
1410
     * Divide an array into two arrays. One with keys and the other with values.
1411
     *
1412
     * @return static
1413
     *                <p>(Immutable)</p>
1414
     */
1415 1
    public function divide(): self
1416
    {
1417 1
        return static::create(
1418
            [
1419 1
                $this->keys(),
1420 1
                $this->values(),
1421
            ],
1422 1
            $this->iteratorClass,
1423 1
            false
1424
        );
1425
    }
1426
1427
    /**
1428
     * Iterate over the current array and modify the array's value.
1429
     *
1430
     * @param \Closure $closure
1431
     *
1432
     * @return static
1433
     *                <p>(Immutable)</p>
1434
     */
1435 4 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...
1436
    {
1437
        // init
1438 4
        $array = [];
1439
1440 4
        foreach ($this->getGenerator() as $key => $value) {
1441 4
            $array[$key] = $closure($value, $key);
1442
        }
1443
1444 4
        return static::create(
1445 4
            $array,
1446 4
            $this->iteratorClass,
1447 4
            false
1448
        );
1449
    }
1450
1451
    /**
1452
     * Check if a value is in the current array using a closure.
1453
     *
1454
     * @param \Closure $closure
1455
     *
1456
     * @return bool
1457
     *              <p>Returns true if the given value is found, false otherwise.</p>
1458
     */
1459 4
    public function exists(\Closure $closure): bool
1460
    {
1461
        // init
1462 4
        $isExists = false;
1463
1464 4
        foreach ($this->getGenerator() as $key => $value) {
1465 3
            if ($closure($value, $key)) {
1466 1
                $isExists = true;
1467
1468 3
                break;
1469
            }
1470
        }
1471
1472 4
        return $isExists;
1473
    }
1474
1475
    /**
1476
     * Fill the array until "$num" with "$default" values.
1477
     *
1478
     * @param int   $num
1479
     * @param mixed $default
1480
     *
1481
     * @return static
1482
     *                <p>(Immutable)</p>
1483
     */
1484 8
    public function fillWithDefaults(int $num, $default = null): self
1485
    {
1486 8
        if ($num < 0) {
1487 1
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1488
        }
1489
1490 7
        $this->generatorToArray();
1491
1492 7
        $tmpArray = $this->array;
1493
1494 7
        $count = \count($tmpArray);
1495
1496 7
        while ($count < $num) {
1497 4
            $tmpArray[] = $default;
1498 4
            ++$count;
1499
        }
1500
1501 7
        return static::create(
1502 7
            $tmpArray,
1503 7
            $this->iteratorClass,
1504 7
            false
1505
        );
1506
    }
1507
1508
    /**
1509
     * Find all items in an array that pass the truth test.
1510
     *
1511
     * @param \Closure|null $closure [optional] <p>
1512
     *                               The callback function to use
1513
     *                               </p>
1514
     *                               <p>
1515
     *                               If no callback is supplied, all entries of
1516
     *                               input equal to false (see
1517
     *                               converting to
1518
     *                               boolean) will be removed.
1519
     *                               </p>
1520
     *                               * @param int $flag [optional] <p>
1521
     *                               Flag determining what arguments are sent to <i>callback</i>:
1522
     *                               </p><ul>
1523
     *                               <li>
1524
     *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1525
     *                               to <i>callback</i> instead of the value</span>
1526
     *                               </li>
1527
     *                               <li>
1528
     *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1529
     *                               arguments to <i>callback</i> instead of the value</span>
1530
     *                               </li>
1531
     *                               </ul>
1532
     *
1533
     * @return static
1534
     *                <p>(Immutable)</p>
1535
     */
1536 11
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH): self
1537
    {
1538 11
        if (!$closure) {
1539 1
            return $this->clean();
1540
        }
1541
1542 11
        return static::create(
1543 11
            \array_filter($this->getArray(), $closure, $flag),
1544 11
            $this->iteratorClass,
1545 11
            false
1546
        );
1547
    }
1548
1549
    /**
1550
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
1551
     * property within that.
1552
     *
1553
     * @param string          $property
1554
     * @param string|string[] $value
1555
     * @param string          $comparisonOp
1556
     *                                      <p>
1557
     *                                      'eq' (equals),<br />
1558
     *                                      'gt' (greater),<br />
1559
     *                                      'gte' || 'ge' (greater or equals),<br />
1560
     *                                      'lt' (less),<br />
1561
     *                                      'lte' || 'le' (less or equals),<br />
1562
     *                                      'ne' (not equals),<br />
1563
     *                                      'contains',<br />
1564
     *                                      'notContains',<br />
1565
     *                                      'newer' (via strtotime),<br />
1566
     *                                      'older' (via strtotime),<br />
1567
     *                                      </p>
1568
     *
1569
     * @return static
1570
     *                <p>(Immutable)</p>
1571
     */
1572 1
    public function filterBy(string $property, $value, string $comparisonOp = null): self
1573
    {
1574 1
        if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1575 1
            $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1576
        }
1577
1578
        $ops = [
1579 1
            'eq' => static function ($item, $prop, $value) {
1580 1
                return $item[$prop] === $value;
1581 1
            },
1582 1
            'gt' => static function ($item, $prop, $value) {
1583
                return $item[$prop] > $value;
1584 1
            },
1585 1
            'ge' => static function ($item, $prop, $value) {
1586
                return $item[$prop] >= $value;
1587 1
            },
1588 1
            'gte' => static function ($item, $prop, $value) {
1589
                return $item[$prop] >= $value;
1590 1
            },
1591 1
            'lt' => static function ($item, $prop, $value) {
1592 1
                return $item[$prop] < $value;
1593 1
            },
1594 1
            'le' => static function ($item, $prop, $value) {
1595
                return $item[$prop] <= $value;
1596 1
            },
1597 1
            'lte' => static function ($item, $prop, $value) {
1598
                return $item[$prop] <= $value;
1599 1
            },
1600 1
            'ne' => static function ($item, $prop, $value) {
1601
                return $item[$prop] !== $value;
1602 1
            },
1603 1
            'contains' => static function ($item, $prop, $value) {
1604 1
                return \in_array($item[$prop], (array) $value, true);
1605 1
            },
1606 1
            'notContains' => static function ($item, $prop, $value) {
1607
                return !\in_array($item[$prop], (array) $value, true);
1608 1
            },
1609 1
            'newer' => static function ($item, $prop, $value) {
1610
                return \strtotime($item[$prop]) > \strtotime($value);
1611 1
            },
1612 1
            'older' => static function ($item, $prop, $value) {
1613
                return \strtotime($item[$prop]) < \strtotime($value);
1614 1
            },
1615
        ];
1616
1617 1
        $result = \array_values(
1618 1
            \array_filter(
1619 1
                $this->getArray(),
1620 1
                static function ($item) use (
1621 1
                    $property,
1622 1
                    $value,
1623 1
                    $ops,
1624 1
                    $comparisonOp
1625
                ) {
1626 1
                    $item = (array) $item;
1627 1
                    $itemArrayy = new static($item);
1628 1
                    $item[$property] = $itemArrayy->get($property, []);
1629
1630 1
                    return $ops[$comparisonOp]($item, $property, $value);
1631 1
                }
1632
            )
1633
        );
1634
1635 1
        return static::create(
1636 1
            $result,
1637 1
            $this->iteratorClass,
1638 1
            false
1639
        );
1640
    }
1641
1642
    /**
1643
     * Find the first item in an array that passes the truth test,
1644
     *  otherwise return false
1645
     *
1646
     * @param \Closure $closure
1647
     *
1648
     * @return false|mixed
1649
     *                     <p>Return false if we did not find the value.</p>
1650
     */
1651 8
    public function find(\Closure $closure)
1652
    {
1653 8
        foreach ($this->getGenerator() as $key => $value) {
1654 6
            if ($closure($value, $key)) {
1655 6
                return $value;
1656
            }
1657
        }
1658
1659 3
        return false;
1660
    }
1661
1662
    /**
1663
     * find by ...
1664
     *
1665
     * @param string          $property
1666
     * @param string|string[] $value
1667
     * @param string          $comparisonOp
1668
     *
1669
     * @return static
1670
     *                <p>(Immutable)</p>
1671
     */
1672
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
1673
    {
1674
        return $this->filterBy($property, $value, $comparisonOp);
1675
    }
1676
1677
    /**
1678
     * Get the first value from the current array.
1679
     *
1680
     * @return mixed
1681
     *               <p>Return null if there wasn't a element.</p>
1682
     */
1683 13
    public function first()
1684
    {
1685 13
        $tmpArray = $this->getArray();
1686
1687 13
        return \array_shift($tmpArray);
1688
    }
1689
1690
    /**
1691
     * Get the first value(s) from the current array.
1692
     * And will return an empty array if there was no first entry.
1693
     *
1694
     * @param int|null $number <p>How many values you will take?</p>
1695
     *
1696
     * @return static
1697
     *                <p>(Immutable)</p>
1698
     */
1699 36
    public function firstsImmutable(int $number = null): self
1700
    {
1701 36
        $arrayTmp = $this->getArray();
1702
1703 36
        if ($number === null) {
1704 14
            $array = (array) \array_shift($arrayTmp);
1705
        } else {
1706 22
            $number = (int) $number;
1707 22
            $array = \array_splice($arrayTmp, 0, $number);
1708
        }
1709
1710 36
        return static::create(
1711 36
            $array,
1712 36
            $this->iteratorClass,
1713 36
            false
1714
        );
1715
    }
1716
1717
    /**
1718
     * Get the first value(s) from the current array.
1719
     * And will return an empty array if there was no first entry.
1720
     *
1721
     * @param int|null $number <p>How many values you will take?</p>
1722
     *
1723
     * @return static
1724
     *                <p>(Mutable)</p>
1725
     */
1726 34
    public function firstsMutable(int $number = null): self
1727
    {
1728 34
        $this->generatorToArray();
1729
1730 34
        if ($number === null) {
1731 19
            $this->array = (array) \array_shift($this->array);
1732
        } else {
1733 15
            $number = (int) $number;
1734 15
            $this->array = \array_splice($this->array, 0, $number);
1735
        }
1736
1737 34
        return $this;
1738
    }
1739
1740
    /**
1741
     * Exchanges all keys with their associated values in an array.
1742
     *
1743
     * @return static
1744
     *                <p>(Immutable)</p>
1745
     */
1746 1
    public function flip(): self
1747
    {
1748 1
        return static::create(
1749 1
            \array_flip($this->getArray()),
1750 1
            $this->iteratorClass,
1751 1
            false
1752
        );
1753
    }
1754
1755
    /**
1756
     * Get a value from an array (optional using dot-notation).
1757
     *
1758
     * @param mixed $key      <p>The key to look for.</p>
1759
     * @param mixed $fallback <p>Value to fallback to.</p>
1760
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
1761
     *                        class.</p>
1762
     *
1763
     * @return mixed|static
1764
     */
1765 73
    public function get($key, $fallback = null, array $array = null)
1766
    {
1767 73
        if ($array !== null) {
1768 5
            $usedArray = $array;
1769
        } else {
1770 68
            $this->generatorToArray();
1771
1772 68
            $usedArray = $this->array;
1773
        }
1774
1775 73
        if ($key === null) {
1776 1
            return static::create(
1777 1
                $usedArray,
1778 1
                $this->iteratorClass,
1779 1
                false
1780
            );
1781
        }
1782
1783
        // php cast "bool"-index into "int"-index
1784 73
        if ((bool) $key === $key) {
1785 3
            $key = (int) $key;
1786
        }
1787
1788 73
        if (\array_key_exists($key, $usedArray) === true) {
1789 62
            if (\is_array($usedArray[$key])) {
1790 9
                return static::create(
1791 9
                    $usedArray[$key],
1792 9
                    $this->iteratorClass,
1793 9
                    false
1794
                );
1795
            }
1796
1797 55
            return $usedArray[$key];
1798
        }
1799
1800
        // crawl through array, get key according to object or not
1801 23
        $usePath = false;
1802
        if (
1803 23
            $this->pathSeparator
1804
            &&
1805 23
            \is_string($key)
1806
            &&
1807 23
            \strpos($key, $this->pathSeparator) !== false
1808
        ) {
1809 7
            $segments = \explode($this->pathSeparator, (string) $key);
1810 7
            if ($segments !== false) {
1811 7
                $usePath = true;
1812
1813 7
                foreach ($segments as $segment) {
1814
                    if (
1815
                        (
1816 7
                            \is_array($usedArray)
1817
                            ||
1818 7
                            $usedArray instanceof \ArrayAccess
1819
                        )
1820
                        &&
1821 7
                        isset($usedArray[$segment])
1822
                    ) {
1823 7
                        $usedArray = $usedArray[$segment];
1824
1825 7
                        continue;
1826
                    }
1827
1828
                    if (
1829 6
                        \is_object($usedArray)
1830
                        &&
1831 6
                        \property_exists($usedArray, $segment)
1832
                    ) {
1833 1
                        $usedArray = $usedArray->{$segment};
1834
1835 1
                        continue;
1836
                    }
1837
1838 5
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
1839
                }
1840
            }
1841
        }
1842
1843 23
        if (!$usePath && !isset($usedArray[$key])) {
1844 16
            return $fallback instanceof \Closure ? $fallback() : $fallback;
1845
        }
1846
1847 7
        if (\is_array($usedArray)) {
1848 1
            return static::create(
1849 1
                $usedArray,
1850 1
                $this->iteratorClass,
1851 1
                false
1852
            );
1853
        }
1854
1855 7
        return $usedArray;
1856
    }
1857
1858
    /**
1859
     * Get the current array from the "Arrayy"-object.
1860
     *
1861
     * @return array
1862
     */
1863 776
    public function getArray(): array
1864
    {
1865
        // init
1866 776
        $array = [];
1867
1868 776
        foreach ($this->getGenerator() as $key => $value) {
1869 671
            $array[$key] = $value;
1870
        }
1871
1872 776
        return $array;
1873
    }
1874
1875
    /**
1876
     * Returns the values from a single column of the input array, identified by
1877
     * the $columnKey, can be used to extract data-columns from multi-arrays.
1878
     *
1879
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
1880
     * array by the values from the $indexKey column in the input array.
1881
     *
1882
     * @param mixed $columnKey
1883
     * @param mixed $indexKey
1884
     *
1885
     * @return static
1886
     *                <p>(Immutable)</p>
1887
     */
1888 1
    public function getColumn($columnKey = null, $indexKey = null): self
1889
    {
1890 1
        return static::create(
1891 1
            \array_column($this->getArray(), $columnKey, $indexKey),
1892 1
            $this->iteratorClass,
1893 1
            false
1894
        );
1895
    }
1896
1897
    /**
1898
     * Get the current array from the "Arrayy"-object as generator.
1899
     *
1900
     * @return \Generator
1901
     */
1902 851
    public function getGenerator(): \Generator
1903
    {
1904 851
        if ($this->generator instanceof ArrayyRewindableGenerator) {
1905 36
            yield from $this->generator;
1906
        }
1907
1908 851
        yield from $this->array;
1909 808
    }
1910
1911
    /**
1912
     * alias: for "Arrayy->keys()"
1913
     *
1914
     * @return static
1915
     *                <p>(Immutable)</p>
1916
     *
1917
     * @see Arrayy::keys()
1918
     */
1919 1
    public function getKeys(): self
1920
    {
1921 1
        return $this->keys();
1922
    }
1923
1924
    /**
1925
     * Get the current array from the "Arrayy"-object as object.
1926
     *
1927
     * @return \stdClass
1928
     */
1929 4
    public function getObject(): \stdClass
1930
    {
1931 4
        return self::arrayToObject($this->getArray());
1932
    }
1933
1934
    /**
1935
     * alias: for "Arrayy->randomImmutable()"
1936
     *
1937
     * @return static
1938
     *                <p>(Immutable)</p>
1939
     *
1940
     * @see Arrayy::randomImmutable()
1941
     */
1942 4
    public function getRandom(): self
1943
    {
1944 4
        return $this->randomImmutable();
1945
    }
1946
1947
    /**
1948
     * alias: for "Arrayy->randomKey()"
1949
     *
1950
     * @return mixed
1951
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
1952
     *
1953
     * @see Arrayy::randomKey()
1954
     */
1955 3
    public function getRandomKey()
1956
    {
1957 3
        return $this->randomKey();
1958
    }
1959
1960
    /**
1961
     * alias: for "Arrayy->randomKeys()"
1962
     *
1963
     * @param int $number
1964
     *
1965
     * @return static
1966
     *                <p>(Immutable)</p>
1967
     *
1968
     * @see Arrayy::randomKeys()
1969
     */
1970 8
    public function getRandomKeys(int $number): self
1971
    {
1972 8
        return $this->randomKeys($number);
1973
    }
1974
1975
    /**
1976
     * alias: for "Arrayy->randomValue()"
1977
     *
1978
     * @return mixed
1979
     *               <p>Get a random value or null if there wasn't a value.</p>
1980
     *
1981
     * @see Arrayy::randomValue()
1982
     */
1983 3
    public function getRandomValue()
1984
    {
1985 3
        return $this->randomValue();
1986
    }
1987
1988
    /**
1989
     * alias: for "Arrayy->randomValues()"
1990
     *
1991
     * @param int $number
1992
     *
1993
     * @return static
1994
     *                <p>(Immutable)</p>
1995
     *
1996
     * @see Arrayy::randomValues()
1997
     */
1998 6
    public function getRandomValues(int $number): self
1999
    {
2000 6
        return $this->randomValues($number);
2001
    }
2002
2003
    /**
2004
     * Group values from a array according to the results of a closure.
2005
     *
2006
     * @param callable|string $grouper  <p>A callable function name.</p>
2007
     * @param bool            $saveKeys
2008
     *
2009
     * @return static
2010
     *                <p>(Immutable)</p>
2011
     */
2012 4
    public function group($grouper, bool $saveKeys = false): self
2013
    {
2014
        // init
2015 4
        $result = [];
2016
2017
        // Iterate over values, group by property/results from closure.
2018 4
        foreach ($this->getGenerator() as $key => $value) {
2019 4
            if (\is_callable($grouper)) {
2020 3
                $groupKey = $grouper($value, $key);
2021
            } else {
2022 1
                $groupKey = $this->get($grouper, null, $this->getArray());
2023
            }
2024
2025 4
            $newValue = $this->get($groupKey, null, $result);
2026
2027 4
            if ($groupKey instanceof self) {
2028
                $groupKey = $groupKey->getArray();
2029
            }
2030
2031 4
            if ($newValue instanceof self) {
2032 4
                $newValue = $newValue->getArray();
2033
            }
2034
2035
            // Add to results.
2036 4
            if ($groupKey !== null) {
2037 3
                if ($saveKeys) {
2038 2
                    $result[$groupKey] = $newValue;
2039 2
                    $result[$groupKey][$key] = $value;
2040
                } else {
2041 1
                    $result[$groupKey] = $newValue;
2042 4
                    $result[$groupKey][] = $value;
2043
                }
2044
            }
2045
        }
2046
2047 4
        return static::create(
2048 4
            $result,
2049 4
            $this->iteratorClass,
2050 4
            false
2051
        );
2052
    }
2053
2054
    /**
2055
     * Check if an array has a given key.
2056
     *
2057
     * @param mixed $key
2058
     *
2059
     * @return bool
2060
     */
2061 23
    public function has($key): bool
2062
    {
2063 23
        static $UN_FOUND = null;
2064
2065 23
        if ($UN_FOUND === null) {
2066
            // Generate unique string to use as marker.
2067 1
            $UN_FOUND = \uniqid('arrayy', true);
2068
        }
2069
2070 23
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2071
    }
2072
2073
    /**
2074
     * Implodes the values of this array.
2075
     *
2076
     * @param string $glue
2077
     *
2078
     * @return string
2079
     */
2080 27
    public function implode(string $glue = ''): string
2081
    {
2082 27
        return $this->implode_recursive($glue, $this->getArray(), false);
2083
    }
2084
2085
    /**
2086
     * Implodes the keys of this array.
2087
     *
2088
     * @param string $glue
2089
     *
2090
     * @return string
2091
     */
2092 8
    public function implodeKeys(string $glue = ''): string
2093
    {
2094 8
        return $this->implode_recursive($glue, $this->getArray(), true);
2095
    }
2096
2097
    /**
2098
     * Given a list and an iterate-function that returns
2099
     * a key for each element in the list (or a property name),
2100
     * returns an object with an index of each item.
2101
     *
2102
     * @param mixed $key
2103
     *
2104
     * @return static
2105
     *                <p>(Immutable)</p>
2106
     */
2107 4
    public function indexBy($key): self
2108
    {
2109
        // init
2110 4
        $results = [];
2111
2112 4
        foreach ($this->getGenerator() as $a) {
2113 4
            if (\array_key_exists($key, $a) === true) {
2114 4
                $results[$a[$key]] = $a;
2115
            }
2116
        }
2117
2118 4
        return static::create(
2119 4
            $results,
2120 4
            $this->iteratorClass,
2121 4
            false
2122
        );
2123
    }
2124
2125
    /**
2126
     * alias: for "Arrayy->searchIndex()"
2127
     *
2128
     * @param mixed $value <p>The value to search for.</p>
2129
     *
2130
     * @return mixed
2131
     *
2132
     * @see Arrayy::searchIndex()
2133
     */
2134 4
    public function indexOf($value)
2135
    {
2136 4
        return $this->searchIndex($value);
2137
    }
2138
2139
    /**
2140
     * Get everything but the last..$to items.
2141
     *
2142
     * @param int $to
2143
     *
2144
     * @return static
2145
     *                <p>(Immutable)</p>
2146
     */
2147 12
    public function initial(int $to = 1): self
2148
    {
2149 12
        return $this->firstsImmutable(\count($this->getArray(), \COUNT_NORMAL) - $to);
2150
    }
2151
2152
    /**
2153
     * Return an array with all elements found in input array.
2154
     *
2155
     * @param array $search
2156
     * @param bool  $keepKeys
2157
     *
2158
     * @return static
2159
     *                <p>(Immutable)</p>
2160
     */
2161 3
    public function intersection(array $search, bool $keepKeys = false): self
2162
    {
2163 3
        if ($keepKeys) {
2164 1
            return static::create(
2165 1
                \array_uintersect(
2166 1
                    $this->array,
2167 1
                    $search,
2168 1
                    static function ($a, $b) {
2169 1
                        return $a === $b ? 0 : -1;
2170 1
                    }
2171
                ),
2172 1
                $this->iteratorClass,
2173 1
                false
2174
            );
2175
        }
2176
2177 2
        return static::create(
2178 2
            \array_values(\array_intersect($this->getArray(), $search)),
2179 2
            $this->iteratorClass,
2180 2
            false
2181
        );
2182
    }
2183
2184
    /**
2185
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
2186
     *
2187
     * @param array $search
2188
     *
2189
     * @return bool
2190
     */
2191 1
    public function intersects(array $search): bool
2192
    {
2193 1
        return \count($this->intersection($search)->array, \COUNT_NORMAL) > 0;
2194
    }
2195
2196
    /**
2197
     * Invoke a function on all of an array's values.
2198
     *
2199
     * @param callable $callable
2200
     * @param mixed    $arguments
2201
     *
2202
     * @return static
2203
     *                <p>(Immutable)</p>
2204
     */
2205 1
    public function invoke($callable, $arguments = []): self
2206
    {
2207
        // If one argument given for each iteration, create an array for it.
2208 1
        if (!\is_array($arguments)) {
2209 1
            $arguments = StaticArrayy::repeat(
2210 1
                $arguments,
2211 1
                \count($this->getArray(), \COUNT_NORMAL)
2212 1
            )->getArray();
2213
        }
2214
2215
        // If the callable has arguments, pass them.
2216 1
        if ($arguments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arguments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2217 1
            $array = \array_map($callable, $this->getArray(), $arguments);
2218
        } else {
2219 1
            $array = $this->map($callable);
2220
        }
2221
2222 1
        return static::create(
2223 1
            $array,
2224 1
            $this->iteratorClass,
2225 1
            false
2226
        );
2227
    }
2228
2229
    /**
2230
     * Check whether array is associative or not.
2231
     *
2232
     * @param bool $recursive
2233
     *
2234
     * @return bool
2235
     *              <p>Returns true if associative, false otherwise.</p>
2236
     */
2237 15
    public function isAssoc(bool $recursive = false): bool
2238
    {
2239 15
        if ($this->isEmpty()) {
2240 3
            return false;
2241
        }
2242
2243 13
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2244 13
            if (!\is_string($key)) {
2245 13
                return false;
2246
            }
2247
        }
2248
2249 3
        return true;
2250
    }
2251
2252
    /**
2253
     * Check whether the array is empty or not.
2254
     *
2255
     * @return bool
2256
     *              <p>Returns true if empty, false otherwise.</p>
2257
     */
2258 38
    public function isEmpty(): bool
2259
    {
2260 38
        if ($this->generator) {
2261
            return $this->getArray() === [];
2262
        }
2263
2264 38
        return $this->array === [];
2265
    }
2266
2267
    /**
2268
     * Check if the current array is equal to the given "$array" or not.
2269
     *
2270
     * @param array $array
2271
     *
2272
     * @return bool
2273
     */
2274
    public function isEqual(array $array): bool
2275
    {
2276
        return $this->getArray() === $array;
2277
    }
2278
2279
    /**
2280
     * Check if the current array is a multi-array.
2281
     *
2282
     * @return bool
2283
     */
2284 14
    public function isMultiArray(): bool
2285
    {
2286
        return !(
2287 14
            \count($this->getArray(), \COUNT_NORMAL)
2288
            ===
2289 14
            \count($this->getArray(), \COUNT_RECURSIVE)
2290
        );
2291
    }
2292
2293
    /**
2294
     * Check whether array is numeric or not.
2295
     *
2296
     * @return bool
2297
     *              <p>Returns true if numeric, false otherwise.</p>
2298
     */
2299 5
    public function isNumeric(): bool
2300
    {
2301 5
        if ($this->isEmpty()) {
2302 2
            return false;
2303
        }
2304
2305 4
        foreach ($this->keys()->getGenerator() as $key) {
2306 4
            if (!\is_int($key)) {
2307 4
                return false;
2308
            }
2309
        }
2310
2311 2
        return true;
2312
    }
2313
2314
    /**
2315
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2316
     *
2317
     * @param bool $recursive
2318
     *
2319
     * @return bool
2320
     */
2321 1
    public function isSequential(bool $recursive = false): bool
2322
    {
2323
2324
        // recursive
2325
2326 1
        if ($recursive === true) {
2327
            return $this->array_keys_recursive($this->getArray())
2328
                   ===
2329
                   \range(0, \count($this->getArray(), \COUNT_RECURSIVE) - 1);
2330
        }
2331
2332
        // non recursive
2333
2334 1
        return \array_keys($this->getArray())
2335
               ===
2336 1
               \range(0, \count($this->getArray(), \COUNT_NORMAL) - 1);
2337
    }
2338
2339
    /**
2340
     * @return array
2341
     */
2342
    public function jsonSerialize(): array
2343
    {
2344
        return $this->getArray();
2345
    }
2346
2347
    /**
2348
     * Get all keys from the current array.
2349
     *
2350
     * @param bool  $recursive    [optional] <p>
2351
     *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2352
     *                            </p>
2353
     * @param mixed $search_value [optional] <p>
2354
     *                            If specified, then only keys containing these values are returned.
2355
     *                            </p>
2356
     * @param bool  $strict       [optional] <p>
2357
     *                            Determines if strict comparison (===) should be used during the search.
2358
     *                            </p>
2359
     *
2360
     * @return static
2361
     *                <p>(Immutable) An array of all the keys in input.</p>
2362
     */
2363 26
    public function keys(bool $recursive = false, $search_value = null, bool $strict = true): self
2364
    {
2365
2366
        // recursive
2367
2368 26
        if ($recursive === true) {
2369 3
            if ($search_value === null) {
2370 3
                $array = $this->array_keys_recursive($this->getArray());
2371
            } else {
2372
                $array = $this->array_keys_recursive($this->getArray(), $search_value, $strict);
2373
            }
2374
2375 3
            return static::create(
2376 3
                $array,
2377 3
                $this->iteratorClass,
2378 3
                false
2379
            );
2380
        }
2381
2382
        // non recursive
2383
2384 25
        if ($search_value === null) {
2385 25
            $arrayFunction = function () {
2386 25
                foreach ($this->getGenerator() as $key => $value) {
2387 24
                    yield $key;
2388
                }
2389 25
            };
2390
        } else {
2391
            $arrayFunction = function () use ($search_value, $strict) {
2392
                foreach ($this->getGenerator() as $key => $value) {
2393
                    if ($strict) {
2394
                        if ($search_value === $value) {
2395
                            yield $key;
2396
                        }
2397
                    } else {
2398
                        /** @noinspection NestedPositiveIfStatementsInspection */
2399
                        if ($search_value == $value) {
2400
                            yield $key;
2401
                        }
2402
                    }
2403
                }
2404
            };
2405
        }
2406
2407 25
        return static::create(
2408 25
            $arrayFunction,
2409 25
            $this->iteratorClass,
2410 25
            false
2411
        );
2412
    }
2413
2414
    /**
2415
     * Sort an array by key in reverse order.
2416
     *
2417
     * @param int $sort_flags [optional] <p>
2418
     *                        You may modify the behavior of the sort using the optional
2419
     *                        parameter sort_flags, for details
2420
     *                        see sort.
2421
     *                        </p>
2422
     *
2423
     * @return static
2424
     *                <p>(Mutable) Return this Arrayy object.</p>
2425
     */
2426 4
    public function krsort(int $sort_flags = 0): self
2427
    {
2428 4
        $this->generatorToArray();
2429
2430 4
        \krsort($this->array, $sort_flags);
2431
2432 4
        return $this;
2433
    }
2434
2435
    /**
2436
     * Get the last value from the current array.
2437
     *
2438
     * @return mixed
2439
     *               <p>Return null if there wasn't a element.</p>
2440
     */
2441 4
    public function last()
2442
    {
2443 4
        return $this->pop();
2444
    }
2445
2446
    /**
2447
     * Get the last value(s) from the current array.
2448
     *
2449
     * @param int|null $number
2450
     *
2451
     * @return static
2452
     *                <p>(Immutable)</p>
2453
     */
2454 13
    public function lastsImmutable(int $number = null): self
2455
    {
2456 13
        if ($this->isEmpty()) {
2457 1
            return static::create(
2458 1
                [],
2459 1
                $this->iteratorClass,
2460 1
                false
2461
            );
2462
        }
2463
2464 12
        if ($number === null) {
2465 8
            $poppedValue = $this->pop();
2466
2467 8
            if ($poppedValue === null) {
2468 1
                $poppedValue = [$poppedValue];
2469
            } else {
2470 7
                $poppedValue = (array) $poppedValue;
2471
            }
2472
2473 8
            $arrayy = static::create(
2474 8
                $poppedValue,
2475 8
                $this->iteratorClass,
2476 8
                false
2477
            );
2478
        } else {
2479 4
            $number = (int) $number;
2480 4
            $arrayy = $this->rest(-$number);
2481
        }
2482
2483 12
        return $arrayy;
2484
    }
2485
2486
    /**
2487
     * Get the last value(s) from the current array.
2488
     *
2489
     * @param int|null $number
2490
     *
2491
     * @return static
2492
     *                <p>(Mutable)</p>
2493
     */
2494 13
    public function lastsMutable(int $number = null): self
2495
    {
2496 13
        if ($this->isEmpty()) {
2497 1
            return $this;
2498
        }
2499
2500 12
        if ($number === null) {
2501 8
            $poppedValue = $this->pop();
2502
2503 8
            if ($poppedValue === null) {
2504 1
                $poppedValue = [$poppedValue];
2505
            } else {
2506 7
                $poppedValue = (array) $poppedValue;
2507
            }
2508
2509 8
            $this->array = static::create(
2510 8
                $poppedValue,
2511 8
                $this->iteratorClass,
2512 8
                false
2513 8
            )->getArray();
2514
        } else {
2515 4
            $number = (int) $number;
2516 4
            $this->array = $this->rest(-$number)->getArray();
2517
        }
2518
2519 12
        $this->generator = null;
2520
2521 12
        return $this;
2522
    }
2523
2524
    /**
2525
     * Count the values from the current array.
2526
     *
2527
     * alias: for "Arrayy->count()"
2528
     *
2529
     * @param int $mode
2530
     *
2531
     * @return int
2532
     *
2533
     * @see Arrayy::count()
2534
     */
2535 20
    public function length(int $mode = \COUNT_NORMAL): int
2536
    {
2537 20
        return $this->count($mode);
2538
    }
2539
2540
    /**
2541
     * Apply the given function to the every element of the array,
2542
     * collecting the results.
2543
     *
2544
     * @param callable $callable
2545
     * @param bool     $useKeyAsSecondParameter
2546
     * @param mixed    ...$arguments
2547
     *
2548
     * @return static
2549
     *                <p>(Immutable) Arrayy object with modified elements.</p>
2550
     */
2551 5
    public function map(callable $callable, bool $useKeyAsSecondParameter = false, ...$arguments): self
2552
    {
2553 5
        $useArguments = \func_num_args() > 2;
2554
2555 5
        return static::create(
2556 5
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
2557 5
                foreach ($this->getGenerator() as $key => $value) {
2558 4
                    if ($useArguments) {
2559 3
                        if ($useKeyAsSecondParameter) {
2560
                            yield $key => $callable($value, $key, ...$arguments);
2561
                        } else {
2562 3
                            yield $key => $callable($value, ...$arguments);
2563
                        }
2564
                    } else {
2565
                        /** @noinspection NestedPositiveIfStatementsInspection */
2566 4
                        if ($useKeyAsSecondParameter) {
2567
                            yield $key => $callable($value, $key);
2568
                        } else {
2569 4
                            yield $key => $callable($value);
2570
                        }
2571
                    }
2572
                }
2573 5
            },
2574 5
            $this->iteratorClass,
2575 5
            false
2576
        );
2577
    }
2578
2579
    /**
2580
     * Check if all items in current array match a truth test.
2581
     *
2582
     * @param \Closure $closure
2583
     *
2584
     * @return bool
2585
     */
2586 15 View Code Duplication
    public function matches(\Closure $closure): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2587
    {
2588 15
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2589 2
            return false;
2590
        }
2591
2592 13
        foreach ($this->getGenerator() as $key => $value) {
2593 13
            $value = $closure($value, $key);
2594
2595 13
            if ($value === false) {
2596 13
                return false;
2597
            }
2598
        }
2599
2600 7
        return true;
2601
    }
2602
2603
    /**
2604
     * Check if any item in the current array matches a truth test.
2605
     *
2606
     * @param \Closure $closure
2607
     *
2608
     * @return bool
2609
     */
2610 14 View Code Duplication
    public function matchesAny(\Closure $closure): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2611
    {
2612 14
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2613 2
            return false;
2614
        }
2615
2616 12
        foreach ($this->getGenerator() as $key => $value) {
2617 12
            $value = $closure($value, $key);
2618
2619 12
            if ($value === true) {
2620 12
                return true;
2621
            }
2622
        }
2623
2624 4
        return false;
2625
    }
2626
2627
    /**
2628
     * Get the max value from an array.
2629
     *
2630
     * @return mixed
2631
     */
2632 10 View Code Duplication
    public function max()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2633
    {
2634 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2635 1
            return false;
2636
        }
2637
2638 9
        return \max($this->getArray());
2639
    }
2640
2641
    /**
2642
     * Merge the new $array into the current array.
2643
     *
2644
     * - keep key,value from the current array, also if the index is in the new $array
2645
     *
2646
     * @param array $array
2647
     * @param bool  $recursive
2648
     *
2649
     * @return static
2650
     *                <p>(Immutable)</p>
2651
     */
2652 25 View Code Duplication
    public function mergeAppendKeepIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2653
    {
2654 25
        if ($recursive === true) {
2655 4
            $result = \array_replace_recursive($this->getArray(), $array);
2656
        } else {
2657 21
            $result = \array_replace($this->getArray(), $array);
2658
        }
2659
2660 25
        return static::create(
2661 25
            $result,
2662 25
            $this->iteratorClass,
2663 25
            false
2664
        );
2665
    }
2666
2667
    /**
2668
     * Merge the new $array into the current array.
2669
     *
2670
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2671
     * - create new indexes
2672
     *
2673
     * @param array $array
2674
     * @param bool  $recursive
2675
     *
2676
     * @return static
2677
     *                <p>(Immutable)</p>
2678
     */
2679 16 View Code Duplication
    public function mergeAppendNewIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2680
    {
2681 16
        if ($recursive === true) {
2682 4
            $result = \array_merge_recursive($this->getArray(), $array);
2683
        } else {
2684 12
            $result = \array_merge($this->getArray(), $array);
2685
        }
2686
2687 16
        return static::create(
2688 16
            $result,
2689 16
            $this->iteratorClass,
2690 16
            false
2691
        );
2692
    }
2693
2694
    /**
2695
     * Merge the the current array into the $array.
2696
     *
2697
     * - use key,value from the new $array, also if the index is in the current array
2698
     *
2699
     * @param array $array
2700
     * @param bool  $recursive
2701
     *
2702
     * @return static
2703
     *                <p>(Immutable)</p>
2704
     */
2705 16 View Code Duplication
    public function mergePrependKeepIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2706
    {
2707 16
        if ($recursive === true) {
2708 4
            $result = \array_replace_recursive($array, $this->getArray());
2709
        } else {
2710 12
            $result = \array_replace($array, $this->getArray());
2711
        }
2712
2713 16
        return static::create(
2714 16
            $result,
2715 16
            $this->iteratorClass,
2716 16
            false
2717
        );
2718
    }
2719
2720
    /**
2721
     * Merge the current array into the new $array.
2722
     *
2723
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
2724
     * - create new indexes
2725
     *
2726
     * @param array $array
2727
     * @param bool  $recursive
2728
     *
2729
     * @return static
2730
     *                <p>(Immutable)</p>
2731
     */
2732 17 View Code Duplication
    public function mergePrependNewIndex(array $array = [], bool $recursive = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2733
    {
2734 17
        if ($recursive === true) {
2735 4
            $result = \array_merge_recursive($array, $this->getArray());
2736
        } else {
2737 13
            $result = \array_merge($array, $this->getArray());
2738
        }
2739
2740 17
        return static::create(
2741 17
            $result,
2742 17
            $this->iteratorClass,
2743 17
            false
2744
        );
2745
    }
2746
2747
    /**
2748
     * @return ArrayyMeta|static
2749
     */
2750 14
    public static function meta()
2751
    {
2752 14
        return (new ArrayyMeta())->getMetaObject(static::class);
2753
    }
2754
2755
    /**
2756
     * Get the min value from an array.
2757
     *
2758
     * @return mixed
2759
     */
2760 10 View Code Duplication
    public function min()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2761
    {
2762 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2763 1
            return false;
2764
        }
2765
2766 9
        return \min($this->getArray());
2767
    }
2768
2769
    /**
2770
     * Move an array element to a new index.
2771
     *
2772
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2773
     *
2774
     * @param int|string $from
2775
     * @param int        $to
2776
     *
2777
     * @return static
2778
     *                <p>(Immutable)</p>
2779
     */
2780 1
    public function moveElement($from, $to): self
2781
    {
2782 1
        $array = $this->getArray();
2783
2784 1
        if (\is_int($from)) {
2785 1
            $tmp = \array_splice($array, $from, 1);
2786 1
            \array_splice($array, (int) $to, 0, $tmp);
2787 1
            $output = $array;
2788 1
        } elseif (\is_string($from)) {
2789 1
            $indexToMove = \array_search($from, \array_keys($array), true);
2790 1
            $itemToMove = $array[$from];
2791 1
            if ($indexToMove !== false) {
2792 1
                \array_splice($array, $indexToMove, 1);
2793
            }
2794 1
            $i = 0;
2795 1
            $output = [];
2796 1
            foreach ($array as $key => $item) {
2797 1
                if ($i === $to) {
2798 1
                    $output[$from] = $itemToMove;
2799
                }
2800 1
                $output[$key] = $item;
2801 1
                ++$i;
2802
            }
2803
        } else {
2804
            $output = [];
2805
        }
2806
2807 1
        return static::create(
2808 1
            $output,
2809 1
            $this->iteratorClass,
2810 1
            false
2811
        );
2812
    }
2813
2814
    /**
2815
     * Get a subset of the items from the given array.
2816
     *
2817
     * @param mixed[] $keys
2818
     *
2819
     * @return static
2820
     *                <p>(Immutable)</p>
2821
     */
2822
    public function only(array $keys): self
2823
    {
2824
        $array = $this->getArray();
2825
2826
        return static::create(
2827
            \array_intersect_key($array, \array_flip($keys)),
2828
            $this->iteratorClass,
2829
            false
2830
        );
2831
    }
2832
2833
    /**
2834
     * Pad array to the specified size with a given value.
2835
     *
2836
     * @param int   $size  <p>Size of the result array.</p>
2837
     * @param mixed $value <p>Empty value by default.</p>
2838
     *
2839
     * @return static
2840
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
2841
     */
2842 4
    public function pad(int $size, $value): self
2843
    {
2844 4
        return static::create(
2845 4
            \array_pad($this->getArray(), $size, $value),
2846 4
            $this->iteratorClass,
2847 4
            false
2848
        );
2849
    }
2850
2851
    /**
2852
     * Pop a specified value off the end of the current array.
2853
     *
2854
     * @return mixed
2855
     *               <p>(Mutable) The popped element from the current array.</p>
2856
     */
2857 16
    public function pop()
2858
    {
2859 16
        $this->generatorToArray();
2860
2861 16
        return \array_pop($this->array);
2862
    }
2863
2864
    /**
2865
     * Prepend a (key) + value to the current array.
2866
     *
2867
     * @param mixed $value
2868
     * @param mixed $key
2869
     *
2870
     * @return static
2871
     *                <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2872
     */
2873 8
    public function prepend($value, $key = null): self
2874
    {
2875 8
        $this->generatorToArray();
2876
2877 8
        if ($key === null) {
2878 8
            \array_unshift($this->array, $value);
2879
        } else {
2880
            /** @noinspection AdditionOperationOnArraysInspection */
2881 1
            $this->array = [$key => $value] + $this->array;
2882
        }
2883
2884 8
        return $this;
2885
    }
2886
2887
    /**
2888
     * Add a suffix to each key.
2889
     *
2890
     * @param mixed $suffix
2891
     *
2892
     * @return static
2893
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2894
     */
2895 10 View Code Duplication
    public function prependToEachKey($suffix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2896
    {
2897
        // init
2898 10
        $result = [];
2899
2900 10
        foreach ($this->getGenerator() as $key => $item) {
2901 9
            if ($item instanceof self) {
2902
                $result[$key] = $item->prependToEachKey($suffix);
2903 9
            } elseif (\is_array($item)) {
2904
                $result[$key] = self::create(
2905
                    $item,
2906
                    $this->iteratorClass,
2907
                    false
2908
                )->prependToEachKey($suffix)
2909
                    ->toArray();
2910
            } else {
2911 9
                $result[$key . $suffix] = $item;
2912
            }
2913
        }
2914
2915 10
        return self::create(
2916 10
            $result,
2917 10
            $this->iteratorClass,
2918 10
            false
2919
        );
2920
    }
2921
2922
    /**
2923
     * Add a suffix to each value.
2924
     *
2925
     * @param mixed $suffix
2926
     *
2927
     * @return static
2928
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2929
     */
2930 10 View Code Duplication
    public function prependToEachValue($suffix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2931
    {
2932
        // init
2933 10
        $result = [];
2934
2935 10
        foreach ($this->getGenerator() as $key => $item) {
2936 9
            if ($item instanceof self) {
2937
                $result[$key] = $item->prependToEachValue($suffix);
2938 9
            } elseif (\is_array($item)) {
2939
                $result[$key] = self::create(
2940
                    $item,
2941
                    $this->iteratorClass,
2942
                    false
2943
                )->prependToEachValue($suffix)
2944
                    ->toArray();
2945 9
            } elseif (\is_object($item)) {
2946 1
                $result[$key] = $item;
2947
            } else {
2948 9
                $result[$key] = $item . $suffix;
2949
            }
2950
        }
2951
2952 10
        return self::create(
2953 10
            $result,
2954 10
            $this->iteratorClass,
2955 10
            false
2956
        );
2957
    }
2958
2959
    /**
2960
     * Push one or more values onto the end of array at once.
2961
     *
2962
     * @return static
2963
     *                <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2964
     */
2965 4 View Code Duplication
    public function push(/* variadic arguments allowed */): 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...
2966
    {
2967 4
        $this->generatorToArray();
2968
2969 4
        if (\func_num_args()) {
2970 4
            $args = \func_get_args();
2971 4
            \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...
2972
        }
2973
2974 4
        return $this;
2975
    }
2976
2977
    /**
2978
     * Get a random value from the current array.
2979
     *
2980
     * @param int|null $number <p>How many values you will take?</p>
2981
     *
2982
     * @return static
2983
     *                <p>(Immutable)</p>
2984
     */
2985 18
    public function randomImmutable(int $number = null): self
2986
    {
2987 18
        $this->generatorToArray();
2988
2989 18 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...
2990 1
            return static::create(
2991 1
                [],
2992 1
                $this->iteratorClass,
2993 1
                false
2994
            );
2995
        }
2996
2997 17 View Code Duplication
        if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2998
            /** @noinspection NonSecureArrayRandUsageInspection */
2999 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3000
3001 13
            return static::create(
3002 13
                $arrayRandValue,
3003 13
                $this->iteratorClass,
3004 13
                false
3005
            );
3006
        }
3007
3008 5
        $arrayTmp = $this->array;
3009
        /** @noinspection NonSecureShuffleUsageInspection */
3010 5
        \shuffle($arrayTmp);
3011
3012 5
        return static::create(
3013 5
            $arrayTmp,
3014 5
            $this->iteratorClass,
3015 5
            false
3016 5
        )->firstsImmutable($number);
3017
    }
3018
3019
    /**
3020
     * Pick a random key/index from the keys of this array.
3021
     *
3022
     * @throws \RangeException If array is empty
3023
     *
3024
     * @return mixed
3025
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
3026
     */
3027 4
    public function randomKey()
3028
    {
3029 4
        $result = $this->randomKeys(1);
3030
3031 4
        if (!isset($result[0])) {
3032
            $result[0] = null;
3033
        }
3034
3035 4
        return $result[0];
3036
    }
3037
3038
    /**
3039
     * Pick a given number of random keys/indexes out of this array.
3040
     *
3041
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
3042
     *
3043
     * @throws \RangeException If array is empty
3044
     *
3045
     * @return static
3046
     *                <p>(Immutable)</p>
3047
     */
3048 13
    public function randomKeys(int $number): self
3049
    {
3050 13
        $this->generatorToArray();
3051
3052 13
        $count = \count($this->array, \COUNT_NORMAL);
3053
3054 13
        if ($number === 0 || $number > $count) {
3055 2
            throw new \RangeException(
3056 2
                \sprintf(
3057 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
3058 2
                    $number,
3059 2
                    $count
3060
                )
3061
            );
3062
        }
3063
3064 11
        $result = (array) \array_rand($this->array, $number);
3065
3066 11
        return static::create(
3067 11
            $result,
3068 11
            $this->iteratorClass,
3069 11
            false
3070
        );
3071
    }
3072
3073
    /**
3074
     * Get a random value from the current array.
3075
     *
3076
     * @param int|null $number <p>How many values you will take?</p>
3077
     *
3078
     * @return static
3079
     *                <p>(Mutable)</p>
3080
     */
3081 17
    public function randomMutable(int $number = null): self
3082
    {
3083 17
        $this->generatorToArray();
3084
3085 17 View Code Duplication
        if (\count($this->array, \COUNT_NORMAL) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3086
            return static::create(
3087
                [],
3088
                $this->iteratorClass,
3089
                false
3090
            );
3091
        }
3092
3093 17 View Code Duplication
        if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
3094
            /** @noinspection NonSecureArrayRandUsageInspection */
3095 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3096 7
            $this->array = $arrayRandValue;
3097
3098 7
            return $this;
3099
        }
3100
3101
        /** @noinspection NonSecureShuffleUsageInspection */
3102 11
        \shuffle($this->array);
3103
3104 11
        return $this->firstsMutable($number);
3105
    }
3106
3107
    /**
3108
     * Pick a random value from the values of this array.
3109
     *
3110
     * @return mixed
3111
     *               <p>Get a random value or null if there wasn't a value.</p>
3112
     */
3113 4
    public function randomValue()
3114
    {
3115 4
        $result = $this->randomImmutable();
3116
3117 4
        if (!isset($result[0])) {
3118
            $result[0] = null;
3119
        }
3120
3121 4
        return $result[0];
3122
    }
3123
3124
    /**
3125
     * Pick a given number of random values out of this array.
3126
     *
3127
     * @param int $number
3128
     *
3129
     * @return static
3130
     *                <p>(Mutable)</p>
3131
     */
3132 7
    public function randomValues(int $number): self
3133
    {
3134 7
        return $this->randomMutable($number);
3135
    }
3136
3137
    /**
3138
     * Get a random value from an array, with the ability to skew the results.
3139
     *
3140
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3141
     *
3142
     * @param array    $array
3143
     * @param int|null $number <p>How many values you will take?</p>
3144
     *
3145
     * @return static
3146
     *                <p>(Immutable)</p>
3147
     */
3148 9
    public function randomWeighted(array $array, int $number = null): self
3149
    {
3150
        // init
3151 9
        $options = [];
3152
3153 9
        foreach ($array as $option => $weight) {
3154 9
            if ($this->searchIndex($option) !== false) {
3155 9
                for ($i = 0; $i < $weight; ++$i) {
3156 1
                    $options[] = $option;
3157
                }
3158
            }
3159
        }
3160
3161 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3162
    }
3163
3164
    /**
3165
     * Reduce the current array via callable e.g. anonymous-function.
3166
     *
3167
     * @param callable $callable
3168
     * @param array    $init
3169
     *
3170
     * @return static
3171
     *                <p>(Immutable)</p>
3172
     */
3173 16
    public function reduce($callable, array $init = []): self
3174
    {
3175 16
        if ($this->generator) {
3176 1
            $result = $init;
3177
3178 1
            foreach ($this->getGenerator() as $value) {
3179 1
                $result = $callable($result, $value);
3180
            }
3181
3182 1
            return static::create(
3183 1
                $result,
3184 1
                $this->iteratorClass,
3185 1
                false
3186
            );
3187
        }
3188
3189 16
        $result = \array_reduce($this->array, $callable, $init);
3190
3191 16
        if ($result === null) {
3192
            $this->array = [];
3193
        } else {
3194 16
            $this->array = (array) $result;
3195
        }
3196
3197 16
        return static::create(
3198 16
            $this->array,
3199 16
            $this->iteratorClass,
3200 16
            false
3201
        );
3202
    }
3203
3204
    /**
3205
     * Create a numerically re-indexed Arrayy object.
3206
     *
3207
     * @return static
3208
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
3209
     */
3210 9
    public function reindex(): self
3211
    {
3212 9
        $this->generatorToArray();
3213
3214 9
        $this->array = \array_values($this->array);
3215
3216 9
        return $this;
3217
    }
3218
3219
    /**
3220
     * Return all items that fail the truth test.
3221
     *
3222
     * @param \Closure $closure
3223
     *
3224
     * @return static
3225
     *                <p>(Immutable)</p>
3226
     */
3227 1 View Code Duplication
    public function reject(\Closure $closure): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3228
    {
3229
        // init
3230 1
        $filtered = [];
3231
3232 1
        foreach ($this->getGenerator() as $key => $value) {
3233 1
            if (!$closure($value, $key)) {
3234 1
                $filtered[$key] = $value;
3235
            }
3236
        }
3237
3238 1
        return static::create(
3239 1
            $filtered,
3240 1
            $this->iteratorClass,
3241 1
            false
3242
        );
3243
    }
3244
3245
    /**
3246
     * Remove a value from the current array (optional using dot-notation).
3247
     *
3248
     * @param mixed $key
3249
     *
3250
     * @return static
3251
     *                <p>(Mutable)</p>
3252
     */
3253 18
    public function remove($key): self
3254
    {
3255
        // recursive call
3256 18
        if (\is_array($key)) {
3257
            foreach ($key as $k) {
3258
                $this->internalRemove($k);
3259
            }
3260
3261
            return static::create(
3262
                $this->getArray(),
3263
                $this->iteratorClass,
3264
                false
3265
            );
3266
        }
3267
3268 18
        $this->internalRemove($key);
3269
3270 18
        return static::create(
3271 18
            $this->getArray(),
3272 18
            $this->iteratorClass,
3273 18
            false
3274
        );
3275
    }
3276
3277
    /**
3278
     * Remove the first value from the current array.
3279
     *
3280
     * @return static
3281
     *                <p>(Immutable)</p>
3282
     */
3283 7 View Code Duplication
    public function removeFirst(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3284
    {
3285 7
        $tmpArray = $this->getArray();
3286
3287 7
        \array_shift($tmpArray);
3288
3289 7
        return static::create(
3290 7
            $tmpArray,
3291 7
            $this->iteratorClass,
3292 7
            false
3293
        );
3294
    }
3295
3296
    /**
3297
     * Remove the last value from the current array.
3298
     *
3299
     * @return static
3300
     *                <p>(Immutable)</p>
3301
     */
3302 7 View Code Duplication
    public function removeLast(): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3303
    {
3304 7
        $tmpArray = $this->getArray();
3305
3306 7
        \array_pop($tmpArray);
3307
3308 7
        return static::create(
3309 7
            $tmpArray,
3310 7
            $this->iteratorClass,
3311 7
            false
3312
        );
3313
    }
3314
3315
    /**
3316
     * Removes a particular value from an array (numeric or associative).
3317
     *
3318
     * @param mixed $value
3319
     *
3320
     * @return static
3321
     *                <p>(Immutable)</p>
3322
     */
3323 7
    public function removeValue($value): self
3324
    {
3325 7
        $this->generatorToArray();
3326
3327
        // init
3328 7
        $isNumericArray = true;
3329
3330 7
        foreach ($this->getGenerator() as $key => $item) {
3331 6
            if ($item === $value) {
3332 6
                if (!\is_int($key)) {
3333
                    $isNumericArray = false;
3334
                }
3335 6
                unset($this->array[$key]);
3336
            }
3337
        }
3338
3339 7
        if ($isNumericArray) {
3340 7
            $this->array = \array_values($this->array);
3341
        }
3342
3343 7
        return static::create(
3344 7
            $this->array,
3345 7
            $this->iteratorClass,
3346 7
            false
3347
        );
3348
    }
3349
3350
    /**
3351
     * Generate array of repeated arrays.
3352
     *
3353
     * @param int $times <p>How many times has to be repeated.</p>
3354
     *
3355
     * @return static
3356
     *                <p>(Immutable)</p>
3357
     */
3358 1
    public function repeat($times): self
3359
    {
3360 1
        if ($times === 0) {
3361 1
            return new static();
3362
        }
3363
3364 1
        return static::create(
3365 1
            \array_fill(0, (int) $times, $this->getArray()),
3366 1
            $this->iteratorClass,
3367 1
            false
3368
        );
3369
    }
3370
3371
    /**
3372
     * Replace a key with a new key/value pair.
3373
     *
3374
     * @param mixed $replace
3375
     * @param mixed $key
3376
     * @param mixed $value
3377
     *
3378
     * @return static
3379
     *                <p>(Immutable)</p>
3380
     */
3381 2
    public function replace($replace, $key, $value): self
3382
    {
3383 2
        $that = clone $this;
3384
3385 2
        return $that->remove($replace)
3386 2
            ->set($key, $value);
3387
    }
3388
3389
    /**
3390
     * Create an array using the current array as values and the other array as keys.
3391
     *
3392
     * @param array $keys <p>An array of keys.</p>
3393
     *
3394
     * @return static
3395
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
3396
     */
3397 2
    public function replaceAllKeys(array $keys): self
3398
    {
3399 2
        return static::create(
3400 2
            \array_combine($keys, $this->getArray()),
3401 2
            $this->iteratorClass,
3402 2
            false
3403
        );
3404
    }
3405
3406
    /**
3407
     * Create an array using the current array as keys and the other array as values.
3408
     *
3409
     * @param array $array <p>An array o values.</p>
3410
     *
3411
     * @return static
3412
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3413
     */
3414 2
    public function replaceAllValues(array $array): self
3415
    {
3416 2
        return static::create(
3417 2
            \array_combine($this->array, $array),
3418 2
            $this->iteratorClass,
3419 2
            false
3420
        );
3421
    }
3422
3423
    /**
3424
     * Replace the keys in an array with another set.
3425
     *
3426
     * @param array $keys <p>An array of keys matching the array's size</p>
3427
     *
3428
     * @return static
3429
     *                <p>(Immutable)</p>
3430
     */
3431 1
    public function replaceKeys(array $keys): self
3432
    {
3433 1
        $values = \array_values($this->getArray());
3434 1
        $result = \array_combine($keys, $values);
3435
3436 1
        return static::create(
3437 1
            $result,
3438 1
            $this->iteratorClass,
3439 1
            false
3440
        );
3441
    }
3442
3443
    /**
3444
     * Replace the first matched value in an array.
3445
     *
3446
     * @param mixed $search      <p>The value to replace.</p>
3447
     * @param mixed $replacement <p>The value to replace.</p>
3448
     *
3449
     * @return static
3450
     *                <p>(Immutable)</p>
3451
     */
3452 3
    public function replaceOneValue($search, $replacement = ''): self
3453
    {
3454 3
        $array = $this->getArray();
3455 3
        $key = \array_search($search, $array, true);
3456
3457 3
        if ($key !== false) {
3458 3
            $array[$key] = $replacement;
3459
        }
3460
3461 3
        return static::create(
3462 3
            $array,
3463 3
            $this->iteratorClass,
3464 3
            false
3465
        );
3466
    }
3467
3468
    /**
3469
     * Replace values in the current array.
3470
     *
3471
     * @param mixed $search      <p>The value to replace.</p>
3472
     * @param mixed $replacement <p>What to replace it with.</p>
3473
     *
3474
     * @return static
3475
     *                <p>(Immutable)</p>
3476
     */
3477 1
    public function replaceValues($search, $replacement = ''): self
3478
    {
3479 1
        $array = $this->each(
3480 1
            static function ($value) use ($search, $replacement) {
3481 1
                return \str_replace($search, $replacement, $value);
3482 1
            }
3483
        );
3484
3485 1
        return $array;
3486
    }
3487
3488
    /**
3489
     * Get the last elements from index $from until the end of this array.
3490
     *
3491
     * @param int $from
3492
     *
3493
     * @return static
3494
     *                <p>(Immutable)</p>
3495
     */
3496 15 View Code Duplication
    public function rest(int $from = 1): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3497
    {
3498 15
        $tmpArray = $this->getArray();
3499
3500 15
        return static::create(
3501 15
            \array_splice($tmpArray, $from),
3502 15
            $this->iteratorClass,
3503 15
            false
3504
        );
3505
    }
3506
3507
    /**
3508
     * Return the array in the reverse order.
3509
     *
3510
     * @return static
3511
     *                <p>(Mutable) Return this Arrayy object.</p>
3512
     */
3513 8
    public function reverse(): self
3514
    {
3515 8
        $this->generatorToArray();
3516
3517 8
        $this->array = \array_reverse($this->array);
3518
3519 8
        return $this;
3520
    }
3521
3522
    /**
3523
     * Sort an array in reverse order.
3524
     *
3525
     * @param int $sort_flags [optional] <p>
3526
     *                        You may modify the behavior of the sort using the optional
3527
     *                        parameter sort_flags, for details
3528
     *                        see sort.
3529
     *                        </p>
3530
     *
3531
     * @return static
3532
     *                <p>(Mutable) Return this Arrayy object.</p>
3533
     */
3534 4
    public function rsort(int $sort_flags = 0): self
3535
    {
3536 4
        $this->generatorToArray();
3537
3538 4
        \rsort($this->array, $sort_flags);
3539
3540 4
        return $this;
3541
    }
3542
3543
    /**
3544
     * Search for the first index of the current array via $value.
3545
     *
3546
     * @param mixed $value
3547
     *
3548
     * @return false|float|int|string
3549
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
3550
     */
3551 20
    public function searchIndex($value)
3552
    {
3553 20
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
3554 19
            if ($value === $valueFromArray) {
3555 19
                return $keyFromArray;
3556
            }
3557
        }
3558
3559 11
        return false;
3560
    }
3561
3562
    /**
3563
     * Search for the value of the current array via $index.
3564
     *
3565
     * @param mixed $index
3566
     *
3567
     * @return static
3568
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3569
     */
3570 9
    public function searchValue($index): self
3571
    {
3572 9
        $this->generatorToArray();
3573
3574
        // init
3575 9
        $return = [];
3576
3577 9
        if ($this->array === []) {
3578
            return static::create(
3579
                [],
3580
                $this->iteratorClass,
3581
                false
3582
            );
3583
        }
3584
3585
        // php cast "bool"-index into "int"-index
3586 9
        if ((bool) $index === $index) {
3587 1
            $index = (int) $index;
3588
        }
3589
3590 9
        if (\array_key_exists($index, $this->array) === true) {
3591 7
            $return = [$this->array[$index]];
3592
        }
3593
3594 9
        return static::create(
3595 9
            $return,
3596 9
            $this->iteratorClass,
3597 9
            false
3598
        );
3599
    }
3600
3601
    /**
3602
     * Set a value for the current array (optional using dot-notation).
3603
     *
3604
     * @param string $key   <p>The key to set.</p>
3605
     * @param mixed  $value <p>Its value.</p>
3606
     *
3607
     * @return static
3608
     *                <p>(Mutable)</p>
3609
     */
3610 18
    public function set($key, $value): self
3611
    {
3612 18
        $this->generatorToArray();
3613
3614 18
        $this->internalSet($key, $value);
3615
3616 18
        return $this;
3617
    }
3618
3619
    /**
3620
     * Get a value from a array and set it if it was not.
3621
     *
3622
     * WARNING: this method only set the value, if the $key is not already set
3623
     *
3624
     * @param mixed $key      <p>The key</p>
3625
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
3626
     *
3627
     * @return mixed
3628
     *               <p>(Mutable)</p>
3629
     */
3630 11
    public function setAndGet($key, $fallback = null)
3631
    {
3632 11
        $this->generatorToArray();
3633
3634
        // If the key doesn't exist, set it.
3635 11
        if (!$this->has($key)) {
3636 4
            $this->array = $this->set($key, $fallback)->getArray();
3637
        }
3638
3639 11
        return $this->get($key);
3640
    }
3641
3642
    /**
3643
     * Shifts a specified value off the beginning of array.
3644
     *
3645
     * @return mixed
3646
     *               <p>(Mutable) A shifted element from the current array.</p>
3647
     */
3648 4
    public function shift()
3649
    {
3650 4
        $this->generatorToArray();
3651
3652 4
        return \array_shift($this->array);
3653
    }
3654
3655
    /**
3656
     * Shuffle the current array.
3657
     *
3658
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3659
     * @param array $array  [optional]
3660
     *
3661
     * @return static
3662
     *                <p>(Immutable)</p>
3663
     */
3664 1
    public function shuffle(bool $secure = false, array $array = null): self
3665
    {
3666 1
        if ($array === null) {
3667 1
            $array = $this->getArray();
3668
        }
3669
3670 1
        if ($secure !== true) {
3671
            /** @noinspection NonSecureShuffleUsageInspection */
3672 1
            \shuffle($array);
3673
        } else {
3674 1
            $size = \count($array, \COUNT_NORMAL);
3675 1
            $keys = \array_keys($array);
3676 1
            for ($i = $size - 1; $i > 0; --$i) {
3677
                try {
3678 1
                    $r = \random_int(0, $i);
3679
                } catch (\Exception $e) {
3680
                    /** @noinspection RandomApiMigrationInspection */
3681
                    $r = \mt_rand(0, $i);
3682
                }
3683 1
                if ($r !== $i) {
3684 1
                    $temp = $array[$keys[$r]];
3685 1
                    $array[$keys[$r]] = $array[$keys[$i]];
3686 1
                    $array[$keys[$i]] = $temp;
3687
                }
3688
            }
3689
3690
            // reset indices
3691 1
            $array = \array_values($array);
3692
        }
3693
3694 1
        foreach ($array as $key => $value) {
3695
            // check if recursive is needed
3696 1
            if (\is_array($value) === true) {
3697 1
                $array[$key] = $this->shuffle($secure, $value);
3698
            }
3699
        }
3700
3701 1
        return static::create(
3702 1
            $array,
3703 1
            $this->iteratorClass,
3704 1
            false
3705
        );
3706
    }
3707
3708
    /**
3709
     * Checks whether array has exactly $size items.
3710
     *
3711
     * @param int $size
3712
     *
3713
     * @return bool
3714
     */
3715 1 View Code Duplication
    public function sizeIs(int $size): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3716
    {
3717
        // init
3718 1
        $itemsTempCount = 0;
3719
3720 1
        foreach ($this->getGenerator() as $key => $value) {
3721 1
            ++$itemsTempCount;
3722 1
            if ($itemsTempCount > $size) {
3723 1
                return false;
3724
            }
3725
        }
3726
3727 1
        return $itemsTempCount === $size;
3728
    }
3729
3730
    /**
3731
     * Checks whether array has less than $size items.
3732
     *
3733
     * @param int $size
3734
     *
3735
     * @return bool
3736
     */
3737 1 View Code Duplication
    public function sizeIsLessThan(int $size): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3738
    {
3739
        // init
3740 1
        $itemsTempCount = 0;
3741
3742 1
        foreach ($this->getGenerator() as $key => $value) {
3743 1
            ++$itemsTempCount;
3744 1
            if ($itemsTempCount > $size) {
3745 1
                return false;
3746
            }
3747
        }
3748
3749 1
        return $itemsTempCount < $size;
3750
    }
3751
3752
    /**
3753
     * Checks whether array has more than $size items.
3754
     *
3755
     * @param int $size
3756
     *
3757
     * @return bool
3758
     */
3759 1 View Code Duplication
    public function sizeIsGreaterThan(int $size): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3760
    {
3761
        // init
3762 1
        $itemsTempCount = 0;
3763
3764 1
        foreach ($this->getGenerator() as $key => $value) {
3765 1
            ++$itemsTempCount;
3766 1
            if ($itemsTempCount > $size) {
3767 1
                return true;
3768
            }
3769
        }
3770
3771 1
        return $itemsTempCount > $size;
3772
    }
3773
3774
    /**
3775
     * Checks whether array has between $fromSize to $toSize items. $toSize can be
3776
     * smaller than $fromSize.
3777
     *
3778
     * @param int $fromSize
3779
     * @param int $toSize
3780
     *
3781
     * @return bool
3782
     */
3783 1
    public function sizeIsBetween(int $fromSize, int $toSize): bool
3784
    {
3785 1
        if ($fromSize > $toSize) {
3786 1
            $tmp = $toSize;
3787 1
            $toSize = $fromSize;
3788 1
            $fromSize = $tmp;
3789
        }
3790
3791
        // init
3792 1
        $itemsTempCount = 0;
3793
3794 1
        foreach ($this->getGenerator() as $key => $value) {
3795 1
            ++$itemsTempCount;
3796 1
            if ($itemsTempCount > $toSize) {
3797 1
                return false;
3798
            }
3799
        }
3800
3801 1
        return $fromSize < $itemsTempCount && $itemsTempCount < $toSize;
3802
    }
3803
3804
    /**
3805
     * Count the values from the current array.
3806
     *
3807
     * alias: for "Arrayy->count()"
3808
     *
3809
     * @param int $mode
3810
     *
3811
     * @return int
3812
     */
3813 20
    public function size(int $mode = \COUNT_NORMAL): int
3814
    {
3815 20
        return $this->count($mode);
3816
    }
3817
3818
    /**
3819
     * Counts all elements in an array, or something in an object.
3820
     *
3821
     * <p>
3822
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3823
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3824
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3825
     * implemented and used in PHP.
3826
     * </p>
3827
     *
3828
     * @return int
3829
     *             <p>
3830
     *             The number of elements in var, which is
3831
     *             typically an array, since anything else will have one
3832
     *             element.
3833
     *             </p>
3834
     *             <p>
3835
     *             If var is not an array or an object with
3836
     *             implemented Countable interface,
3837
     *             1 will be returned.
3838
     *             There is one exception, if var is &null;,
3839
     *             0 will be returned.
3840
     *             </p>
3841
     *             <p>
3842
     *             Caution: count may return 0 for a variable that isn't set,
3843
     *             but it may also return 0 for a variable that has been initialized with an
3844
     *             empty array. Use isset to test if a variable is set.
3845
     *             </p>
3846
     */
3847 10
    public function sizeRecursive(): int
3848
    {
3849 10
        return \count($this->getArray(), \COUNT_RECURSIVE);
3850
    }
3851
3852
    /**
3853
     * Extract a slice of the array.
3854
     *
3855
     * @param int      $offset       <p>Slice begin index.</p>
3856
     * @param int|null $length       <p>Length of the slice.</p>
3857
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3858
     *
3859
     * @return static
3860
     *                <p>A slice of the original array with length $length.</p>
3861
     */
3862 4
    public function slice(int $offset, int $length = null, bool $preserveKeys = false): self
3863
    {
3864 4
        return static::create(
3865 4
            \array_slice(
3866 4
                $this->getArray(),
3867 4
                $offset,
3868 4
                $length,
3869 4
                $preserveKeys
3870
            ),
3871 4
            $this->iteratorClass,
3872 4
            false
3873
        );
3874
    }
3875
3876
    /**
3877
     * Sort the current array and optional you can keep the keys.
3878
     *
3879
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3880
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3881
     *                              <strong>SORT_NATURAL</strong></p>
3882
     * @param bool       $keepKeys
3883
     *
3884
     * @return static
3885
     *                <p>(Mutable) Return this Arrayy object.</p>
3886
     */
3887 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
3888
    {
3889 20
        $this->generatorToArray();
3890
3891 20
        return $this->sorting(
3892 20
            $this->array,
3893 20
            $direction,
3894 20
            $strategy,
3895 20
            $keepKeys
3896
        );
3897
    }
3898
3899
    /**
3900
     * Sort the current array by key.
3901
     *
3902
     * @see http://php.net/manual/en/function.ksort.php
3903
     * @see http://php.net/manual/en/function.krsort.php
3904
     *
3905
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3906
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3907
     *                              <strong>SORT_NATURAL</strong></p>
3908
     *
3909
     * @return static
3910
     *                <p>(Mutable) Return this Arrayy object.</p>
3911
     */
3912 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3913
    {
3914 18
        $this->generatorToArray();
3915
3916 18
        $this->sorterKeys($this->array, $direction, $strategy);
3917
3918 18
        return $this;
3919
    }
3920
3921
    /**
3922
     * Sort the current array by value.
3923
     *
3924
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3925
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3926
     *                              <strong>SORT_NATURAL</strong></p>
3927
     *
3928
     * @return static
3929
     *                <p>(Mutable)</p>
3930
     */
3931 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3932
    {
3933 1
        return $this->sort($direction, $strategy, true);
3934
    }
3935
3936
    /**
3937
     * Sort the current array by value.
3938
     *
3939
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3940
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3941
     *                              <strong>SORT_NATURAL</strong></p>
3942
     *
3943
     * @return static
3944
     *                <p>(Mutable)</p>
3945
     */
3946 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3947
    {
3948 1
        return $this->sort($direction, $strategy, false);
3949
    }
3950
3951
    /**
3952
     * Sort a array by value, by a closure or by a property.
3953
     *
3954
     * - If the sorter is null, the array is sorted naturally.
3955
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3956
     *
3957
     * @param callable|string|null $sorter
3958
     * @param int|string           $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3959
     * @param int                  $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3960
     *                                        <strong>SORT_NATURAL</strong></p>
3961
     *
3962
     * @return static
3963
     *                <p>(Immutable)</p>
3964
     */
3965 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3966
    {
3967 1
        $array = $this->getArray();
3968 1
        $direction = $this->getDirection($direction);
3969
3970
        // Transform all values into their results.
3971 1
        if ($sorter) {
3972 1
            $arrayy = static::create(
3973 1
                $array,
3974 1
                $this->iteratorClass,
3975 1
                false
3976
            );
3977
3978 1
            $results = $arrayy->each(
3979 1
                function ($value) use ($sorter) {
3980 1
                    if (\is_callable($sorter)) {
3981 1
                        return $sorter($value);
3982
                    }
3983
3984 1
                    return $this->get($sorter, null, $this->getArray());
3985 1
                }
3986
            );
3987
3988 1
            $results = $results->getArray();
3989
        } else {
3990 1
            $results = $array;
3991
        }
3992
3993
        // Sort by the results and replace by original values
3994 1
        \array_multisort($results, $direction, $strategy, $array);
3995
3996 1
        return static::create(
3997 1
            $array,
3998 1
            $this->iteratorClass,
3999 1
            false
4000
        );
4001
    }
4002
4003
    /**
4004
     * Split an array in the given amount of pieces.
4005
     *
4006
     * @param int  $numberOfPieces
4007
     * @param bool $keepKeys
4008
     *
4009
     * @return static
4010
     *                <p>(Immutable)</p>
4011
     */
4012 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
4013
    {
4014 1
        $this->generatorToArray();
4015
4016 1
        $arrayCount = \count($this->array, \COUNT_NORMAL);
4017
4018 1
        if ($arrayCount === 0) {
4019 1
            $result = [];
4020
        } else {
4021 1
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
4022 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
4023
        }
4024
4025 1
        return static::create(
4026 1
            $result,
4027 1
            $this->iteratorClass,
4028 1
            false
4029
        );
4030
    }
4031
4032
    /**
4033
     * Stripe all empty items.
4034
     *
4035
     * @return static
4036
     *                <p>(Immutable)</p>
4037
     */
4038 1
    public function stripEmpty(): self
4039
    {
4040 1
        return $this->filter(
4041 1
            static function ($item) {
4042 1
                if ($item === null) {
4043 1
                    return false;
4044
                }
4045
4046 1
                return (bool) \trim((string) $item);
4047 1
            }
4048
        );
4049
    }
4050
4051
    /**
4052
     * Swap two values between positions by key.
4053
     *
4054
     * @param int|string $swapA <p>a key in the array</p>
4055
     * @param int|string $swapB <p>a key in the array</p>
4056
     *
4057
     * @return static
4058
     *                <p>(Immutable)</p>
4059
     */
4060 1
    public function swap($swapA, $swapB): self
4061
    {
4062 1
        $array = $this->getArray();
4063
4064 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
4065
4066 1
        return static::create(
4067 1
            $array,
4068 1
            $this->iteratorClass,
4069 1
            false
4070
        );
4071
    }
4072
4073
    /**
4074
     * alias: for "Arrayy->getArray()"
4075
     *
4076
     * @see Arrayy::getArray()
4077
     */
4078 198
    public function toArray()
4079
    {
4080 198
        return $this->getArray();
4081
    }
4082
4083
    /**
4084
     * Convert the current array to JSON.
4085
     *
4086
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
4087
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
4088
     *
4089
     * @return string
4090
     */
4091 6
    public function toJson(int $options = 0, int $depth = 512): string
4092
    {
4093
        /** @noinspection PhpComposerExtensionStubsInspection */
4094 6
        $return = \json_encode($this->getArray(), $options, $depth);
4095 6
        if ($return === false) {
4096
            return '';
4097
        }
4098
4099 6
        return $return;
4100
    }
4101
4102
    /**
4103
     * Implodes array to a string with specified separator.
4104
     *
4105
     * @param string $separator [optional] <p>The element's separator.</p>
4106
     *
4107
     * @return string
4108
     *                <p>The string representation of array, separated by ",".</p>
4109
     */
4110 19
    public function toString(string $separator = ','): string
4111
    {
4112 19
        return $this->implode($separator);
4113
    }
4114
4115
    /**
4116
     * Return a duplicate free copy of the current array.
4117
     *
4118
     * @return static
4119
     *                <p>(Mutable)</p>
4120
     */
4121 12
    public function unique(): self
4122
    {
4123
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
4124
4125 12
        $this->array = $this->reduce(
4126 12
            static function ($resultArray, $value) {
4127 11
                if (!\in_array($value, $resultArray, true)) {
4128 11
                    $resultArray[] = $value;
4129
                }
4130
4131 11
                return $resultArray;
4132 12
            },
4133 12
            []
4134 12
        )->getArray();
4135 12
        $this->generator = null;
4136
4137 12
        return $this;
4138
    }
4139
4140
    /**
4141
     * Return a duplicate free copy of the current array. (with the old keys)
4142
     *
4143
     * @return static
4144
     *                <p>(Mutable)</p>
4145
     */
4146 11
    public function uniqueKeepIndex(): self
4147
    {
4148
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
4149
4150
        // init
4151 11
        $array = $this->getArray();
4152
4153 11
        $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce(\array_key...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

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

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

Loading history...
4154 11
            \array_keys($array),
4155 11
            static function ($resultArray, $key) use ($array) {
4156 10
                if (!\in_array($array[$key], $resultArray, true)) {
4157 10
                    $resultArray[$key] = $array[$key];
4158
                }
4159
4160 10
                return $resultArray;
4161 11
            },
4162 11
            []
4163
        );
4164 11
        $this->generator = null;
4165
4166 11
        if ($this->array === null) {
4167
            $this->array = [];
4168
        } else {
4169 11
            $this->array = (array) $this->array;
4170
        }
4171
4172 11
        return $this;
4173
    }
4174
4175
    /**
4176
     * @param bool $unique
4177
     *
4178
     * @return static
4179
     *                <p>(Immutable)</p>
4180
     */
4181 14
    public function reduce_dimension(bool $unique = true): self
4182
    {
4183
        // init
4184 14
        $result = [[]];
4185
4186 14
        foreach ($this->getGenerator() as $val) {
4187 12
            if (\is_array($val)) {
4188 5
                $result[] = (new self($val))->reduce_dimension($unique)->getArray();
4189
            } else {
4190 12
                $result[] = [$val];
4191
            }
4192
        }
4193 14
        $result = \array_merge(...$result);
4194
4195 14
        $resultArrayy = new self($result);
4196
4197 14
        return $unique ? $resultArrayy->unique() : $resultArrayy;
4198
    }
4199
4200
    /**
4201
     * alias: for "Arrayy->unique()"
4202
     *
4203
     * @return static
4204
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
4205
     *
4206
     * @see Arrayy::unique()
4207
     */
4208 10
    public function uniqueNewIndex(): self
4209
    {
4210 10
        return $this->unique();
4211
    }
4212
4213
    /**
4214
     * Prepends one or more values to the beginning of array at once.
4215
     *
4216
     * @return static
4217
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
4218
     */
4219 4 View Code Duplication
    public function unshift(/* variadic arguments allowed */): 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...
4220
    {
4221 4
        $this->generatorToArray();
4222
4223 4
        if (\func_num_args()) {
4224 4
            $args = \func_get_args();
4225 4
            \array_unshift(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_unshift() as the parameter $array expects a reference.
Loading history...
4226
        }
4227
4228 4
        return $this;
4229
    }
4230
4231
    /**
4232
     * Get all values from a array.
4233
     *
4234
     * @return static
4235
     *                <p>(Immutable)</p>
4236
     */
4237 2
    public function values(): self
4238
    {
4239 2
        return static::create(
4240 2
            function () {
4241
                /** @noinspection YieldFromCanBeUsedInspection */
4242 2
                foreach ($this->getGenerator() as $value) {
4243 2
                    yield $value;
4244
                }
4245 2
            },
4246 2
            $this->iteratorClass,
4247 2
            false
4248
        );
4249
    }
4250
4251
    /**
4252
     * Apply the given function to every element in the array, discarding the results.
4253
     *
4254
     * @param callable $callable
4255
     * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
4256
     *
4257
     * @return static
4258
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
4259
     */
4260 11
    public function walk($callable, bool $recursive = false): self
4261
    {
4262 11
        $this->generatorToArray();
4263
4264 11
        if ($recursive === true) {
4265 6
            \array_walk_recursive($this->array, $callable);
4266
        } else {
4267 5
            \array_walk($this->array, $callable);
4268
        }
4269
4270 11
        return $this;
4271
    }
4272
4273
    /**
4274
     * Convert an array into a object.
4275
     *
4276
     * @param array $array PHP array
4277
     *
4278
     * @return \stdClass
4279
     */
4280 4
    protected static function arrayToObject(array $array = []): \stdClass
4281
    {
4282
        // init
4283 4
        $object = new \stdClass();
4284
4285 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
4286 1
            return $object;
4287
        }
4288
4289 3
        foreach ($array as $name => $value) {
4290 3
            if (\is_array($value)) {
4291 1
                $object->{$name} = self::arrayToObject($value);
4292
            } else {
4293 3
                $object->{$name} = $value;
4294
            }
4295
        }
4296
4297 3
        return $object;
4298
    }
4299
4300
    /**
4301
     * @param array|\Generator|null $input        <p>
4302
     *                                            An array containing keys to return.
4303
     *                                            </p>
4304
     * @param mixed                 $search_value [optional] <p>
4305
     *                                            If specified, then only keys containing these values are returned.
4306
     *                                            </p>
4307
     * @param bool                  $strict       [optional] <p>
4308
     *                                            Determines if strict comparison (===) should be used during the
4309
     *                                            search.
4310
     *                                            </p>
4311
     *
4312
     * @return array
4313
     *               <p>an array of all the keys in input</p>
4314
     */
4315 10
    protected function array_keys_recursive(
4316
        $input = null,
4317
        $search_value = null,
4318
        bool $strict = true
4319
    ): array {
4320
        // init
4321 10
        $keys = [];
4322 10
        $keysTmp = [[]]; // the inner empty array covers cases when no loops were made
4323
4324 10
        if ($input === null) {
4325
            $input = $this->getGenerator();
4326
        }
4327
4328 10
        foreach ($input as $key => $value) {
4329
            if (
4330 10
                $search_value === null
4331
                ||
4332
                (
4333
                    \is_array($search_value) === true
4334
                    &&
4335 10
                    \in_array($key, $search_value, $strict)
4336
                )
4337
            ) {
4338 10
                $keys[] = $key;
4339
            }
4340
4341
            // check if recursive is needed
4342 10
            if (\is_array($value) === true) {
4343 10
                $keysTmp[] = $this->array_keys_recursive($value);
4344
            }
4345
        }
4346
4347 10
        return \array_merge($keys, ...$keysTmp);
4348
    }
4349
4350
    /**
4351
     * @param mixed      $path
4352
     * @param callable   $callable
4353
     * @param array|null $currentOffset
4354
     */
4355 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
4356
    {
4357 4
        $this->generatorToArray();
4358
4359 4
        if ($currentOffset === null) {
4360 4
            $currentOffset = &$this->array;
4361
        }
4362
4363 4
        $explodedPath = \explode($this->pathSeparator, $path);
4364 4
        if ($explodedPath === false) {
4365
            return;
4366
        }
4367
4368 4
        $nextPath = \array_shift($explodedPath);
4369
4370 4
        if (!isset($currentOffset[$nextPath])) {
4371
            return;
4372
        }
4373
4374 4
        if (!empty($explodedPath)) {
4375 1
            $this->callAtPath(
4376 1
                \implode($this->pathSeparator, $explodedPath),
4377 1
                $callable,
4378 1
                $currentOffset[$nextPath]
4379
            );
4380
        } else {
4381 4
            $callable($currentOffset[$nextPath]);
4382
        }
4383 4
    }
4384
4385
    /**
4386
     * create a fallback for array
4387
     *
4388
     * 1. use the current array, if it's a array
4389
     * 2. fallback to empty array, if there is nothing
4390
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
4391
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
4392
     * 5. call "__toArray()" on object, if the method exists
4393
     * 6. cast a string or object with "__toString()" into an array
4394
     * 7. throw a "InvalidArgumentException"-Exception
4395
     *
4396
     * @param mixed $data
4397
     *
4398
     * @throws \InvalidArgumentException
4399
     *
4400
     * @return array
4401
     */
4402 940
    protected function fallbackForArray(&$data): array
4403
    {
4404 940
        if (\is_array($data)) {
4405 937
            return $data;
4406
        }
4407
4408 46
        if (!$data) {
4409 6
            return [];
4410
        }
4411
4412 45
        $isObject = \is_object($data);
4413
4414 45
        if ($isObject && $data instanceof self) {
4415 2
            return $data->getArray();
4416
        }
4417
4418 44
        if ($isObject && $data instanceof \ArrayObject) {
4419
            return $data->getArrayCopy();
4420
        }
4421
4422 44
        if ($isObject && $data instanceof \Generator) {
4423
            return static::createFromGeneratorImmutable($data)->getArray();
4424
        }
4425
4426 44
        if ($isObject && $data instanceof \Traversable) {
4427
            return static::createFromObject($data)->getArray();
4428
        }
4429
4430 44
        if (\is_callable($data)) {
4431 37
            $this->generator = new ArrayyRewindableGenerator($data);
4432
4433 37
            return [];
4434
        }
4435
4436 9
        if ($isObject && \method_exists($data, '__toArray')) {
4437
            return (array) $data->__toArray();
4438
        }
4439
4440
        if (
4441 9
            \is_string($data)
4442
            ||
4443 9
            ($isObject && \method_exists($data, '__toString'))
4444
        ) {
4445 7
            return [(string) $data];
4446
        }
4447
4448 2
        throw new \InvalidArgumentException(
4449 2
            'Passed value should be a array'
4450
        );
4451
    }
4452
4453
    /**
4454
     * Get correct PHP constant for direction.
4455
     *
4456
     * @param int|string $direction
4457
     *
4458
     * @return int
4459
     */
4460 39
    protected function getDirection($direction): int
4461
    {
4462 39
        if (\is_string($direction)) {
4463 10
            $direction = \strtolower($direction);
4464
4465 10
            if ($direction === 'desc') {
4466 2
                $direction = \SORT_DESC;
4467
            } else {
4468 8
                $direction = \SORT_ASC;
4469
            }
4470
        }
4471
4472
        if (
4473 39
            $direction !== \SORT_DESC
4474
            &&
4475 39
            $direction !== \SORT_ASC
4476
        ) {
4477
            $direction = \SORT_ASC;
4478
        }
4479
4480 39
        return $direction;
4481
    }
4482
4483
    /**
4484
     * @param mixed               $glue
4485
     * @param array|static|string $pieces
4486
     * @param bool                $useKeys
4487
     *
4488
     * @return string
4489
     */
4490 35
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
4491
    {
4492 35
        if ($pieces instanceof self) {
4493 1
            $pieces = $pieces->getArray();
4494
        }
4495
4496 35
        if (\is_array($pieces)) {
4497 35
            $pieces_count = \count($pieces, \COUNT_NORMAL);
4498 35
            $pieces_count_not_zero = $pieces_count > 0;
4499
4500 35
            return \implode(
4501 35
                $glue,
4502 35
                \array_map(
4503 35
                    [$this, 'implode_recursive'],
4504 35
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
4505 35
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
4506
                )
4507
            );
4508
        }
4509
4510 35
        return (string) $pieces;
4511
    }
4512
4513
    /**
4514
     * @param mixed                 $needle   <p>
4515
     *                                        The searched value.
4516
     *                                        </p>
4517
     *                                        <p>
4518
     *                                        If needle is a string, the comparison is done
4519
     *                                        in a case-sensitive manner.
4520
     *                                        </p>
4521
     * @param array|\Generator|null $haystack <p>
4522
     *                                        The array.
4523
     *                                        </p>
4524
     * @param bool                  $strict   [optional] <p>
4525
     *                                        If the third parameter strict is set to true
4526
     *                                        then the in_array function will also check the
4527
     *                                        types of the
4528
     *                                        needle in the haystack.
4529
     *                                        </p>
4530
     *
4531
     * @return bool
4532
     *              <p>true if needle is found in the array, false otherwise</p>
4533
     */
4534 18
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
4535
    {
4536 18
        if ($haystack === null) {
4537
            $haystack = $this->getGenerator();
4538
        }
4539
4540 18
        foreach ($haystack as $item) {
4541 14
            if (\is_array($item) === true) {
4542 3
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
4543
            } else {
4544
                /** @noinspection NestedPositiveIfStatementsInspection */
4545 14
                if ($strict === true) {
4546 14
                    $returnTmp = $item === $needle;
4547
                } else {
4548
                    $returnTmp = $item == $needle;
4549
                }
4550
            }
4551
4552 14
            if ($returnTmp === true) {
4553 14
                return true;
4554
            }
4555
        }
4556
4557 8
        return false;
4558
    }
4559
4560
    /**
4561
     * @param mixed $value
4562
     */
4563
    protected function internalGetArray(&$value)
4564
    {
4565
        if ($value instanceof self) {
4566
            $valueTmp = $value->getArray();
4567
            if (\count($valueTmp, \COUNT_NORMAL) === 0) {
4568
                $value = [];
4569
            } else {
4570
                /** @noinspection PhpUnusedLocalVariableInspection */
4571
                $value = &$valueTmp;
4572
            }
4573
        }
4574
4575
        /** @noinspection PhpComposerExtensionStubsInspection */
4576
        /** @noinspection NotOptimalIfConditionsInspection */
4577
        if (
4578
            \class_exists('JsonSerializable')
4579
            &&
4580
            $value 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...
4581
        ) {
4582
4583
            /** @noinspection PhpUnusedLocalVariableInspection */
4584
            $value = &$value->jsonSerialize();
4585
        }
4586
    }
4587
4588
    /**
4589
     * Internal mechanics of remove method.
4590
     *
4591
     * @param mixed $key
4592
     *
4593
     * @return bool
4594
     */
4595 18
    protected function internalRemove($key): bool
4596
    {
4597 18
        $this->generatorToArray();
4598
4599
        if (
4600 18
            $this->pathSeparator
4601
            &&
4602 18
            \is_string($key)
4603
            &&
4604 18
            \strpos($key, $this->pathSeparator) !== false
4605
        ) {
4606
            $path = \explode($this->pathSeparator, (string) $key);
4607
4608
            if ($path !== false) {
4609
                // crawl though the keys
4610
                while (\count($path, \COUNT_NORMAL) > 1) {
4611
                    $key = \array_shift($path);
4612
4613
                    if (!$this->has($key)) {
4614
                        return false;
4615
                    }
4616
4617
                    $this->array = &$this->array[$key];
4618
                }
4619
4620
                $key = \array_shift($path);
4621
            }
4622
        }
4623
4624 18
        unset($this->array[$key]);
4625
4626 18
        return true;
4627
    }
4628
4629
    /**
4630
     * Internal mechanic of set method.
4631
     *
4632
     * @param int|string|null $key
4633
     * @param mixed           $value
4634
     * @param bool            $checkProperties
4635
     *
4636
     * @return bool
4637
     */
4638 823
    protected function internalSet($key, $value, $checkProperties = true): bool
4639
    {
4640
        if (
4641 823
            $checkProperties === true
4642
            &&
4643 823
            $this->properties !== []
4644
        ) {
4645 13
            if (isset($this->properties[$key]) === false) {
4646
                throw new \InvalidArgumentException('The key ' . $key . ' does not exists as @property in the class (' . \get_class($this) . ').');
4647
            }
4648
4649 13
            $this->properties[$key]->checkType($value);
4650
        }
4651
4652 822
        if ($key === null) {
4653
            return false;
4654
        }
4655
4656 822
        $this->generatorToArray();
4657
4658 822
        $array = &$this->array;
4659
4660
        if (
4661 822
            $this->pathSeparator
4662
            &&
4663 822
            \is_string($key)
4664
            &&
4665 822
            \strpos($key, $this->pathSeparator) !== false
4666
        ) {
4667 3
            $path = \explode($this->pathSeparator, (string) $key);
4668
4669 3
            if ($path !== false) {
4670
                // crawl through the keys
4671 3
                while (\count($path, \COUNT_NORMAL) > 1) {
4672 3
                    $key = \array_shift($path);
4673
4674 3
                    $array = &$array[$key];
4675
                }
4676
4677 3
                $key = \array_shift($path);
4678
            }
4679
        }
4680
4681 822
        $array[$key] = $value;
4682
4683 822
        return true;
4684
    }
4685
4686
    /**
4687
     * Convert a object into an array.
4688
     *
4689
     * @param object $object
4690
     *
4691
     * @return mixed
4692
     */
4693 5
    protected static function objectToArray($object)
4694
    {
4695 5
        if (!\is_object($object)) {
4696 4
            return $object;
4697
        }
4698
4699 5
        if (\is_object($object)) {
4700 5
            $object = \get_object_vars($object);
4701
        }
4702
4703 5
        return \array_map(['static', 'objectToArray'], $object);
4704
    }
4705
4706
    /**
4707
     * sorting keys
4708
     *
4709
     * @param array      $elements
4710
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4711
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4712
     *                              <strong>SORT_NATURAL</strong></p>
4713
     *
4714
     * @return static
4715
     *                <p>(Mutable) Return this Arrayy object.</p>
4716
     */
4717 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4718
    {
4719 18
        $direction = $this->getDirection($direction);
4720
4721
        switch ($direction) {
4722 18
            case 'desc':
4723 18
            case \SORT_DESC:
4724 6
                \krsort($elements, $strategy);
4725
4726 6
                break;
4727 13
            case 'asc':
4728 13
            case \SORT_ASC:
4729
            default:
4730 13
                \ksort($elements, $strategy);
4731
        }
4732
4733 18
        return $this;
4734
    }
4735
4736
    /**
4737
     * @param array      $elements  <p>Warning: used as reference</p>
4738
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4739
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4740
     *                              <strong>SORT_NATURAL</strong></p>
4741
     * @param bool       $keepKeys
4742
     *
4743
     * @return static
4744
     *                <p>(Mutable) Return this Arrayy object.</p>
4745
     */
4746 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4747
    {
4748 20
        $direction = $this->getDirection($direction);
4749
4750 20
        if (!$strategy) {
4751 20
            $strategy = \SORT_REGULAR;
4752
        }
4753
4754
        switch ($direction) {
4755 20
            case 'desc':
4756 20
            case \SORT_DESC:
4757 9
                if ($keepKeys) {
4758 5
                    \arsort($elements, $strategy);
4759
                } else {
4760 4
                    \rsort($elements, $strategy);
4761
                }
4762
4763 9
                break;
4764 11
            case 'asc':
4765 11
            case \SORT_ASC:
4766
            default:
4767 11
                if ($keepKeys) {
4768 4
                    \asort($elements, $strategy);
4769
                } else {
4770 7
                    \sort($elements, $strategy);
4771
                }
4772
        }
4773
4774 20
        return $this;
4775
    }
4776
4777
    /**
4778
     * @return bool
4779
     */
4780 858
    private function generatorToArray(): bool
4781
    {
4782 858
        if ($this->generator) {
4783 1
            $this->array = $this->getArray();
4784 1
            $this->generator = null;
4785
4786 1
            return true;
4787
        }
4788
4789 858
        return false;
4790
    }
4791
4792
    /**
4793
     * @return Property[]
4794
     */
4795 15
    private function getPropertiesFromPhpDoc(): array
4796
    {
4797 15
        static $PROPERTY_CACHE = [];
4798 15
        $cacheKey = 'Class::' . static::class;
4799
4800 15
        if (isset($PROPERTY_CACHE[$cacheKey])) {
4801 14
            return $PROPERTY_CACHE[$cacheKey];
4802
        }
4803
4804
        // init
4805 2
        $properties = [];
4806
4807 2
        $reflector = new \ReflectionClass($this);
4808 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
4809 2
        $docComment = $reflector->getDocComment();
4810 2
        if ($docComment) {
4811 2
            $docblock = $factory->create($docComment);
4812 2
            foreach ($docblock->getTagsByName('property') as $tag) {
4813
                /* @var $tag \phpDocumentor\Reflection\DocBlock\Tags\Property */
4814 2
                $properties[$tag->getVariableName()] = Property::fromPhpDocumentorProperty($tag);
4815
            }
4816
        }
4817
4818 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
4819
    }
4820
}
4821