Completed
Push — master ( 2da837...7cfe76 )
by Lars
01:59
created

Arrayy::get()   D

Complexity

Conditions 21
Paths 66

Size

Total Lines 92

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 45
CRAP Score 21

Importance

Changes 0
Metric Value
cc 21
nc 66
nop 3
dl 0
loc 92
ccs 45
cts 45
cp 1
crap 21
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 910
    public function __construct(
80
        $data = [],
81
        string $iteratorClass = ArrayyIterator::class,
82
        bool $checkForMissingPropertiesInConstructor = true
83
    ) {
84 910
        $data = $this->fallbackForArray($data);
85
86
        // used only for serialize + unserialize, all other methods are overwritten
87 908
        parent::__construct([], 0, $iteratorClass);
88
89 908
        $checkForMissingPropertiesInConstructor = $this->checkForMissingPropertiesInConstructor === true
90
                                                  &&
91 908
                                                  $checkForMissingPropertiesInConstructor === true;
92
93
        if (
94 908
            $this->checkPropertyTypes === true
95
            ||
96 908
            $checkForMissingPropertiesInConstructor === true
97
        ) {
98 15
            $this->properties = $this->getPropertiesFromPhpDoc();
99
        }
100
101
        if (
102 908
            $this->checkPropertiesMismatchInConstructor === true
103
            &&
104 908
            \count($data) !== 0
105
            &&
106 908
            \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 907
        foreach ($data as $key => &$value) {
113 793
            $this->internalSet(
114 793
                $key,
115
                $value,
116
                $checkForMissingPropertiesInConstructor
117
            );
118
        }
119
120 903
        $this->setIteratorClass($iteratorClass);
121 903
    }
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 38
    public function count(int $mode = \COUNT_NORMAL): int
307
    {
308 38
        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 15
    public function getIterator(): \Iterator
344
    {
345 15
        if ($this->generator instanceof ArrayyRewindableGenerator) {
346 1
            return $this->generator;
347
        }
348
349 14
        $iterator = $this->getIteratorClass();
350
351 14
        if ($iterator === ArrayyIterator::class) {
352 14
            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 14
    public function getIteratorClass(): string
364
    {
365 14
        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
                        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
                    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 903
    public function setIteratorClass($class)
576
    {
577 903
        if (\class_exists($class)) {
578 903
            $this->iteratorClass = $class;
579
580 903
            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 1
                foreach ($values as $value) {
673
                    $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 8
                $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
            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
        return \in_array($value, $this->getArray(), $strict);
921
    }
922
923
    /**
924
     * Check if an (case-insensitive) string is in the current array.
925
     *
926
     * @param string $value
927
     * @param bool   $recursive
928
     *
929
     * @return bool
930
     */
931 26
    public function containsCaseInsensitive($value, $recursive = false): bool
932
    {
933 26
        if ($recursive === true) {
934
            /** @noinspection PhpComposerExtensionStubsInspection */
935 26
            return $this->in_array_recursive(
936 26
                \mb_strtoupper((string) $value),
937 26
                $this->walk(
938
                    static function (&$val) {
939
                        /** @noinspection PhpComposerExtensionStubsInspection */
940 22
                        $val = \mb_strtoupper((string) $val);
941 26
                    },
942 26
                    true
943 26
                )->getArray(),
944 26
                true
945
            );
946
        }
947
948
        /** @noinspection PhpComposerExtensionStubsInspection */
949 13
        return \in_array(
950 13
            \mb_strtoupper((string) $value),
951 13
            $this->walk(
952
                static function (&$val) {
953
                    /** @noinspection PhpComposerExtensionStubsInspection */
954 11
                    $val = \mb_strtoupper((string) $val);
955 13
                },
956 13
                false
957 13
            )->getArray(),
958 13
            true
959
        );
960
    }
961
962
    /**
963
     * Check if the given key/index exists in the array.
964
     *
965
     * @param int|string $key <p>key/index to search for</p>
966
     *
967
     * @return bool
968
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
969
     */
970 4
    public function containsKey($key): bool
971
    {
972 4
        return $this->offsetExists($key);
973
    }
974
975
    /**
976
     * Check if all given needles are present in the array as key/index.
977
     *
978
     * @param array $needles   <p>The keys you are searching for.</p>
979
     * @param bool  $recursive
980
     *
981
     * @return bool
982
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
983
     */
984 2
    public function containsKeys(array $needles, $recursive = false): bool
985
    {
986 2
        if ($recursive === true) {
987 2
            return \count(
988 2
                       \array_intersect($needles, $this->keys(true)->getArray()),
989 2
                       \COUNT_RECURSIVE
990
                   )
991
                   ===
992 2
                   \count(
993 2
                       $needles,
994 2
                       \COUNT_RECURSIVE
995
                   );
996
        }
997
998 1
        return \count(
999 1
                   \array_intersect($needles, $this->keys()->getArray()),
1000 1
                   \COUNT_NORMAL
1001
               )
1002
               ===
1003 1
               \count(
1004 1
                   $needles,
1005 1
                   \COUNT_NORMAL
1006
               );
1007
    }
1008
1009
    /**
1010
     * Check if all given needles are present in the array as key/index.
1011
     *
1012
     * @param array $needles <p>The keys you are searching for.</p>
1013
     *
1014
     * @return bool
1015
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
1016
     */
1017 1
    public function containsKeysRecursive(array $needles): bool
1018
    {
1019 1
        return $this->containsKeys($needles, true);
1020
    }
1021
1022
    /**
1023
     * alias: for "Arrayy->contains()"
1024
     *
1025
     * @param float|int|string $value
1026
     *
1027
     * @return bool
1028
     *
1029
     * @see Arrayy::contains()
1030
     */
1031 9
    public function containsValue($value): bool
1032
    {
1033 9
        return $this->contains($value);
1034
    }
1035
1036
    /**
1037
     * alias: for "Arrayy->contains($value, true)"
1038
     *
1039
     * @param float|int|string $value
1040
     *
1041
     * @return bool
1042
     *
1043
     * @see Arrayy::contains()
1044
     */
1045 18
    public function containsValueRecursive($value): bool
1046
    {
1047 18
        return $this->contains($value, true);
1048
    }
1049
1050
    /**
1051
     * Check if all given needles are present in the array.
1052
     *
1053
     * @param array $needles
1054
     *
1055
     * @return bool
1056
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
1057
     */
1058 1
    public function containsValues(array $needles): bool
1059
    {
1060 1
        return \count(\array_intersect($needles, $this->getArray()), \COUNT_NORMAL)
1061
               ===
1062 1
               \count($needles, \COUNT_NORMAL);
1063
    }
1064
1065
    /**
1066
     * Counts all the values of an array
1067
     *
1068
     * @see http://php.net/manual/en/function.array-count-values.php
1069
     *
1070
     * @return static
1071
     *                <p>
1072
     *                (Immutable)
1073
     *                An associative Arrayy-object of values from input as
1074
     *                keys and their count as value.
1075
     *                </p>
1076
     */
1077 1
    public function countValues(): self
1078
    {
1079 1
        return new static(\array_count_values($this->getArray()));
1080
    }
1081
1082
    /**
1083
     * Creates an Arrayy object.
1084
     *
1085
     * @param mixed  $array
1086
     * @param string $iteratorClass
1087
     * @param bool   $checkForMissingPropertiesInConstructor
1088
     *
1089
     * @return static
1090
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1091
     */
1092 543
    public static function create($array = [], string $iteratorClass = ArrayyIterator::class, bool $checkForMissingPropertiesInConstructor = true): self
1093
    {
1094 543
        return new static(
1095 543
            $array,
1096
            $iteratorClass,
1097
            $checkForMissingPropertiesInConstructor
1098
        );
1099
    }
1100
1101
    /**
1102
     * WARNING: Creates an Arrayy object by reference.
1103
     *
1104
     * @param array $array
1105
     *
1106
     * @return static
1107
     *                <p>(Mutable) Return this Arrayy object.</p>
1108
     */
1109 1
    public function createByReference(array &$array = []): self
1110
    {
1111 1
        $array = $this->fallbackForArray($array);
1112
1113 1
        $this->array = &$array;
1114
1115 1
        return $this;
1116
    }
1117
1118
    /**
1119
     * Create an new instance from a callable function which will return an Generator.
1120
     *
1121
     * @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...
1122
     *
1123
     * @return static
1124
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1125
     */
1126 5
    public static function createFromGeneratorFunction(callable $generatorFunction): self
1127
    {
1128 5
        $arrayy = new static($generatorFunction);
1129
1130 5
        return $arrayy;
1131
    }
1132
1133
    /**
1134
     * Create an new instance filled with a copy of values from a "Traversable"-object.
1135
     *
1136
     * @param \Traversable $traversable
1137
     *
1138
     * @return static
1139
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1140
     */
1141
    public static function createFromTraversableImmutable(\Traversable $traversable): self
1142
    {
1143
        return new static(\iterator_to_array($traversable, true));
1144
    }
1145
1146
    /**
1147
     * Create an new instance filled with a copy of values from a "Generator"-object.
1148
     *
1149
     * @param \Generator $generator
1150
     *
1151
     * @return static
1152
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1153
     */
1154 4
    public static function createFromGeneratorImmutable(\Generator $generator): self
1155
    {
1156 4
        return new static(\iterator_to_array($generator, true));
1157
    }
1158
1159
    /**
1160
     * Create an new Arrayy object via JSON.
1161
     *
1162
     * @param string $json
1163
     *
1164
     * @return static
1165
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1166
     */
1167 5
    public static function createFromJson(string $json): self
1168
    {
1169
        /** @noinspection PhpComposerExtensionStubsInspection */
1170 5
        return static::create(\json_decode($json, true));
1171
    }
1172
1173
    /**
1174
     * Create an new instance filled with values from an object that is iterable.
1175
     *
1176
     * @param \Traversable $object <p>iterable object</p>
1177
     *
1178
     * @return static
1179
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1180
     */
1181 4
    public static function createFromObject(\Traversable $object): self
1182
    {
1183
        // init
1184 4
        $array = new static();
1185
1186 4
        if ($object instanceof self) {
1187 4
            $objectArray = $object->getGenerator();
1188
        } else {
1189
            $objectArray = $object;
1190
        }
1191
1192 4
        foreach ($objectArray as $key => $value) {
1193 3
            $array[$key] = $value;
1194
        }
1195
1196 4
        return $array;
1197
    }
1198
1199
    /**
1200
     * Create an new instance filled with values from an object.
1201
     *
1202
     * @param object $object
1203
     *
1204
     * @return static
1205
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1206
     */
1207 5
    public static function createFromObjectVars($object): self
1208
    {
1209 5
        return new static(self::objectToArray($object));
1210
    }
1211
1212
    /**
1213
     * Create an new Arrayy object via string.
1214
     *
1215
     * @param string      $str       <p>The input string.</p>
1216
     * @param string|null $delimiter <p>The boundary string.</p>
1217
     * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1218
     *                               used.</p>
1219
     *
1220
     * @return static
1221
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1222
     */
1223 10
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
1224
    {
1225 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...
1226 1
            \preg_match_all($regEx, $str, $array);
1227
1228 1
            if (!empty($array)) {
1229 1
                $array = $array[0];
1230
            }
1231
        } else {
1232
            /** @noinspection NestedPositiveIfStatementsInspection */
1233 9
            if ($delimiter !== null) {
1234 7
                $array = \explode($delimiter, $str);
1235
            } else {
1236 2
                $array = [$str];
1237
            }
1238
        }
1239
1240
        // trim all string in the array
1241 10
        \array_walk(
1242 10
            $array,
1243
            static function (&$val) {
1244 10
                if (\is_string($val)) {
1245 10
                    $val = \trim($val);
1246
                }
1247 10
            }
1248
        );
1249
1250 10
        return static::create($array);
1251
    }
1252
1253
    /**
1254
     * Create an new instance containing a range of elements.
1255
     *
1256
     * @param mixed $low  <p>First value of the sequence.</p>
1257
     * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1258
     * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1259
     *
1260
     * @return static
1261
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1262
     */
1263 2
    public static function createWithRange($low, $high, int $step = 1): self
1264
    {
1265 2
        return static::create(\range($low, $high, $step));
1266
    }
1267
1268
    /**
1269
     * Custom sort by index via "uksort".
1270
     *
1271
     * @see http://php.net/manual/en/function.uksort.php
1272
     *
1273
     * @param \callable $function
1274
     *
1275
     * @throws \InvalidArgumentException
1276
     *
1277
     * @return static
1278
     *                <p>(Mutable) Return this Arrayy object.</p>
1279
     */
1280 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...
1281
    {
1282 5
        if (!\is_callable($function)) {
1283
            throw new \InvalidArgumentException(
1284
                'Passed function must be callable'
1285
            );
1286
        }
1287
1288 5
        $this->generatorToArray();
1289
1290 5
        \uksort($this->array, $function);
1291
1292 5
        return $this;
1293
    }
1294
1295
    /**
1296
     * Custom sort by value via "usort".
1297
     *
1298
     * @see http://php.net/manual/en/function.usort.php
1299
     *
1300
     * @param \callable $function
1301
     *
1302
     * @throws \InvalidArgumentException
1303
     *
1304
     * @return static
1305
     *                <p>(Mutable) Return this Arrayy object.</p>
1306
     */
1307 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...
1308
    {
1309 5
        if (!\is_callable($function)) {
1310
            throw new \InvalidArgumentException(
1311
                'Passed function must be callable'
1312
            );
1313
        }
1314
1315 5
        $this->generatorToArray();
1316
1317 5
        \usort($this->array, $function);
1318
1319 5
        return $this;
1320
    }
1321
1322
    /**
1323
     * Return values that are only in the current array.
1324
     *
1325
     * @param array $array
1326
     *
1327
     * @return static
1328
     *                <p>(Immutable)</p>
1329
     */
1330 12
    public function diff(array $array = []): self
1331
    {
1332 12
        return static::create(
1333 12
            \array_diff($this->getArray(), $array),
1334 12
            $this->iteratorClass,
1335 12
            false
1336
        );
1337
    }
1338
1339
    /**
1340
     * Return values that are only in the current multi-dimensional array.
1341
     *
1342
     * @param array      $array
1343
     * @param array|null $helperVariableForRecursion <p>(only for internal usage)</p>
1344
     *
1345
     * @return static
1346
     *                <p>(Immutable)</p>
1347
     */
1348 1
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
1349
    {
1350
        // init
1351 1
        $result = [];
1352
1353
        if (
1354 1
            $helperVariableForRecursion !== null
1355
            &&
1356 1
            \is_array($helperVariableForRecursion)
1357
        ) {
1358
            $arrayForTheLoop = $helperVariableForRecursion;
1359
        } else {
1360 1
            $arrayForTheLoop = $this->getGenerator();
1361
        }
1362
1363 1
        foreach ($arrayForTheLoop as $key => $value) {
1364 1
            if ($value instanceof self) {
1365
                $value = $value->getArray();
1366
            }
1367
1368 1
            if (\array_key_exists($key, $array)) {
1369 1
                if ($value !== $array[$key]) {
1370 1
                    $result[$key] = $value;
1371
                }
1372
            } else {
1373 1
                $result[$key] = $value;
1374
            }
1375
        }
1376
1377 1
        return static::create(
1378 1
            $result,
1379 1
            $this->iteratorClass,
1380 1
            false
1381
        );
1382
    }
1383
1384
    /**
1385
     * Return values that are only in the new $array.
1386
     *
1387
     * @param array $array
1388
     *
1389
     * @return static
1390
     *                <p>(Immutable)</p>
1391
     */
1392 8
    public function diffReverse(array $array = []): self
1393
    {
1394 8
        return static::create(
1395 8
            \array_diff($array, $this->getArray()),
1396 8
            $this->iteratorClass,
1397 8
            false
1398
        );
1399
    }
1400
1401
    /**
1402
     * Divide an array into two arrays. One with keys and the other with values.
1403
     *
1404
     * @return static
1405
     *                <p>(Immutable)</p>
1406
     */
1407 1
    public function divide(): self
1408
    {
1409 1
        return static::create(
1410
            [
1411 1
                $this->keys(),
1412 1
                $this->values(),
1413
            ],
1414 1
            $this->iteratorClass,
1415 1
            false
1416
        );
1417
    }
1418
1419
    /**
1420
     * Iterate over the current array and modify the array's value.
1421
     *
1422
     * @param \Closure $closure
1423
     *
1424
     * @return static
1425
     *                <p>(Immutable)</p>
1426
     */
1427 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...
1428
    {
1429
        // init
1430 4
        $array = [];
1431
1432 4
        foreach ($this->getGenerator() as $key => $value) {
1433 4
            $array[$key] = $closure($value, $key);
1434
        }
1435
1436 4
        return static::create(
1437 4
            $array,
1438 4
            $this->iteratorClass,
1439 4
            false
1440
        );
1441
    }
1442
1443
    /**
1444
     * Check if a value is in the current array using a closure.
1445
     *
1446
     * @param \Closure $closure
1447
     *
1448
     * @return bool
1449
     *              <p>Returns true if the given value is found, false otherwise.</p>
1450
     */
1451 4
    public function exists(\Closure $closure): bool
1452
    {
1453
        // init
1454 4
        $isExists = false;
1455
1456 4
        foreach ($this->getGenerator() as $key => $value) {
1457 3
            if ($closure($value, $key)) {
1458 1
                $isExists = true;
1459
1460 1
                break;
1461
            }
1462
        }
1463
1464 4
        return $isExists;
1465
    }
1466
1467
    /**
1468
     * Fill the array until "$num" with "$default" values.
1469
     *
1470
     * @param int   $num
1471
     * @param mixed $default
1472
     *
1473
     * @return static
1474
     *                <p>(Immutable)</p>
1475
     */
1476 8
    public function fillWithDefaults(int $num, $default = null): self
1477
    {
1478 8
        if ($num < 0) {
1479 1
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1480
        }
1481
1482 7
        $this->generatorToArray();
1483
1484 7
        $tmpArray = $this->array;
1485
1486 7
        $count = \count($tmpArray);
1487
1488 7
        while ($count < $num) {
1489 4
            $tmpArray[] = $default;
1490 4
            ++$count;
1491
        }
1492
1493 7
        return static::create(
1494 7
            $tmpArray,
1495 7
            $this->iteratorClass,
1496 7
            false
1497
        );
1498
    }
1499
1500
    /**
1501
     * Find all items in an array that pass the truth test.
1502
     *
1503
     * @param \Closure|null $closure [optional] <p>
1504
     *                               The callback function to use
1505
     *                               </p>
1506
     *                               <p>
1507
     *                               If no callback is supplied, all entries of
1508
     *                               input equal to false (see
1509
     *                               converting to
1510
     *                               boolean) will be removed.
1511
     *                               </p>
1512
     *                               * @param int $flag [optional] <p>
1513
     *                               Flag determining what arguments are sent to <i>callback</i>:
1514
     *                               </p><ul>
1515
     *                               <li>
1516
     *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1517
     *                               to <i>callback</i> instead of the value</span>
1518
     *                               </li>
1519
     *                               <li>
1520
     *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1521
     *                               arguments to <i>callback</i> instead of the value</span>
1522
     *                               </li>
1523
     *                               </ul>
1524
     *
1525
     * @return static
1526
     *                <p>(Immutable)</p>
1527
     */
1528 11
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH): self
1529
    {
1530 11
        if (!$closure) {
1531 1
            return $this->clean();
1532
        }
1533
1534 11
        return static::create(
1535 11
            \array_filter($this->getArray(), $closure, $flag),
1536 11
            $this->iteratorClass,
1537 11
            false
1538
        );
1539
    }
1540
1541
    /**
1542
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
1543
     * property within that.
1544
     *
1545
     * @param string          $property
1546
     * @param string|string[] $value
1547
     * @param string          $comparisonOp
1548
     *                                      <p>
1549
     *                                      'eq' (equals),<br />
1550
     *                                      'gt' (greater),<br />
1551
     *                                      'gte' || 'ge' (greater or equals),<br />
1552
     *                                      'lt' (less),<br />
1553
     *                                      'lte' || 'le' (less or equals),<br />
1554
     *                                      'ne' (not equals),<br />
1555
     *                                      'contains',<br />
1556
     *                                      'notContains',<br />
1557
     *                                      'newer' (via strtotime),<br />
1558
     *                                      'older' (via strtotime),<br />
1559
     *                                      </p>
1560
     *
1561
     * @return static
1562
     *                <p>(Immutable)</p>
1563
     */
1564 1
    public function filterBy(string $property, $value, string $comparisonOp = null): self
1565
    {
1566 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...
1567 1
            $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1568
        }
1569
1570
        $ops = [
1571
            'eq' => static function ($item, $prop, $value) {
1572 1
                return $item[$prop] === $value;
1573 1
            },
1574
            'gt' => static function ($item, $prop, $value) {
1575
                return $item[$prop] > $value;
1576 1
            },
1577
            'ge' => static function ($item, $prop, $value) {
1578
                return $item[$prop] >= $value;
1579 1
            },
1580
            'gte' => static function ($item, $prop, $value) {
1581
                return $item[$prop] >= $value;
1582 1
            },
1583
            'lt' => static function ($item, $prop, $value) {
1584 1
                return $item[$prop] < $value;
1585 1
            },
1586
            'le' => static function ($item, $prop, $value) {
1587
                return $item[$prop] <= $value;
1588 1
            },
1589
            'lte' => static function ($item, $prop, $value) {
1590
                return $item[$prop] <= $value;
1591 1
            },
1592
            'ne' => static function ($item, $prop, $value) {
1593
                return $item[$prop] !== $value;
1594 1
            },
1595
            'contains' => static function ($item, $prop, $value) {
1596 1
                return \in_array($item[$prop], (array) $value, true);
1597 1
            },
1598
            'notContains' => static function ($item, $prop, $value) {
1599
                return !\in_array($item[$prop], (array) $value, true);
1600 1
            },
1601
            'newer' => static function ($item, $prop, $value) {
1602
                return \strtotime($item[$prop]) > \strtotime($value);
1603 1
            },
1604
            'older' => static function ($item, $prop, $value) {
1605
                return \strtotime($item[$prop]) < \strtotime($value);
1606 1
            },
1607
        ];
1608
1609 1
        $result = \array_values(
1610 1
            \array_filter(
1611 1
                $this->getArray(),
1612
                static function ($item) use (
1613 1
                    $property,
1614 1
                    $value,
1615 1
                    $ops,
1616 1
                    $comparisonOp
1617
                ) {
1618 1
                    $item = (array) $item;
1619 1
                    $itemArrayy = new static($item);
1620 1
                    $item[$property] = $itemArrayy->get($property, []);
1621
1622 1
                    return $ops[$comparisonOp]($item, $property, $value);
1623 1
                }
1624
            )
1625
        );
1626
1627 1
        return static::create(
1628 1
            $result,
1629 1
            $this->iteratorClass,
1630 1
            false
1631
        );
1632
    }
1633
1634
    /**
1635
     * Find the first item in an array that passes the truth test,
1636
     *  otherwise return false
1637
     *
1638
     * @param \Closure $closure
1639
     *
1640
     * @return false|mixed
1641
     *                     <p>Return false if we did not find the value.</p>
1642
     */
1643 8
    public function find(\Closure $closure)
1644
    {
1645 8
        foreach ($this->getGenerator() as $key => $value) {
1646 6
            if ($closure($value, $key)) {
1647 5
                return $value;
1648
            }
1649
        }
1650
1651 3
        return false;
1652
    }
1653
1654
    /**
1655
     * find by ...
1656
     *
1657
     * @param string          $property
1658
     * @param string|string[] $value
1659
     * @param string          $comparisonOp
1660
     *
1661
     * @return static
1662
     *                <p>(Immutable)</p>
1663
     */
1664
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
1665
    {
1666
        return $this->filterBy($property, $value, $comparisonOp);
1667
    }
1668
1669
    /**
1670
     * Get the first value from the current array.
1671
     *
1672
     * @return mixed
1673
     *               <p>Return null if there wasn't a element.</p>
1674
     */
1675 13
    public function first()
1676
    {
1677 13
        $tmpArray = $this->getArray();
1678
1679 13
        return \array_shift($tmpArray);
1680
    }
1681
1682
    /**
1683
     * Get the first value(s) from the current array.
1684
     *
1685
     * @param int|null $number <p>How many values you will take?</p>
1686
     *
1687
     * @return static
1688
     *                <p>(Immutable)</p>
1689
     */
1690 29
    public function firstsImmutable(int $number = null): self
1691
    {
1692 29
        $arrayTmp = $this->getArray();
1693
1694 29
        if ($number === null) {
1695 7
            $array = (array) \array_shift($arrayTmp);
1696
        } else {
1697 22
            $number = (int) $number;
1698 22
            $array = \array_splice($arrayTmp, 0, $number);
1699
        }
1700
1701 29
        return static::create(
1702 29
            $array,
1703 29
            $this->iteratorClass,
1704 29
            false
1705
        );
1706
    }
1707
1708
    /**
1709
     * Get the first value(s) from the current array.
1710
     *
1711
     * @param int|null $number <p>How many values you will take?</p>
1712
     *
1713
     * @return static
1714
     *                <p>(Mutable)</p>
1715
     */
1716 26
    public function firstsMutable(int $number = null): self
1717
    {
1718 26
        $this->generatorToArray();
1719
1720 26
        if ($number === null) {
1721 11
            $this->array = (array) \array_shift($this->array);
1722
        } else {
1723 15
            $number = (int) $number;
1724 15
            $this->array = \array_splice($this->array, 0, $number);
1725
        }
1726
1727 26
        return $this;
1728
    }
1729
1730
    /**
1731
     * Exchanges all keys with their associated values in an array.
1732
     *
1733
     * @return static
1734
     *                <p>(Immutable)</p>
1735
     */
1736 1
    public function flip(): self
1737
    {
1738 1
        return static::create(
1739 1
            \array_flip($this->getArray()),
1740 1
            $this->iteratorClass,
1741 1
            false
1742
        );
1743
    }
1744
1745
    /**
1746
     * Get a value from an array (optional using dot-notation).
1747
     *
1748
     * @param mixed $key      <p>The key to look for.</p>
1749
     * @param mixed $fallback <p>Value to fallback to.</p>
1750
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
1751
     *                        class.</p>
1752
     *
1753
     * @return mixed|static
1754
     */
1755 72
    public function get($key, $fallback = null, array $array = null)
1756
    {
1757 72
        if ($array !== null) {
1758 4
            $usedArray = $array;
1759
        } else {
1760 68
            $this->generatorToArray();
1761
1762 68
            $usedArray = $this->array;
1763
        }
1764
1765 72
        if ($key === null) {
1766 1
            return static::create(
1767 1
                $usedArray,
1768 1
                $this->iteratorClass,
1769 1
                false
1770
            );
1771
        }
1772
1773
        // php cast "bool"-index into "int"-index
1774 72
        if ((bool) $key === $key) {
1775 3
            $key = (int) $key;
1776
        }
1777
1778 72
        if (\array_key_exists($key, $usedArray) === true) {
1779 61
            if (\is_array($usedArray[$key])) {
1780 9
                return static::create(
1781 9
                    $usedArray[$key],
1782 9
                    $this->iteratorClass,
1783 9
                    false
1784
                );
1785
            }
1786
1787 54
            return $usedArray[$key];
1788
        }
1789
1790
        // crawl through array, get key according to object or not
1791 23
        $usePath = false;
1792
        if (
1793 23
            $this->pathSeparator
1794
            &&
1795 23
            \is_string($key)
1796
            &&
1797 23
            \strpos($key, $this->pathSeparator) !== false
1798
        ) {
1799 7
            $segments = \explode($this->pathSeparator, (string) $key);
1800 7
            if ($segments !== false) {
1801 7
                $usePath = true;
1802
1803 7
                foreach ($segments as $segment) {
1804
                    if (
1805
                        (
1806 7
                            \is_array($usedArray)
1807
                            ||
1808 7
                            $usedArray instanceof \ArrayAccess
1809
                        )
1810
                        &&
1811 7
                        isset($usedArray[$segment])
1812
                    ) {
1813 7
                        $usedArray = $usedArray[$segment];
1814
1815 7
                        continue;
1816
                    }
1817
1818
                    if (
1819 6
                        \is_object($usedArray)
1820
                        &&
1821 6
                        property_exists($usedArray, $segment)
1822
                    ) {
1823 1
                        $usedArray = $usedArray->{$segment};
1824
1825 1
                        continue;
1826
                    }
1827
1828 5
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
1829
                }
1830
            }
1831
        }
1832
1833 23
        if (!$usePath && !isset($usedArray[$key])) {
1834 16
            return $fallback instanceof \Closure ? $fallback() : $fallback;
1835
        }
1836
1837 7
        if (\is_array($usedArray)) {
1838 1
            return static::create(
1839 1
                $usedArray,
1840 1
                $this->iteratorClass,
1841 1
                false
1842
            );
1843
        }
1844
1845 7
        return $usedArray;
1846
    }
1847
1848
    /**
1849
     * Get the current array from the "Arrayy"-object.
1850
     *
1851
     * @return array
1852
     */
1853 796
    public function getArray(): array
1854
    {
1855
        // init
1856 796
        $array = [];
1857
1858 796
        foreach ($this->getGenerator() as $key => $value) {
1859 691
            $array[$key] = $value;
1860
        }
1861
1862 796
        return $array;
1863
    }
1864
1865
    /**
1866
     * Returns the values from a single column of the input array, identified by
1867
     * the $columnKey, can be used to extract data-columns from multi-arrays.
1868
     *
1869
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
1870
     * array by the values from the $indexKey column in the input array.
1871
     *
1872
     * @param mixed $columnKey
1873
     * @param mixed $indexKey
1874
     *
1875
     * @return static
1876
     *                <p>(Immutable)</p>
1877
     */
1878 1
    public function getColumn($columnKey = null, $indexKey = null): self
1879
    {
1880 1
        return static::create(
1881 1
            \array_column($this->getArray(), $columnKey, $indexKey),
1882 1
            $this->iteratorClass,
1883 1
            false
1884
        );
1885
    }
1886
1887
    /**
1888
     * Get the current array from the "Arrayy"-object as generator.
1889
     *
1890
     * @return \Generator
1891
     */
1892 821
    public function getGenerator(): \Generator
1893
    {
1894 821
        if ($this->generator instanceof ArrayyRewindableGenerator) {
1895 5
            yield from $this->generator;
1896
        }
1897
1898 821
        yield from $this->array;
1899 808
    }
1900
1901
    /**
1902
     * alias: for "Arrayy->keys()"
1903
     *
1904
     * @return static
1905
     *                <p>(Immutable)</p>
1906
     *
1907
     * @see Arrayy::keys()
1908
     */
1909 1
    public function getKeys(): self
1910
    {
1911 1
        return $this->keys();
1912
    }
1913
1914
    /**
1915
     * Get the current array from the "Arrayy"-object as object.
1916
     *
1917
     * @return \stdClass
1918
     */
1919 4
    public function getObject(): \stdClass
1920
    {
1921 4
        return self::arrayToObject($this->getArray());
1922
    }
1923
1924
    /**
1925
     * alias: for "Arrayy->randomImmutable()"
1926
     *
1927
     * @return static
1928
     *                <p>(Immutable)</p>
1929
     *
1930
     * @see Arrayy::randomImmutable()
1931
     */
1932 4
    public function getRandom(): self
1933
    {
1934 4
        return $this->randomImmutable();
1935
    }
1936
1937
    /**
1938
     * alias: for "Arrayy->randomKey()"
1939
     *
1940
     * @return mixed
1941
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
1942
     *
1943
     * @see Arrayy::randomKey()
1944
     */
1945 3
    public function getRandomKey()
1946
    {
1947 3
        return $this->randomKey();
1948
    }
1949
1950
    /**
1951
     * alias: for "Arrayy->randomKeys()"
1952
     *
1953
     * @param int $number
1954
     *
1955
     * @return static
1956
     *                <p>(Immutable)</p>
1957
     *
1958
     * @see Arrayy::randomKeys()
1959
     */
1960 8
    public function getRandomKeys(int $number): self
1961
    {
1962 8
        return $this->randomKeys($number);
1963
    }
1964
1965
    /**
1966
     * alias: for "Arrayy->randomValue()"
1967
     *
1968
     * @return mixed
1969
     *               <p>Get a random value or null if there wasn't a value.</p>
1970
     *
1971
     * @see Arrayy::randomValue()
1972
     */
1973 3
    public function getRandomValue()
1974
    {
1975 3
        return $this->randomValue();
1976
    }
1977
1978
    /**
1979
     * alias: for "Arrayy->randomValues()"
1980
     *
1981
     * @param int $number
1982
     *
1983
     * @return static
1984
     *                <p>(Immutable)</p>
1985
     *
1986
     * @see Arrayy::randomValues()
1987
     */
1988 6
    public function getRandomValues(int $number): self
1989
    {
1990 6
        return $this->randomValues($number);
1991
    }
1992
1993
    /**
1994
     * Group values from a array according to the results of a closure.
1995
     *
1996
     * @param \callable $grouper  <p>A callable function name.</p>
1997
     * @param bool      $saveKeys
1998
     *
1999
     * @return static
2000
     *                <p>(Immutable)</p>
2001
     */
2002 4
    public function group($grouper, bool $saveKeys = false): self
2003
    {
2004
        // init
2005 4
        $result = [];
2006
2007
        // Iterate over values, group by property/results from closure.
2008 4
        foreach ($this->getGenerator() as $key => $value) {
2009 4
            $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $this->getArray());
2010 4
            $newValue = $this->get($groupKey, null, $result);
2011
2012 4
            if ($groupKey instanceof self) {
2013
                $groupKey = $groupKey->getArray();
2014
            }
2015
2016 4
            if ($newValue instanceof self) {
2017 4
                $newValue = $newValue->getArray();
2018
            }
2019
2020
            // Add to results.
2021 4
            if ($groupKey !== null) {
2022 3
                if ($saveKeys) {
2023 2
                    $result[$groupKey] = $newValue;
2024 2
                    $result[$groupKey][$key] = $value;
2025
                } else {
2026 1
                    $result[$groupKey] = $newValue;
2027 1
                    $result[$groupKey][] = $value;
2028
                }
2029
            }
2030
        }
2031
2032 4
        return static::create(
2033 4
            $result,
2034 4
            $this->iteratorClass,
2035 4
            false
2036
        );
2037
    }
2038
2039
    /**
2040
     * Check if an array has a given key.
2041
     *
2042
     * @param mixed $key
2043
     *
2044
     * @return bool
2045
     */
2046 23
    public function has($key): bool
2047
    {
2048 23
        static $UN_FOUND = null;
2049
2050 23
        if ($UN_FOUND === null) {
2051
            // Generate unique string to use as marker.
2052 1
            $UN_FOUND = \uniqid('arrayy', true);
2053
        }
2054
2055 23
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2056
    }
2057
2058
    /**
2059
     * Implodes the values of this array.
2060
     *
2061
     * @param string $glue
2062
     *
2063
     * @return string
2064
     */
2065 27
    public function implode(string $glue = ''): string
2066
    {
2067 27
        return $this->implode_recursive($glue, $this->getArray(), false);
2068
    }
2069
2070
    /**
2071
     * Implodes the keys of this array.
2072
     *
2073
     * @param string $glue
2074
     *
2075
     * @return string
2076
     */
2077 8
    public function implodeKeys(string $glue = ''): string
2078
    {
2079 8
        return $this->implode_recursive($glue, $this->getArray(), true);
2080
    }
2081
2082
    /**
2083
     * Given a list and an iterate-function that returns
2084
     * a key for each element in the list (or a property name),
2085
     * returns an object with an index of each item.
2086
     *
2087
     * @param mixed $key
2088
     *
2089
     * @return static
2090
     *                <p>(Immutable)</p>
2091
     */
2092 4
    public function indexBy($key): self
2093
    {
2094
        // init
2095 4
        $results = [];
2096
2097 4
        foreach ($this->getGenerator() as $a) {
2098 4
            if (\array_key_exists($key, $a) === true) {
2099 3
                $results[$a[$key]] = $a;
2100
            }
2101
        }
2102
2103 4
        return static::create(
2104 4
            $results,
2105 4
            $this->iteratorClass,
2106 4
            false
2107
        );
2108
    }
2109
2110
    /**
2111
     * alias: for "Arrayy->searchIndex()"
2112
     *
2113
     * @param mixed $value <p>The value to search for.</p>
2114
     *
2115
     * @return mixed
2116
     *
2117
     * @see Arrayy::searchIndex()
2118
     */
2119 4
    public function indexOf($value)
2120
    {
2121 4
        return $this->searchIndex($value);
2122
    }
2123
2124
    /**
2125
     * Get everything but the last..$to items.
2126
     *
2127
     * @param int $to
2128
     *
2129
     * @return static
2130
     *                <p>(Immutable)</p>
2131
     */
2132 12
    public function initial(int $to = 1): self
2133
    {
2134 12
        return $this->firstsImmutable(\count($this->getArray(), \COUNT_NORMAL) - $to);
2135
    }
2136
2137
    /**
2138
     * Return an array with all elements found in input array.
2139
     *
2140
     * @param array $search
2141
     * @param bool  $keepKeys
2142
     *
2143
     * @return static
2144
     *                <p>(Immutable)</p>
2145
     */
2146 3
    public function intersection(array $search, bool $keepKeys = false): self
2147
    {
2148 3
        if ($keepKeys) {
2149 1
            return static::create(
2150 1
                \array_uintersect(
2151 1
                    $this->array,
2152 1
                    $search,
2153
                    static function ($a, $b) {
2154 1
                        return $a === $b ? 0 : -1;
2155 1
                    }
2156
                ),
2157 1
                $this->iteratorClass,
2158 1
                false
2159
            );
2160
        }
2161
2162 2
        return static::create(
2163 2
            \array_values(\array_intersect($this->getArray(), $search)),
2164 2
            $this->iteratorClass,
2165 2
            false
2166
        );
2167
    }
2168
2169
    /**
2170
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
2171
     *
2172
     * @param array $search
2173
     *
2174
     * @return bool
2175
     */
2176 1
    public function intersects(array $search): bool
2177
    {
2178 1
        return \count($this->intersection($search)->array, \COUNT_NORMAL) > 0;
2179
    }
2180
2181
    /**
2182
     * Invoke a function on all of an array's values.
2183
     *
2184
     * @param mixed $callable
2185
     * @param mixed $arguments
2186
     *
2187
     * @return static
2188
     *                <p>(Immutable)</p>
2189
     */
2190 1
    public function invoke($callable, $arguments = []): self
2191
    {
2192
        // If one argument given for each iteration, create an array for it.
2193 1
        if (!\is_array($arguments)) {
2194 1
            $arguments = StaticArrayy::repeat(
2195 1
                $arguments,
2196 1
                \count($this->getArray(), \COUNT_NORMAL)
2197 1
            )->getArray();
2198
        }
2199
2200
        // If the callable has arguments, pass them.
2201 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...
2202 1
            $array = \array_map($callable, $this->getArray(), $arguments);
2203
        } else {
2204 1
            $array = \array_map($callable, $this->getArray());
2205
        }
2206
2207 1
        return static::create(
2208 1
            $array,
2209 1
            $this->iteratorClass,
2210 1
            false
2211
        );
2212
    }
2213
2214
    /**
2215
     * Check whether array is associative or not.
2216
     *
2217
     * @param bool $recursive
2218
     *
2219
     * @return bool
2220
     *              <p>Returns true if associative, false otherwise.</p>
2221
     */
2222 15
    public function isAssoc(bool $recursive = false): bool
2223
    {
2224 15
        if ($this->isEmpty()) {
2225 3
            return false;
2226
        }
2227
2228 13
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2229 13
            if (!\is_string($key)) {
2230 11
                return false;
2231
            }
2232
        }
2233
2234 3
        return true;
2235
    }
2236
2237
    /**
2238
     * Check whether the array is empty or not.
2239
     *
2240
     * @return bool
2241
     *              <p>Returns true if empty, false otherwise.</p>
2242
     */
2243 38
    public function isEmpty(): bool
2244
    {
2245 38
        if ($this->generator) {
2246
            return $this->getArray() === [];
2247
        }
2248
2249 38
        return $this->array === [];
2250
    }
2251
2252
    /**
2253
     * Check if the current array is equal to the given "$array" or not.
2254
     *
2255
     * @param array $array
2256
     *
2257
     * @return bool
2258
     */
2259
    public function isEqual(array $array): bool
2260
    {
2261
        return $this->getArray() === $array;
2262
    }
2263
2264
    /**
2265
     * Check if the current array is a multi-array.
2266
     *
2267
     * @return bool
2268
     */
2269 14
    public function isMultiArray(): bool
2270
    {
2271
        return !(
2272 14
            \count($this->getArray(), \COUNT_NORMAL)
2273
            ===
2274 14
            \count($this->getArray(), \COUNT_RECURSIVE)
2275
        );
2276
    }
2277
2278
    /**
2279
     * Check whether array is numeric or not.
2280
     *
2281
     * @return bool
2282
     *              <p>Returns true if numeric, false otherwise.</p>
2283
     */
2284 5
    public function isNumeric(): bool
2285
    {
2286 5
        if ($this->isEmpty()) {
2287 2
            return false;
2288
        }
2289
2290 4
        foreach ($this->keys()->getGenerator() as $key) {
2291 4
            if (!\is_int($key)) {
2292 2
                return false;
2293
            }
2294
        }
2295
2296 2
        return true;
2297
    }
2298
2299
    /**
2300
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2301
     *
2302
     * @param bool $recursive
2303
     *
2304
     * @return bool
2305
     */
2306 1
    public function isSequential(bool $recursive = false): bool
2307
    {
2308
2309
        // recursive
2310
2311 1
        if ($recursive === true) {
2312
            return $this->array_keys_recursive($this->getArray())
2313
                   ===
2314
                   \range(0, \count($this->getArray(), \COUNT_RECURSIVE) - 1);
2315
        }
2316
2317
        // non recursive
2318
2319 1
        return \array_keys($this->getArray())
2320
               ===
2321 1
               \range(0, \count($this->getArray(), \COUNT_NORMAL) - 1);
2322
    }
2323
2324
    /**
2325
     * @return array
2326
     */
2327
    public function jsonSerialize(): array
2328
    {
2329
        return $this->getArray();
2330
    }
2331
2332
    /**
2333
     * Get all keys from the current array.
2334
     *
2335
     * @param bool  $recursive    [optional] <p>
2336
     *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2337
     *                            </p>
2338
     * @param mixed $search_value [optional] <p>
2339
     *                            If specified, then only keys containing these values are returned.
2340
     *                            </p>
2341
     * @param bool  $strict       [optional] <p>
2342
     *                            Determines if strict comparison (===) should be used during the search.
2343
     *                            </p>
2344
     *
2345
     * @return static
2346
     *                <p>(Immutable) An array of all the keys in input.</p>
2347
     */
2348 26
    public function keys(bool $recursive = false, $search_value = null, bool $strict = true): self
2349
    {
2350
2351
        // recursive
2352
2353 26
        if ($recursive === true) {
2354 3
            if ($search_value === null) {
2355 3
                $array = $this->array_keys_recursive($this->getArray());
2356
            } else {
2357
                $array = $this->array_keys_recursive($this->getArray(), $search_value, $strict);
2358
            }
2359
2360 3
            return static::create(
2361 3
                $array,
2362 3
                $this->iteratorClass,
2363 3
                false
2364
            );
2365
        }
2366
2367
        // non recursive
2368
2369 25
        if ($search_value === null) {
2370 25
            $array = \array_keys($this->getArray());
2371
        } else {
2372
            $array = \array_keys($this->getArray(), $search_value, $strict);
2373
        }
2374
2375 25
        return static::create(
2376 25
            $array,
2377 25
            $this->iteratorClass,
2378 25
            false
2379
        );
2380
    }
2381
2382
    /**
2383
     * Sort an array by key in reverse order.
2384
     *
2385
     * @param int $sort_flags [optional] <p>
2386
     *                        You may modify the behavior of the sort using the optional
2387
     *                        parameter sort_flags, for details
2388
     *                        see sort.
2389
     *                        </p>
2390
     *
2391
     * @return static
2392
     *                <p>(Mutable) Return this Arrayy object.</p>
2393
     */
2394 4
    public function krsort(int $sort_flags = 0): self
2395
    {
2396 4
        $this->generatorToArray();
2397
2398 4
        \krsort($this->array, $sort_flags);
2399
2400 4
        return $this;
2401
    }
2402
2403
    /**
2404
     * Get the last value from the current array.
2405
     *
2406
     * @return mixed
2407
     *               <p>Return null if there wasn't a element.</p>
2408
     */
2409 4
    public function last()
2410
    {
2411 4
        return $this->pop();
2412
    }
2413
2414
    /**
2415
     * Get the last value(s) from the current array.
2416
     *
2417
     * @param int|null $number
2418
     *
2419
     * @return static
2420
     *                <p>(Immutable)</p>
2421
     */
2422 13
    public function lastsImmutable(int $number = null): self
2423
    {
2424 13
        if ($this->isEmpty()) {
2425 1
            return static::create(
2426 1
                [],
2427 1
                $this->iteratorClass,
2428 1
                false
2429
            );
2430
        }
2431
2432 12
        if ($number === null) {
2433 8
            $poppedValue = $this->pop();
2434
2435 8
            if ($poppedValue === null) {
2436 1
                $poppedValue = [$poppedValue];
2437
            } else {
2438 7
                $poppedValue = (array) $poppedValue;
2439
            }
2440
2441 8
            $arrayy = static::create(
2442 8
                $poppedValue,
2443 8
                $this->iteratorClass,
2444 8
                false
2445
            );
2446
        } else {
2447 4
            $number = (int) $number;
2448 4
            $arrayy = $this->rest(-$number);
2449
        }
2450
2451 12
        return $arrayy;
2452
    }
2453
2454
    /**
2455
     * Get the last value(s) from the current array.
2456
     *
2457
     * @param int|null $number
2458
     *
2459
     * @return static
2460
     *                <p>(Mutable)</p>
2461
     */
2462 13
    public function lastsMutable(int $number = null): self
2463
    {
2464 13
        if ($this->isEmpty()) {
2465 1
            return $this;
2466
        }
2467
2468 12
        if ($number === null) {
2469 8
            $poppedValue = $this->pop();
2470
2471 8
            if ($poppedValue === null) {
2472 1
                $poppedValue = [$poppedValue];
2473
            } else {
2474 7
                $poppedValue = (array) $poppedValue;
2475
            }
2476
2477 8
            $this->array = static::create(
2478 8
                $poppedValue,
2479 8
                $this->iteratorClass,
2480 8
                false
2481 8
            )->getArray();
2482
        } else {
2483 4
            $number = (int) $number;
2484 4
            $this->array = $this->rest(-$number)->getArray();
2485
        }
2486
2487 12
        $this->generator = null;
2488
2489 12
        return $this;
2490
    }
2491
2492
    /**
2493
     * Count the values from the current array.
2494
     *
2495
     * alias: for "Arrayy->count()"
2496
     *
2497
     * @param int $mode
2498
     *
2499
     * @return int
2500
     *
2501
     * @see Arrayy::count()
2502
     */
2503 20
    public function length(int $mode = \COUNT_NORMAL): int
2504
    {
2505 20
        return $this->count($mode);
2506
    }
2507
2508
    /**
2509
     * Apply the given function to the every element of the array,
2510
     * collecting the results.
2511
     *
2512
     * @param callable $callable
2513
     *
2514
     * @return static
2515
     *                <p>(Immutable) Arrayy object with modified elements.</p>
2516
     */
2517 4
    public function map(callable $callable): self
2518
    {
2519 4
        return static::create(
2520 4
            \array_map($callable, $this->getArray()),
2521 4
            $this->iteratorClass,
2522 4
            false
2523
        );
2524
    }
2525
2526
    /**
2527
     * Check if all items in current array match a truth test.
2528
     *
2529
     * @param \Closure $closure
2530
     *
2531
     * @return bool
2532
     */
2533 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...
2534
    {
2535 15
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2536 2
            return false;
2537
        }
2538
2539 13
        foreach ($this->getGenerator() as $key => $value) {
2540 13
            $value = $closure($value, $key);
2541
2542 13
            if ($value === false) {
2543 7
                return false;
2544
            }
2545
        }
2546
2547 7
        return true;
2548
    }
2549
2550
    /**
2551
     * Check if any item in the current array matches a truth test.
2552
     *
2553
     * @param \Closure $closure
2554
     *
2555
     * @return bool
2556
     */
2557 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...
2558
    {
2559 14
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2560 2
            return false;
2561
        }
2562
2563 12
        foreach ($this->getGenerator() as $key => $value) {
2564 12
            $value = $closure($value, $key);
2565
2566 12
            if ($value === true) {
2567 9
                return true;
2568
            }
2569
        }
2570
2571 4
        return false;
2572
    }
2573
2574
    /**
2575
     * Get the max value from an array.
2576
     *
2577
     * @return mixed
2578
     */
2579 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...
2580
    {
2581 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2582 1
            return false;
2583
        }
2584
2585 9
        return \max($this->getArray());
2586
    }
2587
2588
    /**
2589
     * Merge the new $array into the current array.
2590
     *
2591
     * - keep key,value from the current array, also if the index is in the new $array
2592
     *
2593
     * @param array $array
2594
     * @param bool  $recursive
2595
     *
2596
     * @return static
2597
     *                <p>(Immutable)</p>
2598
     */
2599 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...
2600
    {
2601 25
        if ($recursive === true) {
2602 4
            $result = \array_replace_recursive($this->getArray(), $array);
2603
        } else {
2604 21
            $result = \array_replace($this->getArray(), $array);
2605
        }
2606
2607 25
        return static::create(
2608 25
            $result,
2609 25
            $this->iteratorClass,
2610 25
            false
2611
        );
2612
    }
2613
2614
    /**
2615
     * Merge the new $array into the current array.
2616
     *
2617
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2618
     * - create new indexes
2619
     *
2620
     * @param array $array
2621
     * @param bool  $recursive
2622
     *
2623
     * @return static
2624
     *                <p>(Immutable)</p>
2625
     */
2626 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...
2627
    {
2628 16
        if ($recursive === true) {
2629 4
            $result = \array_merge_recursive($this->getArray(), $array);
2630
        } else {
2631 12
            $result = \array_merge($this->getArray(), $array);
2632
        }
2633
2634 16
        return static::create(
2635 16
            $result,
2636 16
            $this->iteratorClass,
2637 16
            false
2638
        );
2639
    }
2640
2641
    /**
2642
     * Merge the the current array into the $array.
2643
     *
2644
     * - use key,value from the new $array, also if the index is in the current array
2645
     *
2646
     * @param array $array
2647
     * @param bool  $recursive
2648
     *
2649
     * @return static
2650
     *                <p>(Immutable)</p>
2651
     */
2652 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...
2653
    {
2654 16
        if ($recursive === true) {
2655 4
            $result = \array_replace_recursive($array, $this->getArray());
2656
        } else {
2657 12
            $result = \array_replace($array, $this->getArray());
2658
        }
2659
2660 16
        return static::create(
2661 16
            $result,
2662 16
            $this->iteratorClass,
2663 16
            false
2664
        );
2665
    }
2666
2667
    /**
2668
     * Merge the current array into the new $array.
2669
     *
2670
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
2671
     * - create new indexes
2672
     *
2673
     * @param array $array
2674
     * @param bool  $recursive
2675
     *
2676
     * @return static
2677
     *                <p>(Immutable)</p>
2678
     */
2679 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...
2680
    {
2681 17
        if ($recursive === true) {
2682 4
            $result = \array_merge_recursive($array, $this->getArray());
2683
        } else {
2684 13
            $result = \array_merge($array, $this->getArray());
2685
        }
2686
2687 17
        return static::create(
2688 17
            $result,
2689 17
            $this->iteratorClass,
2690 17
            false
2691
        );
2692
    }
2693
2694
    /**
2695
     * @return ArrayyMeta|static
2696
     */
2697 14
    public static function meta()
2698
    {
2699 14
        return (new ArrayyMeta())->getMetaObject(static::class);
2700
    }
2701
2702
    /**
2703
     * Get the min value from an array.
2704
     *
2705
     * @return mixed
2706
     */
2707 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...
2708
    {
2709 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2710 1
            return false;
2711
        }
2712
2713 9
        return \min($this->getArray());
2714
    }
2715
2716
    /**
2717
     * Move an array element to a new index.
2718
     *
2719
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2720
     *
2721
     * @param int|string $from
2722
     * @param int $to
2723
     *
2724
     * @return static
2725
     *                <p>(Immutable)</p>
2726
     */
2727 1
    public function moveElement($from, $to): self
2728
    {
2729 1
        $array = $this->getArray();
2730
2731 1
        if (\is_int($from)) {
2732 1
            $tmp = \array_splice($array, $from, 1);
2733 1
            \array_splice($array, (int) $to, 0, $tmp);
2734 1
            $output = $array;
2735 1
        } elseif (\is_string($from)) {
2736 1
            $indexToMove = \array_search($from, \array_keys($array), true);
2737 1
            $itemToMove = $array[$from];
2738 1
            if ($indexToMove !== false) {
2739 1
                \array_splice($array, $indexToMove, 1);
2740
            }
2741 1
            $i = 0;
2742 1
            $output = [];
2743 1
            foreach ($array as $key => $item) {
2744 1
                if ($i === $to) {
2745 1
                    $output[$from] = $itemToMove;
2746
                }
2747 1
                $output[$key] = $item;
2748 1
                ++$i;
2749
            }
2750
        } else {
2751
            $output = [];
2752
        }
2753
2754 1
        return static::create(
2755 1
            $output,
2756 1
            $this->iteratorClass,
2757 1
            false
2758
        );
2759
    }
2760
2761
    /**
2762
     * Get a subset of the items from the given array.
2763
     *
2764
     * @param mixed[] $keys
2765
     *
2766
     * @return static
2767
     *                <p>(Immutable)</p>
2768
     */
2769
    public function only(array $keys): self
2770
    {
2771
        $array = $this->getArray();
2772
2773
        return static::create(
2774
            \array_intersect_key($array, \array_flip($keys)),
2775
            $this->iteratorClass,
2776
            false
2777
        );
2778
    }
2779
2780
    /**
2781
     * Pad array to the specified size with a given value.
2782
     *
2783
     * @param int   $size  <p>Size of the result array.</p>
2784
     * @param mixed $value <p>Empty value by default.</p>
2785
     *
2786
     * @return static
2787
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
2788
     */
2789 4
    public function pad(int $size, $value): self
2790
    {
2791 4
        return static::create(
2792 4
            \array_pad($this->getArray(), $size, $value),
2793 4
            $this->iteratorClass,
2794 4
            false
2795
        );
2796
    }
2797
2798
    /**
2799
     * Pop a specified value off the end of the current array.
2800
     *
2801
     * @return mixed
2802
     *               <p>(Mutable) The popped element from the current array.</p>
2803
     */
2804 16
    public function pop()
2805
    {
2806 16
        $this->generatorToArray();
2807
2808 16
        return \array_pop($this->array);
2809
    }
2810
2811
    /**
2812
     * Prepend a (key) + value to the current array.
2813
     *
2814
     * @param mixed $value
2815
     * @param mixed $key
2816
     *
2817
     * @return static
2818
     *                <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2819
     */
2820 8
    public function prepend($value, $key = null): self
2821
    {
2822 8
        $this->generatorToArray();
2823
2824 8
        if ($key === null) {
2825 8
            \array_unshift($this->array, $value);
2826
        } else {
2827
            /** @noinspection AdditionOperationOnArraysInspection */
2828 1
            $this->array = [$key => $value] + $this->array;
2829
        }
2830
2831 8
        return $this;
2832
    }
2833
2834
    /**
2835
     * Add a suffix to each key.
2836
     *
2837
     * @param mixed $suffix
2838
     *
2839
     * @return static
2840
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2841
     */
2842 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...
2843
    {
2844
        // init
2845 10
        $result = [];
2846
2847 10
        foreach ($this->getGenerator() as $key => $item) {
2848 9
            if ($item instanceof self) {
2849
                $result[$key] = $item->prependToEachKey($suffix);
2850 9
            } elseif (\is_array($item)) {
2851
                $result[$key] = self::create(
2852
                    $item,
2853
                    $this->iteratorClass,
2854
                    false
2855
                )->prependToEachKey($suffix)
2856
                    ->toArray();
2857
            } else {
2858 9
                $result[$key . $suffix] = $item;
2859
            }
2860
        }
2861
2862 10
        return self::create(
2863 10
            $result,
2864 10
            $this->iteratorClass,
2865 10
            false
2866
        );
2867
    }
2868
2869
    /**
2870
     * Add a suffix to each value.
2871
     *
2872
     * @param mixed $suffix
2873
     *
2874
     * @return static
2875
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2876
     */
2877 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...
2878
    {
2879
        // init
2880 10
        $result = [];
2881
2882 10
        foreach ($this->getGenerator() as $key => $item) {
2883 9
            if ($item instanceof self) {
2884
                $result[$key] = $item->prependToEachValue($suffix);
2885 9
            } elseif (\is_array($item)) {
2886
                $result[$key] = self::create(
2887
                    $item,
2888
                    $this->iteratorClass,
2889
                    false
2890
                )->prependToEachValue($suffix)
2891
                    ->toArray();
2892 9
            } elseif (\is_object($item)) {
2893 1
                $result[$key] = $item;
2894
            } else {
2895 8
                $result[$key] = $item . $suffix;
2896
            }
2897
        }
2898
2899 10
        return self::create(
2900 10
            $result,
2901 10
            $this->iteratorClass,
2902 10
            false
2903
        );
2904
    }
2905
2906
    /**
2907
     * Push one or more values onto the end of array at once.
2908
     *
2909
     * @return static
2910
     *                <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2911
     */
2912 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...
2913
    {
2914 4
        $this->generatorToArray();
2915
2916 4
        if (\func_num_args()) {
2917 4
            $args = \array_merge([&$this->array], \func_get_args());
2918 4
            \array_push(...$args);
2919
        }
2920
2921 4
        return $this;
2922
    }
2923
2924
    /**
2925
     * Get a random value from the current array.
2926
     *
2927
     * @param int|null $number <p>How many values you will take?</p>
2928
     *
2929
     * @return static
2930
     *                <p>(Immutable)</p>
2931
     */
2932 18
    public function randomImmutable(int $number = null): self
2933
    {
2934 18
        $this->generatorToArray();
2935
2936 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...
2937 1
            return static::create(
2938 1
                [],
2939 1
                $this->iteratorClass,
2940 1
                false
2941
            );
2942
        }
2943
2944 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...
2945
            /** @noinspection NonSecureArrayRandUsageInspection */
2946 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
2947
2948 13
            return static::create(
2949 13
                $arrayRandValue,
2950 13
                $this->iteratorClass,
2951 13
                false
2952
            );
2953
        }
2954
2955 5
        $arrayTmp = $this->array;
2956
        /** @noinspection NonSecureShuffleUsageInspection */
2957 5
        \shuffle($arrayTmp);
2958
2959 5
        return static::create(
2960 5
            $arrayTmp,
2961 5
            $this->iteratorClass,
2962 5
            false
2963 5
        )->firstsImmutable($number);
2964
    }
2965
2966
    /**
2967
     * Pick a random key/index from the keys of this array.
2968
     *
2969
     * @throws \RangeException If array is empty
2970
     *
2971
     * @return mixed
2972
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2973
     */
2974 4
    public function randomKey()
2975
    {
2976 4
        $result = $this->randomKeys(1);
2977
2978 4
        if (!isset($result[0])) {
2979
            $result[0] = null;
2980
        }
2981
2982 4
        return $result[0];
2983
    }
2984
2985
    /**
2986
     * Pick a given number of random keys/indexes out of this array.
2987
     *
2988
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2989
     *
2990
     * @throws \RangeException If array is empty
2991
     *
2992
     * @return static
2993
     *                <p>(Immutable)</p>
2994
     */
2995 13
    public function randomKeys(int $number): self
2996
    {
2997 13
        $this->generatorToArray();
2998
2999 13
        $count = \count($this->array, \COUNT_NORMAL);
3000
3001 13
        if ($number === 0 || $number > $count) {
3002 2
            throw new \RangeException(
3003 2
                \sprintf(
3004 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
3005 2
                    $number,
3006 2
                    $count
3007
                )
3008
            );
3009
        }
3010
3011 11
        $result = (array) \array_rand($this->array, $number);
3012
3013 11
        return static::create(
3014 11
            $result,
3015 11
            $this->iteratorClass,
3016 11
            false
3017
        );
3018
    }
3019
3020
    /**
3021
     * Get a random value from the current array.
3022
     *
3023
     * @param int|null $number <p>How many values you will take?</p>
3024
     *
3025
     * @return static
3026
     *                <p>(Mutable)</p>
3027
     */
3028 17
    public function randomMutable(int $number = null): self
3029
    {
3030 17
        $this->generatorToArray();
3031
3032 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...
3033
            return static::create(
3034
                [],
3035
                $this->iteratorClass,
3036
                false
3037
            );
3038
        }
3039
3040 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...
3041
            /** @noinspection NonSecureArrayRandUsageInspection */
3042 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3043 7
            $this->array = $arrayRandValue;
3044
3045 7
            return $this;
3046
        }
3047
3048
        /** @noinspection NonSecureShuffleUsageInspection */
3049 11
        \shuffle($this->array);
3050
3051 11
        return $this->firstsMutable($number);
3052
    }
3053
3054
    /**
3055
     * Pick a random value from the values of this array.
3056
     *
3057
     * @return mixed
3058
     *               <p>Get a random value or null if there wasn't a value.</p>
3059
     */
3060 4
    public function randomValue()
3061
    {
3062 4
        $result = $this->randomImmutable();
3063
3064 4
        if (!isset($result[0])) {
3065
            $result[0] = null;
3066
        }
3067
3068 4
        return $result[0];
3069
    }
3070
3071
    /**
3072
     * Pick a given number of random values out of this array.
3073
     *
3074
     * @param int $number
3075
     *
3076
     * @return static
3077
     *                <p>(Mutable)</p>
3078
     */
3079 7
    public function randomValues(int $number): self
3080
    {
3081 7
        return $this->randomMutable($number);
3082
    }
3083
3084
    /**
3085
     * Get a random value from an array, with the ability to skew the results.
3086
     *
3087
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3088
     *
3089
     * @param array    $array
3090
     * @param int|null $number <p>How many values you will take?</p>
3091
     *
3092
     * @return static
3093
     *                <p>(Immutable)</p>
3094
     */
3095 9
    public function randomWeighted(array $array, int $number = null): self
3096
    {
3097
        // init
3098 9
        $options = [];
3099
3100 9
        foreach ($array as $option => $weight) {
3101 9
            if ($this->searchIndex($option) !== false) {
3102 2
                for ($i = 0; $i < $weight; ++$i) {
3103 1
                    $options[] = $option;
3104
                }
3105
            }
3106
        }
3107
3108 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3109
    }
3110
3111
    /**
3112
     * Reduce the current array via callable e.g. anonymous-function.
3113
     *
3114
     * @param \callable $callable
3115
     * @param array     $init
3116
     *
3117
     * @return static
3118
     *                <p>(Immutable)</p>
3119
     */
3120 14
    public function reduce($callable, array $init = []): self
3121
    {
3122 14
        if ($this->generator) {
3123 1
            $result = $init;
3124
3125 1
            foreach ($this->getGenerator() as $value) {
3126 1
                $result = $callable($result, $value);
3127
            }
3128
3129 1
            return static::create(
3130 1
                $result,
3131 1
                $this->iteratorClass,
3132 1
                false
3133
            );
3134
        }
3135
3136 14
        $result = \array_reduce($this->array, $callable, $init);
3137
3138 14
        if ($result === null) {
3139
            $this->array = [];
3140
        } else {
3141 14
            $this->array = (array) $result;
3142
        }
3143
3144 14
        return static::create(
3145 14
            $this->array,
3146 14
            $this->iteratorClass,
3147 14
            false
3148
        );
3149
    }
3150
3151
    /**
3152
     * Create a numerically re-indexed Arrayy object.
3153
     *
3154
     * @return static
3155
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
3156
     */
3157 9
    public function reindex(): self
3158
    {
3159 9
        $this->generatorToArray();
3160
3161 9
        $this->array = \array_values($this->array);
3162
3163 9
        return $this;
3164
    }
3165
3166
    /**
3167
     * Return all items that fail the truth test.
3168
     *
3169
     * @param \Closure $closure
3170
     *
3171
     * @return static
3172
     *                <p>(Immutable)</p>
3173
     */
3174 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...
3175
    {
3176
        // init
3177 1
        $filtered = [];
3178
3179 1
        foreach ($this->getGenerator() as $key => $value) {
3180 1
            if (!$closure($value, $key)) {
3181 1
                $filtered[$key] = $value;
3182
            }
3183
        }
3184
3185 1
        return static::create(
3186 1
            $filtered,
3187 1
            $this->iteratorClass,
3188 1
            false
3189
        );
3190
    }
3191
3192
    /**
3193
     * Remove a value from the current array (optional using dot-notation).
3194
     *
3195
     * @param mixed $key
3196
     *
3197
     * @return static
3198
     *                <p>(Immutable)</p>
3199
     */
3200 18
    public function remove($key): self
3201
    {
3202
        // recursive call
3203 18
        if (\is_array($key)) {
3204
            foreach ($key as $k) {
3205
                $this->internalRemove($k);
3206
            }
3207
3208
            return static::create(
3209
                $this->getArray(),
3210
                $this->iteratorClass,
3211
                false
3212
            );
3213
        }
3214
3215 18
        $this->internalRemove($key);
3216
3217 18
        return static::create(
3218 18
            $this->getArray(),
3219 18
            $this->iteratorClass,
3220 18
            false
3221
        );
3222
    }
3223
3224
    /**
3225
     * Remove the first value from the current array.
3226
     *
3227
     * @return static
3228
     *                <p>(Immutable)</p>
3229
     */
3230 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...
3231
    {
3232 7
        $tmpArray = $this->getArray();
3233
3234 7
        \array_shift($tmpArray);
3235
3236 7
        return static::create(
3237 7
            $tmpArray,
3238 7
            $this->iteratorClass,
3239 7
            false
3240
        );
3241
    }
3242
3243
    /**
3244
     * Remove the last value from the current array.
3245
     *
3246
     * @return static
3247
     *                <p>(Immutable)</p>
3248
     */
3249 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...
3250
    {
3251 7
        $tmpArray = $this->getArray();
3252
3253 7
        \array_pop($tmpArray);
3254
3255 7
        return static::create(
3256 7
            $tmpArray,
3257 7
            $this->iteratorClass,
3258 7
            false
3259
        );
3260
    }
3261
3262
    /**
3263
     * Removes a particular value from an array (numeric or associative).
3264
     *
3265
     * @param mixed $value
3266
     *
3267
     * @return static
3268
     *                <p>(Immutable)</p>
3269
     */
3270 7
    public function removeValue($value): self
3271
    {
3272 7
        $this->generatorToArray();
3273
3274
        // init
3275 7
        $isNumericArray = true;
3276
3277 7
        foreach ($this->getGenerator() as $key => $item) {
3278 6
            if ($item === $value) {
3279 6
                if (!\is_int($key)) {
3280
                    $isNumericArray = false;
3281
                }
3282 6
                unset($this->array[$key]);
3283
            }
3284
        }
3285
3286 7
        if ($isNumericArray) {
3287 7
            $this->array = \array_values($this->array);
3288
        }
3289
3290 7
        return static::create(
3291 7
            $this->array,
3292 7
            $this->iteratorClass,
3293 7
            false
3294
        );
3295
    }
3296
3297
    /**
3298
     * Generate array of repeated arrays.
3299
     *
3300
     * @param int $times <p>How many times has to be repeated.</p>
3301
     *
3302
     * @return static
3303
     *                <p>(Immutable)</p>
3304
     */
3305 1
    public function repeat($times): self
3306
    {
3307 1
        if ($times === 0) {
3308 1
            return new static();
3309
        }
3310
3311 1
        return static::create(
3312 1
            \array_fill(0, (int) $times, $this->getArray()),
3313 1
            $this->iteratorClass,
3314 1
            false
3315
        );
3316
    }
3317
3318
    /**
3319
     * Replace a key with a new key/value pair.
3320
     *
3321
     * @param mixed $replace
3322
     * @param mixed $key
3323
     * @param mixed $value
3324
     *
3325
     * @return static
3326
     *                <p>(Immutable)</p>
3327
     */
3328 2
    public function replace($replace, $key, $value): self
3329
    {
3330 2
        $that = $this->remove($replace);
3331
3332 2
        return $that->set($key, $value);
3333
    }
3334
3335
    /**
3336
     * Create an array using the current array as values and the other array as keys.
3337
     *
3338
     * @param array $keys <p>An array of keys.</p>
3339
     *
3340
     * @return static
3341
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
3342
     */
3343 2
    public function replaceAllKeys(array $keys): self
3344
    {
3345 2
        return static::create(
3346 2
            \array_combine($keys, $this->getArray()),
3347 2
            $this->iteratorClass,
3348 2
            false
3349
        );
3350
    }
3351
3352
    /**
3353
     * Create an array using the current array as keys and the other array as values.
3354
     *
3355
     * @param array $array <p>An array o values.</p>
3356
     *
3357
     * @return static
3358
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3359
     */
3360 2
    public function replaceAllValues(array $array): self
3361
    {
3362 2
        return static::create(
3363 2
            \array_combine($this->array, $array),
3364 2
            $this->iteratorClass,
3365 2
            false
3366
        );
3367
    }
3368
3369
    /**
3370
     * Replace the keys in an array with another set.
3371
     *
3372
     * @param array $keys <p>An array of keys matching the array's size</p>
3373
     *
3374
     * @return static
3375
     *                <p>(Immutable)</p>
3376
     */
3377 1
    public function replaceKeys(array $keys): self
3378
    {
3379 1
        $values = \array_values($this->getArray());
3380 1
        $result = \array_combine($keys, $values);
3381
3382 1
        return static::create(
3383 1
            $result,
3384 1
            $this->iteratorClass,
3385 1
            false
3386
        );
3387
    }
3388
3389
    /**
3390
     * Replace the first matched value in an array.
3391
     *
3392
     * @param mixed $search      <p>The value to replace.</p>
3393
     * @param mixed $replacement <p>The value to replace.</p>
3394
     *
3395
     * @return static
3396
     *                <p>(Immutable)</p>
3397
     */
3398 3
    public function replaceOneValue($search, $replacement = ''): self
3399
    {
3400 3
        $array = $this->getArray();
3401 3
        $key = \array_search($search, $array, true);
3402
3403 3
        if ($key !== false) {
3404 3
            $array[$key] = $replacement;
3405
        }
3406
3407 3
        return static::create(
3408 3
            $array,
3409 3
            $this->iteratorClass,
3410 3
            false
3411
        );
3412
    }
3413
3414
    /**
3415
     * Replace values in the current array.
3416
     *
3417
     * @param mixed $search      <p>The value to replace.</p>
3418
     * @param mixed $replacement <p>What to replace it with.</p>
3419
     *
3420
     * @return static
3421
     *                <p>(Immutable)</p>
3422
     */
3423 1
    public function replaceValues($search, $replacement = ''): self
3424
    {
3425 1
        $array = $this->each(
3426
            static function ($value) use ($search, $replacement) {
3427 1
                return \str_replace($search, $replacement, $value);
3428 1
            }
3429
        );
3430
3431 1
        return $array;
3432
    }
3433
3434
    /**
3435
     * Get the last elements from index $from until the end of this array.
3436
     *
3437
     * @param int $from
3438
     *
3439
     * @return static
3440
     *                <p>(Immutable)</p>
3441
     */
3442 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...
3443
    {
3444 15
        $tmpArray = $this->getArray();
3445
3446 15
        return static::create(
3447 15
            \array_splice($tmpArray, $from),
3448 15
            $this->iteratorClass,
3449 15
            false
3450
        );
3451
    }
3452
3453
    /**
3454
     * Return the array in the reverse order.
3455
     *
3456
     * @return static
3457
     *                <p>(Mutable) Return this Arrayy object.</p>
3458
     */
3459 8
    public function reverse(): self
3460
    {
3461 8
        $this->generatorToArray();
3462
3463 8
        $this->array = \array_reverse($this->array);
3464
3465 8
        return $this;
3466
    }
3467
3468
    /**
3469
     * Sort an array in reverse order.
3470
     *
3471
     * @param int $sort_flags [optional] <p>
3472
     *                        You may modify the behavior of the sort using the optional
3473
     *                        parameter sort_flags, for details
3474
     *                        see sort.
3475
     *                        </p>
3476
     *
3477
     * @return static
3478
     *                <p>(Mutable) Return this Arrayy object.</p>
3479
     */
3480 4
    public function rsort(int $sort_flags = 0): self
3481
    {
3482 4
        $this->generatorToArray();
3483
3484 4
        \rsort($this->array, $sort_flags);
3485
3486 4
        return $this;
3487
    }
3488
3489
    /**
3490
     * Search for the first index of the current array via $value.
3491
     *
3492
     * @param mixed $value
3493
     *
3494
     * @return false|float|int|string
3495
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
3496
     */
3497 20
    public function searchIndex($value)
3498
    {
3499 20
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
3500 19
            if ($value === $valueFromArray) {
3501 9
                return $keyFromArray;
3502
            }
3503
        }
3504
3505 11
        return false;
3506
    }
3507
3508
    /**
3509
     * Search for the value of the current array via $index.
3510
     *
3511
     * @param mixed $index
3512
     *
3513
     * @return static
3514
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3515
     */
3516 9
    public function searchValue($index): self
3517
    {
3518 9
        $this->generatorToArray();
3519
3520
        // init
3521 9
        $return = [];
3522
3523 9
        if ($this->array === []) {
3524
            return static::create(
3525
                [],
3526
                $this->iteratorClass,
3527
                false
3528
            );
3529
        }
3530
3531
        // php cast "bool"-index into "int"-index
3532 9
        if ((bool) $index === $index) {
3533 1
            $index = (int) $index;
3534
        }
3535
3536 9
        if (\array_key_exists($index, $this->array) === true) {
3537 7
            $return = [$this->array[$index]];
3538
        }
3539
3540 9
        return static::create(
3541 9
            $return,
3542 9
            $this->iteratorClass,
3543 9
            false
3544
        );
3545
    }
3546
3547
    /**
3548
     * Set a value for the current array (optional using dot-notation).
3549
     *
3550
     * @param string $key   <p>The key to set.</p>
3551
     * @param mixed  $value <p>Its value.</p>
3552
     *
3553
     * @return static
3554
     *                <p>(Mutable)</p>
3555
     */
3556 18
    public function set($key, $value): self
3557
    {
3558 18
        $this->generatorToArray();
3559
3560 18
        $this->internalSet($key, $value);
3561
3562 18
        return $this;
3563
    }
3564
3565
    /**
3566
     * Get a value from a array and set it if it was not.
3567
     *
3568
     * WARNING: this method only set the value, if the $key is not already set
3569
     *
3570
     * @param mixed $key      <p>The key</p>
3571
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
3572
     *
3573
     * @return mixed
3574
     *               <p>(Mutable)</p>
3575
     */
3576 11
    public function setAndGet($key, $fallback = null)
3577
    {
3578 11
        $this->generatorToArray();
3579
3580
        // If the key doesn't exist, set it.
3581 11
        if (!$this->has($key)) {
3582 4
            $this->array = $this->set($key, $fallback)->getArray();
3583
        }
3584
3585 11
        return $this->get($key);
3586
    }
3587
3588
    /**
3589
     * Shifts a specified value off the beginning of array.
3590
     *
3591
     * @return mixed
3592
     *               <p>(Mutable) A shifted element from the current array.</p>
3593
     */
3594 4
    public function shift()
3595
    {
3596 4
        $this->generatorToArray();
3597
3598 4
        return \array_shift($this->array);
3599
    }
3600
3601
    /**
3602
     * Shuffle the current array.
3603
     *
3604
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3605
     * @param array $array  [optional]
3606
     *
3607
     * @return static
3608
     *                <p>(Immutable)</p>
3609
     */
3610 1
    public function shuffle(bool $secure = false, array $array = null): self
3611
    {
3612 1
        if ($array === null) {
3613 1
            $array = $this->getArray();
3614
        }
3615
3616 1
        if ($secure !== true) {
3617
            /** @noinspection NonSecureShuffleUsageInspection */
3618 1
            \shuffle($array);
3619
        } else {
3620 1
            $size = \count($array, \COUNT_NORMAL);
3621 1
            $keys = \array_keys($array);
3622 1
            for ($i = $size - 1; $i > 0; --$i) {
3623
                try {
3624 1
                    $r = \random_int(0, $i);
3625
                } catch (\Exception $e) {
3626
                    /** @noinspection RandomApiMigrationInspection */
3627
                    $r = \mt_rand(0, $i);
3628
                }
3629 1
                if ($r !== $i) {
3630 1
                    $temp = $array[$keys[$r]];
3631 1
                    $array[$keys[$r]] = $array[$keys[$i]];
3632 1
                    $array[$keys[$i]] = $temp;
3633
                }
3634
            }
3635
3636
            // reset indices
3637 1
            $array = \array_values($array);
3638
        }
3639
3640 1
        foreach ($array as $key => $value) {
3641
            // check if recursive is needed
3642 1
            if (\is_array($value) === true) {
3643
                $array[$key] = $this->shuffle($secure, $value);
3644
            }
3645
        }
3646
3647 1
        return static::create(
3648 1
            $array,
3649 1
            $this->iteratorClass,
3650 1
            false
3651
        );
3652
    }
3653
3654
    /**
3655
     * Count the values from the current array.
3656
     *
3657
     * alias: for "Arrayy->count()"
3658
     *
3659
     * @param int $mode
3660
     *
3661
     * @return int
3662
     */
3663 20
    public function size(int $mode = \COUNT_NORMAL): int
3664
    {
3665 20
        return $this->count($mode);
3666
    }
3667
3668
    /**
3669
     * Counts all elements in an array, or something in an object.
3670
     *
3671
     * <p>
3672
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3673
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3674
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3675
     * implemented and used in PHP.
3676
     * </p>
3677
     *
3678
     * @return int
3679
     *             <p>
3680
     *             The number of elements in var, which is
3681
     *             typically an array, since anything else will have one
3682
     *             element.
3683
     *             </p>
3684
     *             <p>
3685
     *             If var is not an array or an object with
3686
     *             implemented Countable interface,
3687
     *             1 will be returned.
3688
     *             There is one exception, if var is &null;,
3689
     *             0 will be returned.
3690
     *             </p>
3691
     *             <p>
3692
     *             Caution: count may return 0 for a variable that isn't set,
3693
     *             but it may also return 0 for a variable that has been initialized with an
3694
     *             empty array. Use isset to test if a variable is set.
3695
     *             </p>
3696
     */
3697 10
    public function sizeRecursive(): int
3698
    {
3699 10
        return \count($this->getArray(), \COUNT_RECURSIVE);
3700
    }
3701
3702
    /**
3703
     * Extract a slice of the array.
3704
     *
3705
     * @param int      $offset       <p>Slice begin index.</p>
3706
     * @param int|null $length       <p>Length of the slice.</p>
3707
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3708
     *
3709
     * @return static
3710
     *                <p>A slice of the original array with length $length.</p>
3711
     */
3712 4
    public function slice(int $offset, int $length = null, bool $preserveKeys = false): self
3713
    {
3714 4
        return static::create(
3715 4
            \array_slice(
3716 4
                $this->getArray(),
3717 4
                $offset,
3718 4
                $length,
3719 4
                $preserveKeys
3720
            ),
3721 4
            $this->iteratorClass,
3722 4
            false
3723
        );
3724
    }
3725
3726
    /**
3727
     * Sort the current array and optional you can keep the keys.
3728
     *
3729
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3730
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3731
     *                              <strong>SORT_NATURAL</strong></p>
3732
     * @param bool       $keepKeys
3733
     *
3734
     * @return static
3735
     *                <p>(Mutable) Return this Arrayy object.</p>
3736
     */
3737 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
3738
    {
3739 20
        $this->generatorToArray();
3740
3741 20
        return $this->sorting(
3742 20
            $this->array,
3743
            $direction,
3744
            $strategy,
3745
            $keepKeys
3746
        );
3747
    }
3748
3749
    /**
3750
     * Sort the current array by key.
3751
     *
3752
     * @see http://php.net/manual/en/function.ksort.php
3753
     * @see http://php.net/manual/en/function.krsort.php
3754
     *
3755
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3756
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3757
     *                              <strong>SORT_NATURAL</strong></p>
3758
     *
3759
     * @return static
3760
     *                <p>(Mutable) Return this Arrayy object.</p>
3761
     */
3762 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3763
    {
3764 18
        $this->generatorToArray();
3765
3766 18
        $this->sorterKeys($this->array, $direction, $strategy);
3767
3768 18
        return $this;
3769
    }
3770
3771
    /**
3772
     * Sort the current array by value.
3773
     *
3774
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3775
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3776
     *                              <strong>SORT_NATURAL</strong></p>
3777
     *
3778
     * @return static
3779
     *                <p>(Mutable)</p>
3780
     */
3781 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3782
    {
3783 1
        return $this->sort($direction, $strategy, true);
3784
    }
3785
3786
    /**
3787
     * Sort the current array by value.
3788
     *
3789
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3790
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3791
     *                              <strong>SORT_NATURAL</strong></p>
3792
     *
3793
     * @return static
3794
     *                <p>(Mutable)</p>
3795
     */
3796 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3797
    {
3798 1
        return $this->sort($direction, $strategy, false);
3799
    }
3800
3801
    /**
3802
     * Sort a array by value, by a closure or by a property.
3803
     *
3804
     * - If the sorter is null, the array is sorted naturally.
3805
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3806
     *
3807
     * @param \callable|null $sorter
3808
     * @param int|string     $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3809
     * @param int            $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3810
     *                                  <strong>SORT_NATURAL</strong></p>
3811
     *
3812
     * @return static
3813
     *                <p>(Immutable)</p>
3814
     */
3815 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3816
    {
3817 1
        $array = $this->getArray();
3818 1
        $direction = $this->getDirection($direction);
3819
3820
        // Transform all values into their results.
3821 1
        if ($sorter) {
3822 1
            $arrayy = static::create(
3823 1
                $array,
3824 1
                $this->iteratorClass,
3825 1
                false
3826
            );
3827
3828 1
            $that = $this;
3829 1
            $results = $arrayy->each(
3830
                static function ($value) use ($sorter, $that) {
3831 1
                    return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3832 1
                }
3833
            );
3834
3835 1
            $results = $results->getArray();
3836
        } else {
3837 1
            $results = $array;
3838
        }
3839
3840
        // Sort by the results and replace by original values
3841 1
        \array_multisort($results, $direction, $strategy, $array);
3842
3843 1
        return static::create(
3844 1
            $array,
3845 1
            $this->iteratorClass,
3846 1
            false
3847
        );
3848
    }
3849
3850
    /**
3851
     * Split an array in the given amount of pieces.
3852
     *
3853
     * @param int  $numberOfPieces
3854
     * @param bool $keepKeys
3855
     *
3856
     * @return static
3857
     *                <p>(Immutable)</p>
3858
     */
3859 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
3860
    {
3861 1
        $this->generatorToArray();
3862
3863 1
        $arrayCount = \count($this->array, \COUNT_NORMAL);
3864
3865 1
        if ($arrayCount === 0) {
3866 1
            $result = [];
3867
        } else {
3868 1
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
3869 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
3870
        }
3871
3872 1
        return static::create(
3873 1
            $result,
3874 1
            $this->iteratorClass,
3875 1
            false
3876
        );
3877
    }
3878
3879
    /**
3880
     * Stripe all empty items.
3881
     *
3882
     * @return static
3883
     *                <p>(Immutable)</p>
3884
     */
3885 1
    public function stripEmpty(): self
3886
    {
3887 1
        return $this->filter(
3888
            static function ($item) {
3889 1
                if ($item === null) {
3890 1
                    return false;
3891
                }
3892
3893 1
                return (bool) \trim((string) $item);
3894 1
            }
3895
        );
3896
    }
3897
3898
    /**
3899
     * Swap two values between positions by key.
3900
     *
3901
     * @param int|string $swapA <p>a key in the array</p>
3902
     * @param int|string $swapB <p>a key in the array</p>
3903
     *
3904
     * @return static
3905
     *                <p>(Immutable)</p>
3906
     */
3907 1
    public function swap($swapA, $swapB): self
3908
    {
3909 1
        $array = $this->getArray();
3910
3911 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3912
3913 1
        return static::create(
3914 1
            $array,
3915 1
            $this->iteratorClass,
3916 1
            false
3917
        );
3918
    }
3919
3920
    /**
3921
     * alias: for "Arrayy->getArray()"
3922
     *
3923
     * @see Arrayy::getArray()
3924
     */
3925 198
    public function toArray()
3926
    {
3927 198
        return $this->getArray();
3928
    }
3929
3930
    /**
3931
     * Convert the current array to JSON.
3932
     *
3933
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3934
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3935
     *
3936
     * @return string
3937
     */
3938 6
    public function toJson(int $options = 0, int $depth = 512): string
3939
    {
3940
        /** @noinspection PhpComposerExtensionStubsInspection */
3941 6
        $return = \json_encode($this->getArray(), $options, $depth);
3942 6
        if ($return === false) {
3943
            return '';
3944
        }
3945
3946 6
        return $return;
3947
    }
3948
3949
    /**
3950
     * Implodes array to a string with specified separator.
3951
     *
3952
     * @param string $separator [optional] <p>The element's separator.</p>
3953
     *
3954
     * @return string
3955
     *                <p>The string representation of array, separated by ",".</p>
3956
     */
3957 19
    public function toString(string $separator = ','): string
3958
    {
3959 19
        return $this->implode($separator);
3960
    }
3961
3962
    /**
3963
     * Return a duplicate free copy of the current array.
3964
     *
3965
     * @return static
3966
     *                <p>(Mutable)</p>
3967
     */
3968 10
    public function unique(): self
3969
    {
3970
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3971
3972 10
        $this->array = $this->reduce(
3973
            static function ($resultArray, $value) {
3974 9
                if (!\in_array($value, $resultArray, true)) {
3975 9
                    $resultArray[] = $value;
3976
                }
3977
3978 9
                return $resultArray;
3979 10
            },
3980 10
            []
3981 10
        )->getArray();
3982 10
        $this->generator = null;
3983
3984 10
        return $this;
3985
    }
3986
3987
    /**
3988
     * Return a duplicate free copy of the current array. (with the old keys)
3989
     *
3990
     * @return static
3991
     *                <p>(Mutable)</p>
3992
     */
3993 11
    public function uniqueKeepIndex(): self
3994
    {
3995
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3996
3997
        // init
3998 11
        $array = $this->getArray();
3999
4000 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...
4001 11
            \array_keys($array),
4002
            static function ($resultArray, $key) use ($array) {
4003 10
                if (!\in_array($array[$key], $resultArray, true)) {
4004 10
                    $resultArray[$key] = $array[$key];
4005
                }
4006
4007 10
                return $resultArray;
4008 11
            },
4009 11
            []
4010
        );
4011 11
        $this->generator = null;
4012
4013 11
        if ($this->array === null) {
4014
            $this->array = [];
4015
        } else {
4016 11
            $this->array = (array) $this->array;
4017
        }
4018
4019 11
        return $this;
4020
    }
4021
4022
    /**
4023
     * alias: for "Arrayy->unique()"
4024
     *
4025
     * @return static
4026
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
4027
     *
4028
     * @see Arrayy::unique()
4029
     */
4030 10
    public function uniqueNewIndex(): self
4031
    {
4032 10
        return $this->unique();
4033
    }
4034
4035
    /**
4036
     * Prepends one or more values to the beginning of array at once.
4037
     *
4038
     * @return static
4039
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
4040
     */
4041 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...
4042
    {
4043 4
        $this->generatorToArray();
4044
4045 4
        if (\func_num_args()) {
4046 4
            $args = \array_merge([&$this->array], \func_get_args());
4047 4
            \array_unshift(...$args);
4048
        }
4049
4050 4
        return $this;
4051
    }
4052
4053
    /**
4054
     * Get all values from a array.
4055
     *
4056
     * @return static
4057
     *                <p>(Immutable)</p>
4058
     */
4059 2
    public function values(): self
4060
    {
4061 2
        return static::create(
4062 2
            \array_values($this->getArray()),
4063 2
            $this->iteratorClass,
4064 2
            false
4065
        );
4066
    }
4067
4068
    /**
4069
     * Apply the given function to every element in the array, discarding the results.
4070
     *
4071
     * @param \callable $callable
4072
     * @param bool      $recursive <p>Whether array will be walked recursively or no</p>
4073
     *
4074
     * @return static
4075
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
4076
     */
4077 37
    public function walk($callable, bool $recursive = false): self
4078
    {
4079 37
        $this->generatorToArray();
4080
4081 37
        if ($recursive === true) {
4082 32
            \array_walk_recursive($this->array, $callable);
4083
        } else {
4084 18
            \array_walk($this->array, $callable);
4085
        }
4086
4087 37
        return $this;
4088
    }
4089
4090
    /**
4091
     * Convert an array into a object.
4092
     *
4093
     * @param array $array PHP array
4094
     *
4095
     * @return \stdClass
4096
     */
4097 4
    protected static function arrayToObject(array $array = []): \stdClass
4098
    {
4099
        // init
4100 4
        $object = new \stdClass();
4101
4102 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
4103 1
            return $object;
4104
        }
4105
4106 3
        foreach ($array as $name => $value) {
4107 3
            if (\is_array($value)) {
4108 1
                $object->{$name} = self::arrayToObject($value);
4109
            } else {
4110 3
                $object->{$name} = $value;
4111
            }
4112
        }
4113
4114 3
        return $object;
4115
    }
4116
4117
    /**
4118
     * @param array|\Generator|null $input        <p>
4119
     *                                            An array containing keys to return.
4120
     *                                            </p>
4121
     * @param mixed                 $search_value [optional] <p>
4122
     *                                            If specified, then only keys containing these values are returned.
4123
     *                                            </p>
4124
     * @param bool                  $strict       [optional] <p>
4125
     *                                            Determines if strict comparison (===) should be used during the
4126
     *                                            search.
4127
     *                                            </p>
4128
     *
4129
     * @return array
4130
     *               <p>an array of all the keys in input</p>
4131
     */
4132 10
    protected function array_keys_recursive(
4133
        $input = null,
4134
        $search_value = null,
4135
        bool $strict = true
4136
    ): array {
4137
        // init
4138 10
        $keys = [];
4139 10
        $keysTmp = [[]]; // the inner empty array covers cases when no loops were made
4140
4141 10
        if ($input === null) {
4142
            $input = $this->getGenerator();
4143
        }
4144
4145 10
        foreach ($input as $key => $value) {
4146
            if (
4147 10
                $search_value === null
4148
                ||
4149
                (
4150
                    \is_array($search_value) === true
4151
                    &&
4152 10
                    \in_array($key, $search_value, $strict)
4153
                )
4154
            ) {
4155 10
                $keys[] = $key;
4156
            }
4157
4158
            // check if recursive is needed
4159 10
            if (\is_array($value) === true) {
4160 4
                $keysTmp[] = $this->array_keys_recursive($value);
4161
            }
4162
        }
4163
4164 10
        return \array_merge($keys, ...$keysTmp);
4165
    }
4166
4167
    /**
4168
     * @param mixed      $path
4169
     * @param \callable  $callable
4170
     * @param array|null $currentOffset
4171
     */
4172 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
4173
    {
4174 4
        $this->generatorToArray();
4175
4176 4
        if ($currentOffset === null) {
4177 4
            $currentOffset = &$this->array;
4178
        }
4179
4180 4
        $explodedPath = \explode($this->pathSeparator, $path);
4181 4
        if ($explodedPath === false) {
4182
            return;
4183
        }
4184
4185 4
        $nextPath = \array_shift($explodedPath);
4186
4187 4
        if (!isset($currentOffset[$nextPath])) {
4188
            return;
4189
        }
4190
4191 4
        if (!empty($explodedPath)) {
4192 1
            $this->callAtPath(
4193 1
                \implode($this->pathSeparator, $explodedPath),
4194
                $callable,
4195 1
                $currentOffset[$nextPath]
4196
            );
4197
        } else {
4198 4
            $callable($currentOffset[$nextPath]);
4199
        }
4200 4
    }
4201
4202
    /**
4203
     * create a fallback for array
4204
     *
4205
     * 1. use the current array, if it's a array
4206
     * 2. fallback to empty array, if there is nothing
4207
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
4208
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
4209
     * 5. call "__toArray()" on object, if the method exists
4210
     * 6. cast a string or object with "__toString()" into an array
4211
     * 7. throw a "InvalidArgumentException"-Exception
4212
     *
4213
     * @param mixed $data
4214
     *
4215
     * @throws \InvalidArgumentException
4216
     *
4217
     * @return array
4218
     */
4219 910
    protected function fallbackForArray(&$data): array
4220
    {
4221 910
        if (\is_array($data)) {
4222 907
            return $data;
4223
        }
4224
4225 17
        if (!$data) {
4226 6
            return [];
4227
        }
4228
4229 16
        $isObject = \is_object($data);
4230
4231 16
        if ($isObject && $data instanceof self) {
4232 1
            return $data->getArray();
4233
        }
4234
4235 15
        if ($isObject && $data instanceof \ArrayObject) {
4236
            return $data->getArrayCopy();
4237
        }
4238
4239 15
        if ($isObject && $data instanceof \Generator) {
4240
            return static::createFromGeneratorImmutable($data)->getArray();
4241
        }
4242
4243 15
        if ($isObject && $data instanceof \Traversable) {
4244
            return static::createFromObject($data)->getArray();
4245
        }
4246
4247 15
        if (\is_callable($data)) {
4248 6
            $this->generator = new ArrayyRewindableGenerator($data);
4249
4250 6
            return [];
4251
        }
4252
4253 9
        if ($isObject && \method_exists($data, '__toArray')) {
4254
            return (array) $data->__toArray();
4255
        }
4256
4257
        if (
4258 9
            \is_string($data)
4259
            ||
4260 9
            ($isObject && \method_exists($data, '__toString'))
4261
        ) {
4262 7
            return [(string) $data];
4263
        }
4264
4265 2
        throw new \InvalidArgumentException(
4266 2
            'Passed value should be a array'
4267
        );
4268
    }
4269
4270
    /**
4271
     * Get correct PHP constant for direction.
4272
     *
4273
     * @param int|string $direction
4274
     *
4275
     * @return int
4276
     */
4277 39
    protected function getDirection($direction): int
4278
    {
4279 39
        if (\is_string($direction)) {
4280 10
            $direction = \strtolower($direction);
4281
4282 10
            if ($direction === 'desc') {
4283 2
                $direction = \SORT_DESC;
4284
            } else {
4285 8
                $direction = \SORT_ASC;
4286
            }
4287
        }
4288
4289
        if (
4290 39
            $direction !== \SORT_DESC
4291
            &&
4292 39
            $direction !== \SORT_ASC
4293
        ) {
4294
            $direction = \SORT_ASC;
4295
        }
4296
4297 39
        return $direction;
4298
    }
4299
4300
    /**
4301
     * @param mixed               $glue
4302
     * @param array|static|string $pieces
4303
     * @param bool                $useKeys
4304
     *
4305
     * @return string
4306
     */
4307 35
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
4308
    {
4309 35
        if ($pieces instanceof self) {
4310 1
            $pieces = $pieces->getArray();
4311
        }
4312
4313 35
        if (\is_array($pieces)) {
4314 35
            $pieces_count = \count($pieces, \COUNT_NORMAL);
4315 35
            $pieces_count_not_zero = $pieces_count > 0;
4316
4317 35
            return \implode(
4318 35
                $glue,
4319 35
                \array_map(
4320 35
                    [$this, 'implode_recursive'],
4321 35
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
4322 35
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
4323
                )
4324
            );
4325
        }
4326
4327 35
        return (string) $pieces;
4328
    }
4329
4330
    /**
4331
     * @param mixed                 $needle   <p>
4332
     *                                        The searched value.
4333
     *                                        </p>
4334
     *                                        <p>
4335
     *                                        If needle is a string, the comparison is done
4336
     *                                        in a case-sensitive manner.
4337
     *                                        </p>
4338
     * @param array|\Generator|null $haystack <p>
4339
     *                                        The array.
4340
     *                                        </p>
4341
     * @param bool                  $strict   [optional] <p>
4342
     *                                        If the third parameter strict is set to true
4343
     *                                        then the in_array function will also check the
4344
     *                                        types of the
4345
     *                                        needle in the haystack.
4346
     *                                        </p>
4347
     *
4348
     * @return bool
4349
     *              <p>true if needle is found in the array, false otherwise</p>
4350
     */
4351 44
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
4352
    {
4353 44
        if ($haystack === null) {
4354
            $haystack = $this->getGenerator();
4355
        }
4356
4357 44
        foreach ($haystack as $item) {
4358 36
            if (\is_array($item) === true) {
4359 8
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
4360
            } else {
4361 36
                $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
4362
            }
4363
4364 36
            if ($returnTmp === true) {
4365 26
                return true;
4366
            }
4367
        }
4368
4369 18
        return false;
4370
    }
4371
4372
    /**
4373
     * @param mixed $value
4374
     */
4375
    protected function internalGetArray(&$value)
4376
    {
4377
        if ($value instanceof self) {
4378
            $valueTmp = $value->getArray();
4379
            if (\count($valueTmp, \COUNT_NORMAL) === 0) {
4380
                $value = [];
4381
            } else {
4382
                /** @noinspection PhpUnusedLocalVariableInspection */
4383
                $value = &$valueTmp;
4384
            }
4385
        }
4386
4387
        /** @noinspection PhpComposerExtensionStubsInspection */
4388
        /** @noinspection NotOptimalIfConditionsInspection */
4389
        if (
4390
            \class_exists('JsonSerializable')
4391
            &&
4392
            $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...
4393
        ) {
4394
4395
            /** @noinspection PhpUnusedLocalVariableInspection */
4396
            $value = &$value->jsonSerialize();
4397
        }
4398
    }
4399
4400
    /**
4401
     * Internal mechanics of remove method.
4402
     *
4403
     * @param mixed $key
4404
     *
4405
     * @return bool
4406
     */
4407 18
    protected function internalRemove($key): bool
4408
    {
4409 18
        $this->generatorToArray();
4410
4411
        if (
4412 18
            $this->pathSeparator
4413
            &&
4414 18
            \is_string($key)
4415
            &&
4416 18
            \strpos($key, $this->pathSeparator) !== false
4417
        ) {
4418
            $path = \explode($this->pathSeparator, (string) $key);
4419
4420
            if ($path !== false) {
4421
                // crawl though the keys
4422
                while (\count($path, \COUNT_NORMAL) > 1) {
4423
                    $key = \array_shift($path);
4424
4425
                    if (!$this->has($key)) {
4426
                        return false;
4427
                    }
4428
4429
                    $this->array = &$this->array[$key];
4430
                }
4431
4432
                $key = \array_shift($path);
4433
            }
4434
        }
4435
4436 18
        unset($this->array[$key]);
4437
4438 18
        return true;
4439
    }
4440
4441
    /**
4442
     * Internal mechanic of set method.
4443
     *
4444
     * @param int|string|null $key
4445
     * @param mixed           $value
4446
     * @param bool            $checkProperties
4447
     *
4448
     * @return bool
4449
     */
4450 798
    protected function internalSet($key, $value, $checkProperties = true): bool
4451
    {
4452
        if (
4453 798
            $checkProperties === true
4454
            &&
4455 798
            $this->properties !== []
4456
        ) {
4457 13
            if (isset($this->properties[$key]) === false) {
4458
                throw new \InvalidArgumentException('The key ' . $key . ' does not exists as @property in the class (' . \get_class($this) . ').');
4459
            }
4460
4461 13
            $this->properties[$key]->checkType($value);
4462
        }
4463
4464 797
        if ($key === null) {
4465
            return false;
4466
        }
4467
4468 797
        $this->generatorToArray();
4469
4470 797
        $array = &$this->array;
4471
4472
        if (
4473 797
            $this->pathSeparator
4474
            &&
4475 797
            \is_string($key)
4476
            &&
4477 797
            \strpos($key, $this->pathSeparator) !== false
4478
        ) {
4479 3
            $path = \explode($this->pathSeparator, (string) $key);
4480
4481 3
            if ($path !== false) {
4482
                // crawl through the keys
4483 3
                while (\count($path, \COUNT_NORMAL) > 1) {
4484 3
                    $key = \array_shift($path);
4485
4486 3
                    $array = &$array[$key];
4487
                }
4488
4489 3
                $key = \array_shift($path);
4490
            }
4491
        }
4492
4493 797
        $array[$key] = $value;
4494
4495 797
        return true;
4496
    }
4497
4498
    /**
4499
     * Convert a object into an array.
4500
     *
4501
     * @param object $object
4502
     *
4503
     * @return mixed
4504
     */
4505 5
    protected static function objectToArray($object)
4506
    {
4507 5
        if (!\is_object($object)) {
4508 4
            return $object;
4509
        }
4510
4511 5
        if (\is_object($object)) {
4512 5
            $object = \get_object_vars($object);
4513
        }
4514
4515 5
        return \array_map(['static', 'objectToArray'], $object);
4516
    }
4517
4518
    /**
4519
     * sorting keys
4520
     *
4521
     * @param array      $elements
4522
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4523
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4524
     *                              <strong>SORT_NATURAL</strong></p>
4525
     *
4526
     * @return static
4527
     *                <p>(Mutable) Return this Arrayy object.</p>
4528
     */
4529 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4530
    {
4531 18
        $direction = $this->getDirection($direction);
4532
4533 18
        switch ($direction) {
4534 18
            case 'desc':
4535
            case \SORT_DESC:
4536 6
                \krsort($elements, $strategy);
4537
4538 6
                break;
4539 13
            case 'asc':
4540 13
            case \SORT_ASC:
4541
            default:
4542 13
                \ksort($elements, $strategy);
4543
        }
4544
4545 18
        return $this;
4546
    }
4547
4548
    /**
4549
     * @param array      $elements  <p>Warning: used as reference</p>
4550
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4551
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4552
     *                              <strong>SORT_NATURAL</strong></p>
4553
     * @param bool       $keepKeys
4554
     *
4555
     * @return static
4556
     *                <p>(Mutable) Return this Arrayy object.</p>
4557
     */
4558 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4559
    {
4560 20
        $direction = $this->getDirection($direction);
4561
4562 20
        if (!$strategy) {
4563 20
            $strategy = \SORT_REGULAR;
4564
        }
4565
4566 20
        switch ($direction) {
4567 20
            case 'desc':
4568
            case \SORT_DESC:
4569 9
                if ($keepKeys) {
4570 5
                    \arsort($elements, $strategy);
4571
                } else {
4572 4
                    \rsort($elements, $strategy);
4573
                }
4574
4575 9
                break;
4576 11
            case 'asc':
4577 11
            case \SORT_ASC:
4578
            default:
4579 11
                if ($keepKeys) {
4580 4
                    \asort($elements, $strategy);
4581
                } else {
4582 7
                    \sort($elements, $strategy);
4583
                }
4584
        }
4585
4586 20
        return $this;
4587
    }
4588
4589
    /**
4590
     * @return bool
4591
     */
4592 835
    private function generatorToArray(): bool
4593
    {
4594 835
        if ($this->generator) {
4595 1
            $this->array = $this->getArray();
4596 1
            $this->generator = null;
4597
4598 1
            return true;
4599
        }
4600
4601 835
        return false;
4602
    }
4603
4604
    /**
4605
     * @return Property[]
4606
     */
4607 15
    private function getPropertiesFromPhpDoc(): array
4608
    {
4609 15
        static $PROPERTY_CACHE = [];
4610 15
        $cacheKey = 'Class::' . static::class;
4611
4612 15
        if (isset($PROPERTY_CACHE[$cacheKey])) {
4613 14
            return $PROPERTY_CACHE[$cacheKey];
4614
        }
4615
4616
        // init
4617 2
        $properties = [];
4618
4619 2
        $reflector = new \ReflectionClass($this);
4620 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
4621 2
        $docComment = $reflector->getDocComment();
4622 2
        if ($docComment) {
4623 2
            $docblock = $factory->create($docComment);
4624 2
            foreach ($docblock->getTagsByName('property') as $tag) {
4625
                /* @var $tag \phpDocumentor\Reflection\DocBlock\Tags\Property */
4626 2
                $properties[$tag->getVariableName()] = Property::fromPhpDocumentorProperty($tag);
4627
            }
4628
        }
4629
4630 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
4631
    }
4632
}
4633