Completed
Push — master ( 394461...0f70f1 )
by Lars
01:50
created

Arrayy::callAtPath()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5.0406

Importance

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

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

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

Loading history...
606
    {
607
        if (!\is_callable($function)) {
608
            throw new \InvalidArgumentException(
609
                'Passed function must be callable'
610
            );
611
        }
612
613
        $this->generatorToArray();
614
615
        \uasort($this->array, $function);
616
617
        return $this;
618
    }
619
620
    /**
621
     * Sort the entries by keys using a user-defined comparison function.
622
     *
623
     * @param \callable $function
624
     *
625
     * @throws \InvalidArgumentException
626
     *
627
     * @return static
628
     *                <p>(Mutable) Return this Arrayy object.</p>
629
     */
630 5
    public function uksort($function): self
631
    {
632 5
        return $this->customSortKeys($function);
633
    }
634
635
    /**
636
     * Unserialize an string and return the instance of the "Arrayy"-class.
637
     *
638
     * @param string $string
639
     *
640
     * @return static
641
     */
642 2
    public function unserialize($string): self
643
    {
644 2
        parent::unserialize($string);
645
646 2
        return $this;
647
    }
648
649
    /**
650
     * Append a (key) + values to the current array.
651
     *
652
     * @param array $values
653
     * @param mixed $key
654
     *
655
     * @return static
656
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
657
     */
658 1
    public function appendArrayValues(array $values, $key = null): self
659
    {
660 1
        $this->generatorToArray();
661
662 1
        if ($key !== null) {
663
            if (
664 1
                isset($this->array[$key])
665
                &&
666 1
                \is_array($this->array[$key])
667
            ) {
668 1
                foreach ($values as $value) {
669 1
                    $this->array[$key][] = $value;
670
                }
671
            } else {
672
                foreach ($values as $value) {
673 1
                    $this->array[$key] = $value;
674
                }
675
            }
676
        } else {
677
            foreach ($values as $value) {
678
                $this->array[] = $value;
679
            }
680
        }
681
682 1
        return $this;
683
    }
684
685
    /**
686
     * Add a suffix to each key.
687
     *
688
     * @param mixed $prefix
689
     *
690
     * @return static
691
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
692
     */
693 10 View Code Duplication
    public function appendToEachKey($prefix): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

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

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

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

Loading history...
722
    {
723
        // init
724 10
        $result = [];
725
726 10
        foreach ($this->getGenerator() as $key => $item) {
727 9
            if ($item instanceof self) {
728
                $result[$key] = $item->appendToEachValue($prefix);
729 9
            } elseif (\is_array($item)) {
730
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
731 9
            } elseif (\is_object($item)) {
732 1
                $result[$key] = $item;
733
            } else {
734 9
                $result[$key] = $prefix . $item;
735
            }
736
        }
737
738 10
        return self::create($result, $this->iteratorClass, false);
739
    }
740
741
    /**
742
     * Sort an array in reverse order and maintain index association.
743
     *
744
     * @return static
745
     *                <p>(Mutable) Return this Arrayy object.</p>
746
     */
747 4
    public function arsort(): self
748
    {
749 4
        $this->generatorToArray();
750
751 4
        \arsort($this->array);
752
753 4
        return $this;
754
    }
755
756
    /**
757
     * Iterate over the current array and execute a callback for each loop.
758
     *
759
     * @param \Closure $closure
760
     *
761
     * @return static
762
     *                <p>(Immutable)</p>
763
     */
764 2
    public function at(\Closure $closure): self
765
    {
766 2
        $arrayy = clone $this;
767
768 2
        foreach ($arrayy->getGenerator() as $key => $value) {
769 2
            $closure($value, $key);
770
        }
771
772 2
        return static::create(
773 2
            $arrayy->toArray(),
774 2
            $this->iteratorClass,
775 2
            false
776
        );
777
    }
778
779
    /**
780
     * Returns the average value of the current array.
781
     *
782
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
783
     *
784
     * @return float|int
785
     *                   <p>The average value.</p>
786
     */
787 10
    public function average($decimals = 0)
788
    {
789 10
        $count = \count($this->getArray(), \COUNT_NORMAL);
790
791 10
        if (!$count) {
792 2
            return 0;
793
        }
794
795 8
        if (!\is_int($decimals)) {
796 3
            $decimals = 0;
797
        }
798
799 8
        return \round(\array_sum($this->getArray()) / $count, $decimals);
800
    }
801
802
    /**
803
     * Changes all keys in an array.
804
     *
805
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
806
     *                  or <strong>CASE_LOWER</strong> (default)</p>
807
     *
808
     * @return static
809
     *                <p>(Immutable)</p>
810
     */
811 1
    public function changeKeyCase(int $case = \CASE_LOWER): self
812
    {
813
        if (
814 1
            $case !== \CASE_LOWER
815
            &&
816 1
            $case !== \CASE_UPPER
817
        ) {
818
            $case = \CASE_LOWER;
819
        }
820
821 1
        $return = [];
822 1
        foreach ($this->getGenerator() as $key => $value) {
823 1
            if ($case === \CASE_LOWER) {
824
                /** @noinspection PhpComposerExtensionStubsInspection */
825 1
                $key = \mb_strtolower((string) $key);
826
            } else {
827
                /** @noinspection PhpComposerExtensionStubsInspection */
828 1
                $key = \mb_strtoupper((string) $key);
829
            }
830
831 1
            $return[$key] = $value;
832
        }
833
834 1
        return static::create(
835 1
            $return,
836 1
            $this->iteratorClass,
837 1
            false
838
        );
839
    }
840
841
    /**
842
     * Change the path separator of the array wrapper.
843
     *
844
     * By default, the separator is: "."
845
     *
846
     * @param string $separator <p>Separator to set.</p>
847
     *
848
     * @return static
849
     *                <p>Mutable</p>
850
     */
851 10
    public function changeSeparator($separator): self
852
    {
853 10
        $this->pathSeparator = $separator;
854
855 10
        return $this;
856
    }
857
858
    /**
859
     * Create a chunked version of the current array.
860
     *
861
     * @param int  $size         <p>Size of each chunk.</p>
862
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
863
     *
864
     * @return static
865
     *                <p>(Immutable) A new array of chunks from the original array.</p>
866
     */
867 4
    public function chunk($size, $preserveKeys = false): self
868
    {
869 4
        return static::create(
870 4
            \array_chunk($this->getArray(), $size, $preserveKeys),
871 4
            $this->iteratorClass,
872 4
            false
873
        );
874
    }
875
876
    /**
877
     * Clean all falsy values from the current array.
878
     *
879
     * @return static
880
     *                <p>(Immutable)</p>
881
     */
882 8
    public function clean(): self
883
    {
884 8
        return $this->filter(
885 8
            static function ($value) {
886 7
                return (bool) $value;
887 8
            }
888
        );
889
    }
890
891
    /**
892
     * WARNING!!! -> Clear the current array.
893
     *
894
     * @return static
895
     *                <p>(Mutable) Return this Arrayy object, with an empty array.</p>
896
     */
897 4
    public function clear(): self
898
    {
899 4
        $this->array = [];
900 4
        $this->generator = null;
901
902 4
        return $this;
903
    }
904
905
    /**
906
     * Check if an item is in the current array.
907
     *
908
     * @param float|int|string $value
909
     * @param bool             $recursive
910
     * @param bool             $strict
911
     *
912
     * @return bool
913
     */
914 22
    public function contains($value, bool $recursive = false, bool $strict = true): bool
915
    {
916 22
        if ($recursive === true) {
917 18
            return $this->in_array_recursive($value, $this->getArray(), $strict);
918
        }
919
920 13
        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 26
                    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 13
                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 550
    public static function create($array = [], string $iteratorClass = ArrayyIterator::class, bool $checkForMissingPropertiesInConstructor = true): self
1093
    {
1094 550
        return new static(
1095 550
            $array,
1096 550
            $iteratorClass,
1097 550
            $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
            $array,
1243 10
            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 3
                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 1
            'eq' => static function ($item, $prop, $value) {
1572 1
                return $item[$prop] === $value;
1573 1
            },
1574 1
            'gt' => static function ($item, $prop, $value) {
1575
                return $item[$prop] > $value;
1576 1
            },
1577 1
            'ge' => static function ($item, $prop, $value) {
1578
                return $item[$prop] >= $value;
1579 1
            },
1580 1
            'gte' => static function ($item, $prop, $value) {
1581
                return $item[$prop] >= $value;
1582 1
            },
1583 1
            'lt' => static function ($item, $prop, $value) {
1584 1
                return $item[$prop] < $value;
1585 1
            },
1586 1
            'le' => static function ($item, $prop, $value) {
1587
                return $item[$prop] <= $value;
1588 1
            },
1589 1
            'lte' => static function ($item, $prop, $value) {
1590
                return $item[$prop] <= $value;
1591 1
            },
1592 1
            'ne' => static function ($item, $prop, $value) {
1593
                return $item[$prop] !== $value;
1594 1
            },
1595 1
            'contains' => static function ($item, $prop, $value) {
1596 1
                return \in_array($item[$prop], (array) $value, true);
1597 1
            },
1598 1
            'notContains' => static function ($item, $prop, $value) {
1599
                return !\in_array($item[$prop], (array) $value, true);
1600 1
            },
1601 1
            'newer' => static function ($item, $prop, $value) {
1602
                return \strtotime($item[$prop]) > \strtotime($value);
1603 1
            },
1604 1
            '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 1
                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 6
                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
     * And will return an empty array if there was no first entry.
1685
     *
1686
     * @param int|null $number <p>How many values you will take?</p>
1687
     *
1688
     * @return static
1689
     *                <p>(Immutable)</p>
1690
     */
1691 36
    public function firstsImmutable(int $number = null): self
1692
    {
1693 36
        $arrayTmp = $this->getArray();
1694
1695 36
        if ($number === null) {
1696 14
            $array = (array) \array_shift($arrayTmp);
1697
        } else {
1698 22
            $number = (int) $number;
1699 22
            $array = \array_splice($arrayTmp, 0, $number);
1700
        }
1701
1702 36
        return static::create(
1703 36
            $array,
1704 36
            $this->iteratorClass,
1705 36
            false
1706
        );
1707
    }
1708
1709
    /**
1710
     * Get the first value(s) from the current array.
1711
     * And will return an empty array if there was no first entry.
1712
     *
1713
     * @param int|null $number <p>How many values you will take?</p>
1714
     *
1715
     * @return static
1716
     *                <p>(Mutable)</p>
1717
     */
1718 34
    public function firstsMutable(int $number = null): self
1719
    {
1720 34
        $this->generatorToArray();
1721
1722 34
        if ($number === null) {
1723 19
            $this->array = (array) \array_shift($this->array);
1724
        } else {
1725 15
            $number = (int) $number;
1726 15
            $this->array = \array_splice($this->array, 0, $number);
1727
        }
1728
1729 34
        return $this;
1730
    }
1731
1732
    /**
1733
     * Exchanges all keys with their associated values in an array.
1734
     *
1735
     * @return static
1736
     *                <p>(Immutable)</p>
1737
     */
1738 1
    public function flip(): self
1739
    {
1740 1
        return static::create(
1741 1
            \array_flip($this->getArray()),
1742 1
            $this->iteratorClass,
1743 1
            false
1744
        );
1745
    }
1746
1747
    /**
1748
     * Get a value from an array (optional using dot-notation).
1749
     *
1750
     * @param mixed $key      <p>The key to look for.</p>
1751
     * @param mixed $fallback <p>Value to fallback to.</p>
1752
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
1753
     *                        class.</p>
1754
     *
1755
     * @return mixed|static
1756
     */
1757 72
    public function get($key, $fallback = null, array $array = null)
1758
    {
1759 72
        if ($array !== null) {
1760 4
            $usedArray = $array;
1761
        } else {
1762 68
            $this->generatorToArray();
1763
1764 68
            $usedArray = $this->array;
1765
        }
1766
1767 72
        if ($key === null) {
1768 1
            return static::create(
1769 1
                $usedArray,
1770 1
                $this->iteratorClass,
1771 1
                false
1772
            );
1773
        }
1774
1775
        // php cast "bool"-index into "int"-index
1776 72
        if ((bool) $key === $key) {
1777 3
            $key = (int) $key;
1778
        }
1779
1780 72
        if (\array_key_exists($key, $usedArray) === true) {
1781 61
            if (\is_array($usedArray[$key])) {
1782 9
                return static::create(
1783 9
                    $usedArray[$key],
1784 9
                    $this->iteratorClass,
1785 9
                    false
1786
                );
1787
            }
1788
1789 54
            return $usedArray[$key];
1790
        }
1791
1792
        // crawl through array, get key according to object or not
1793 23
        $usePath = false;
1794
        if (
1795 23
            $this->pathSeparator
1796
            &&
1797 23
            \is_string($key)
1798
            &&
1799 23
            \strpos($key, $this->pathSeparator) !== false
1800
        ) {
1801 7
            $segments = \explode($this->pathSeparator, (string) $key);
1802 7
            if ($segments !== false) {
1803 7
                $usePath = true;
1804
1805 7
                foreach ($segments as $segment) {
1806
                    if (
1807
                        (
1808 7
                            \is_array($usedArray)
1809
                            ||
1810 7
                            $usedArray instanceof \ArrayAccess
1811
                        )
1812
                        &&
1813 7
                        isset($usedArray[$segment])
1814
                    ) {
1815 7
                        $usedArray = $usedArray[$segment];
1816
1817 7
                        continue;
1818
                    }
1819
1820
                    if (
1821 6
                        \is_object($usedArray)
1822
                        &&
1823 6
                        property_exists($usedArray, $segment)
1824
                    ) {
1825 1
                        $usedArray = $usedArray->{$segment};
1826
1827 1
                        continue;
1828
                    }
1829
1830 5
                    return $fallback instanceof \Closure ? $fallback() : $fallback;
1831
                }
1832
            }
1833
        }
1834
1835 23
        if (!$usePath && !isset($usedArray[$key])) {
1836 16
            return $fallback instanceof \Closure ? $fallback() : $fallback;
1837
        }
1838
1839 7
        if (\is_array($usedArray)) {
1840 1
            return static::create(
1841 1
                $usedArray,
1842 1
                $this->iteratorClass,
1843 1
                false
1844
            );
1845
        }
1846
1847 7
        return $usedArray;
1848
    }
1849
1850
    /**
1851
     * Get the current array from the "Arrayy"-object.
1852
     *
1853
     * @return array
1854
     */
1855 808
    public function getArray(): array
1856
    {
1857
        // init
1858 808
        $array = [];
1859
1860 808
        foreach ($this->getGenerator() as $key => $value) {
1861 700
            $array[$key] = $value;
1862
        }
1863
1864 808
        return $array;
1865
    }
1866
1867
    /**
1868
     * Returns the values from a single column of the input array, identified by
1869
     * the $columnKey, can be used to extract data-columns from multi-arrays.
1870
     *
1871
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
1872
     * array by the values from the $indexKey column in the input array.
1873
     *
1874
     * @param mixed $columnKey
1875
     * @param mixed $indexKey
1876
     *
1877
     * @return static
1878
     *                <p>(Immutable)</p>
1879
     */
1880 1
    public function getColumn($columnKey = null, $indexKey = null): self
1881
    {
1882 1
        return static::create(
1883 1
            \array_column($this->getArray(), $columnKey, $indexKey),
1884 1
            $this->iteratorClass,
1885 1
            false
1886
        );
1887
    }
1888
1889
    /**
1890
     * Get the current array from the "Arrayy"-object as generator.
1891
     *
1892
     * @return \Generator
1893
     */
1894 833
    public function getGenerator(): \Generator
1895
    {
1896 833
        if ($this->generator instanceof ArrayyRewindableGenerator) {
1897 5
            yield from $this->generator;
1898
        }
1899
1900 833
        yield from $this->array;
1901 820
    }
1902
1903
    /**
1904
     * alias: for "Arrayy->keys()"
1905
     *
1906
     * @return static
1907
     *                <p>(Immutable)</p>
1908
     *
1909
     * @see Arrayy::keys()
1910
     */
1911 1
    public function getKeys(): self
1912
    {
1913 1
        return $this->keys();
1914
    }
1915
1916
    /**
1917
     * Get the current array from the "Arrayy"-object as object.
1918
     *
1919
     * @return \stdClass
1920
     */
1921 4
    public function getObject(): \stdClass
1922
    {
1923 4
        return self::arrayToObject($this->getArray());
1924
    }
1925
1926
    /**
1927
     * alias: for "Arrayy->randomImmutable()"
1928
     *
1929
     * @return static
1930
     *                <p>(Immutable)</p>
1931
     *
1932
     * @see Arrayy::randomImmutable()
1933
     */
1934 4
    public function getRandom(): self
1935
    {
1936 4
        return $this->randomImmutable();
1937
    }
1938
1939
    /**
1940
     * alias: for "Arrayy->randomKey()"
1941
     *
1942
     * @return mixed
1943
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
1944
     *
1945
     * @see Arrayy::randomKey()
1946
     */
1947 3
    public function getRandomKey()
1948
    {
1949 3
        return $this->randomKey();
1950
    }
1951
1952
    /**
1953
     * alias: for "Arrayy->randomKeys()"
1954
     *
1955
     * @param int $number
1956
     *
1957
     * @return static
1958
     *                <p>(Immutable)</p>
1959
     *
1960
     * @see Arrayy::randomKeys()
1961
     */
1962 8
    public function getRandomKeys(int $number): self
1963
    {
1964 8
        return $this->randomKeys($number);
1965
    }
1966
1967
    /**
1968
     * alias: for "Arrayy->randomValue()"
1969
     *
1970
     * @return mixed
1971
     *               <p>Get a random value or null if there wasn't a value.</p>
1972
     *
1973
     * @see Arrayy::randomValue()
1974
     */
1975 3
    public function getRandomValue()
1976
    {
1977 3
        return $this->randomValue();
1978
    }
1979
1980
    /**
1981
     * alias: for "Arrayy->randomValues()"
1982
     *
1983
     * @param int $number
1984
     *
1985
     * @return static
1986
     *                <p>(Immutable)</p>
1987
     *
1988
     * @see Arrayy::randomValues()
1989
     */
1990 6
    public function getRandomValues(int $number): self
1991
    {
1992 6
        return $this->randomValues($number);
1993
    }
1994
1995
    /**
1996
     * Group values from a array according to the results of a closure.
1997
     *
1998
     * @param \callable $grouper  <p>A callable function name.</p>
1999
     * @param bool      $saveKeys
2000
     *
2001
     * @return static
2002
     *                <p>(Immutable)</p>
2003
     */
2004 4
    public function group($grouper, bool $saveKeys = false): self
2005
    {
2006
        // init
2007 4
        $result = [];
2008
2009
        // Iterate over values, group by property/results from closure.
2010 4
        foreach ($this->getGenerator() as $key => $value) {
2011 4
            $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $this->getArray());
2012 4
            $newValue = $this->get($groupKey, null, $result);
2013
2014 4
            if ($groupKey instanceof self) {
2015
                $groupKey = $groupKey->getArray();
2016
            }
2017
2018 4
            if ($newValue instanceof self) {
2019 4
                $newValue = $newValue->getArray();
2020
            }
2021
2022
            // Add to results.
2023 4
            if ($groupKey !== null) {
2024 3
                if ($saveKeys) {
2025 2
                    $result[$groupKey] = $newValue;
2026 2
                    $result[$groupKey][$key] = $value;
2027
                } else {
2028 1
                    $result[$groupKey] = $newValue;
2029 4
                    $result[$groupKey][] = $value;
2030
                }
2031
            }
2032
        }
2033
2034 4
        return static::create(
2035 4
            $result,
2036 4
            $this->iteratorClass,
2037 4
            false
2038
        );
2039
    }
2040
2041
    /**
2042
     * Check if an array has a given key.
2043
     *
2044
     * @param mixed $key
2045
     *
2046
     * @return bool
2047
     */
2048 23
    public function has($key): bool
2049
    {
2050 23
        static $UN_FOUND = null;
2051
2052 23
        if ($UN_FOUND === null) {
2053
            // Generate unique string to use as marker.
2054 1
            $UN_FOUND = \uniqid('arrayy', true);
2055
        }
2056
2057 23
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
2058
    }
2059
2060
    /**
2061
     * Implodes the values of this array.
2062
     *
2063
     * @param string $glue
2064
     *
2065
     * @return string
2066
     */
2067 27
    public function implode(string $glue = ''): string
2068
    {
2069 27
        return $this->implode_recursive($glue, $this->getArray(), false);
2070
    }
2071
2072
    /**
2073
     * Implodes the keys of this array.
2074
     *
2075
     * @param string $glue
2076
     *
2077
     * @return string
2078
     */
2079 8
    public function implodeKeys(string $glue = ''): string
2080
    {
2081 8
        return $this->implode_recursive($glue, $this->getArray(), true);
2082
    }
2083
2084
    /**
2085
     * Given a list and an iterate-function that returns
2086
     * a key for each element in the list (or a property name),
2087
     * returns an object with an index of each item.
2088
     *
2089
     * @param mixed $key
2090
     *
2091
     * @return static
2092
     *                <p>(Immutable)</p>
2093
     */
2094 4
    public function indexBy($key): self
2095
    {
2096
        // init
2097 4
        $results = [];
2098
2099 4
        foreach ($this->getGenerator() as $a) {
2100 4
            if (\array_key_exists($key, $a) === true) {
2101 4
                $results[$a[$key]] = $a;
2102
            }
2103
        }
2104
2105 4
        return static::create(
2106 4
            $results,
2107 4
            $this->iteratorClass,
2108 4
            false
2109
        );
2110
    }
2111
2112
    /**
2113
     * alias: for "Arrayy->searchIndex()"
2114
     *
2115
     * @param mixed $value <p>The value to search for.</p>
2116
     *
2117
     * @return mixed
2118
     *
2119
     * @see Arrayy::searchIndex()
2120
     */
2121 4
    public function indexOf($value)
2122
    {
2123 4
        return $this->searchIndex($value);
2124
    }
2125
2126
    /**
2127
     * Get everything but the last..$to items.
2128
     *
2129
     * @param int $to
2130
     *
2131
     * @return static
2132
     *                <p>(Immutable)</p>
2133
     */
2134 12
    public function initial(int $to = 1): self
2135
    {
2136 12
        return $this->firstsImmutable(\count($this->getArray(), \COUNT_NORMAL) - $to);
2137
    }
2138
2139
    /**
2140
     * Return an array with all elements found in input array.
2141
     *
2142
     * @param array $search
2143
     * @param bool  $keepKeys
2144
     *
2145
     * @return static
2146
     *                <p>(Immutable)</p>
2147
     */
2148 3
    public function intersection(array $search, bool $keepKeys = false): self
2149
    {
2150 3
        if ($keepKeys) {
2151 1
            return static::create(
2152 1
                \array_uintersect(
2153 1
                    $this->array,
2154 1
                    $search,
2155 1
                    static function ($a, $b) {
2156 1
                        return $a === $b ? 0 : -1;
2157 1
                    }
2158
                ),
2159 1
                $this->iteratorClass,
2160 1
                false
2161
            );
2162
        }
2163
2164 2
        return static::create(
2165 2
            \array_values(\array_intersect($this->getArray(), $search)),
2166 2
            $this->iteratorClass,
2167 2
            false
2168
        );
2169
    }
2170
2171
    /**
2172
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
2173
     *
2174
     * @param array $search
2175
     *
2176
     * @return bool
2177
     */
2178 1
    public function intersects(array $search): bool
2179
    {
2180 1
        return \count($this->intersection($search)->array, \COUNT_NORMAL) > 0;
2181
    }
2182
2183
    /**
2184
     * Invoke a function on all of an array's values.
2185
     *
2186
     * @param mixed $callable
2187
     * @param mixed $arguments
2188
     *
2189
     * @return static
2190
     *                <p>(Immutable)</p>
2191
     */
2192 1
    public function invoke($callable, $arguments = []): self
2193
    {
2194
        // If one argument given for each iteration, create an array for it.
2195 1
        if (!\is_array($arguments)) {
2196 1
            $arguments = StaticArrayy::repeat(
2197 1
                $arguments,
2198 1
                \count($this->getArray(), \COUNT_NORMAL)
2199 1
            )->getArray();
2200
        }
2201
2202
        // If the callable has arguments, pass them.
2203 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...
2204 1
            $array = \array_map($callable, $this->getArray(), $arguments);
2205
        } else {
2206 1
            $array = \array_map($callable, $this->getArray());
2207
        }
2208
2209 1
        return static::create(
2210 1
            $array,
2211 1
            $this->iteratorClass,
2212 1
            false
2213
        );
2214
    }
2215
2216
    /**
2217
     * Check whether array is associative or not.
2218
     *
2219
     * @param bool $recursive
2220
     *
2221
     * @return bool
2222
     *              <p>Returns true if associative, false otherwise.</p>
2223
     */
2224 15
    public function isAssoc(bool $recursive = false): bool
2225
    {
2226 15
        if ($this->isEmpty()) {
2227 3
            return false;
2228
        }
2229
2230 13
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2231 13
            if (!\is_string($key)) {
2232 13
                return false;
2233
            }
2234
        }
2235
2236 3
        return true;
2237
    }
2238
2239
    /**
2240
     * Check whether the array is empty or not.
2241
     *
2242
     * @return bool
2243
     *              <p>Returns true if empty, false otherwise.</p>
2244
     */
2245 38
    public function isEmpty(): bool
2246
    {
2247 38
        if ($this->generator) {
2248
            return $this->getArray() === [];
2249
        }
2250
2251 38
        return $this->array === [];
2252
    }
2253
2254
    /**
2255
     * Check if the current array is equal to the given "$array" or not.
2256
     *
2257
     * @param array $array
2258
     *
2259
     * @return bool
2260
     */
2261
    public function isEqual(array $array): bool
2262
    {
2263
        return $this->getArray() === $array;
2264
    }
2265
2266
    /**
2267
     * Check if the current array is a multi-array.
2268
     *
2269
     * @return bool
2270
     */
2271 14
    public function isMultiArray(): bool
2272
    {
2273
        return !(
2274 14
            \count($this->getArray(), \COUNT_NORMAL)
2275
            ===
2276 14
            \count($this->getArray(), \COUNT_RECURSIVE)
2277
        );
2278
    }
2279
2280
    /**
2281
     * Check whether array is numeric or not.
2282
     *
2283
     * @return bool
2284
     *              <p>Returns true if numeric, false otherwise.</p>
2285
     */
2286 5
    public function isNumeric(): bool
2287
    {
2288 5
        if ($this->isEmpty()) {
2289 2
            return false;
2290
        }
2291
2292 4
        foreach ($this->keys()->getGenerator() as $key) {
2293 4
            if (!\is_int($key)) {
2294 4
                return false;
2295
            }
2296
        }
2297
2298 2
        return true;
2299
    }
2300
2301
    /**
2302
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2303
     *
2304
     * @param bool $recursive
2305
     *
2306
     * @return bool
2307
     */
2308 1
    public function isSequential(bool $recursive = false): bool
2309
    {
2310
2311
        // recursive
2312
2313 1
        if ($recursive === true) {
2314
            return $this->array_keys_recursive($this->getArray())
2315
                   ===
2316
                   \range(0, \count($this->getArray(), \COUNT_RECURSIVE) - 1);
2317
        }
2318
2319
        // non recursive
2320
2321 1
        return \array_keys($this->getArray())
2322
               ===
2323 1
               \range(0, \count($this->getArray(), \COUNT_NORMAL) - 1);
2324
    }
2325
2326
    /**
2327
     * @return array
2328
     */
2329
    public function jsonSerialize(): array
2330
    {
2331
        return $this->getArray();
2332
    }
2333
2334
    /**
2335
     * Get all keys from the current array.
2336
     *
2337
     * @param bool  $recursive    [optional] <p>
2338
     *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2339
     *                            </p>
2340
     * @param mixed $search_value [optional] <p>
2341
     *                            If specified, then only keys containing these values are returned.
2342
     *                            </p>
2343
     * @param bool  $strict       [optional] <p>
2344
     *                            Determines if strict comparison (===) should be used during the search.
2345
     *                            </p>
2346
     *
2347
     * @return static
2348
     *                <p>(Immutable) An array of all the keys in input.</p>
2349
     */
2350 26
    public function keys(bool $recursive = false, $search_value = null, bool $strict = true): self
2351
    {
2352
2353
        // recursive
2354
2355 26
        if ($recursive === true) {
2356 3
            if ($search_value === null) {
2357 3
                $array = $this->array_keys_recursive($this->getArray());
2358
            } else {
2359
                $array = $this->array_keys_recursive($this->getArray(), $search_value, $strict);
2360
            }
2361
2362 3
            return static::create(
2363 3
                $array,
2364 3
                $this->iteratorClass,
2365 3
                false
2366
            );
2367
        }
2368
2369
        // non recursive
2370
2371 25
        if ($search_value === null) {
2372 25
            $array = \array_keys($this->getArray());
2373
        } else {
2374
            $array = \array_keys($this->getArray(), $search_value, $strict);
2375
        }
2376
2377 25
        return static::create(
2378 25
            $array,
2379 25
            $this->iteratorClass,
2380 25
            false
2381
        );
2382
    }
2383
2384
    /**
2385
     * Sort an array by key in reverse order.
2386
     *
2387
     * @param int $sort_flags [optional] <p>
2388
     *                        You may modify the behavior of the sort using the optional
2389
     *                        parameter sort_flags, for details
2390
     *                        see sort.
2391
     *                        </p>
2392
     *
2393
     * @return static
2394
     *                <p>(Mutable) Return this Arrayy object.</p>
2395
     */
2396 4
    public function krsort(int $sort_flags = 0): self
2397
    {
2398 4
        $this->generatorToArray();
2399
2400 4
        \krsort($this->array, $sort_flags);
2401
2402 4
        return $this;
2403
    }
2404
2405
    /**
2406
     * Get the last value from the current array.
2407
     *
2408
     * @return mixed
2409
     *               <p>Return null if there wasn't a element.</p>
2410
     */
2411 4
    public function last()
2412
    {
2413 4
        return $this->pop();
2414
    }
2415
2416
    /**
2417
     * Get the last value(s) from the current array.
2418
     *
2419
     * @param int|null $number
2420
     *
2421
     * @return static
2422
     *                <p>(Immutable)</p>
2423
     */
2424 13
    public function lastsImmutable(int $number = null): self
2425
    {
2426 13
        if ($this->isEmpty()) {
2427 1
            return static::create(
2428 1
                [],
2429 1
                $this->iteratorClass,
2430 1
                false
2431
            );
2432
        }
2433
2434 12
        if ($number === null) {
2435 8
            $poppedValue = $this->pop();
2436
2437 8
            if ($poppedValue === null) {
2438 1
                $poppedValue = [$poppedValue];
2439
            } else {
2440 7
                $poppedValue = (array) $poppedValue;
2441
            }
2442
2443 8
            $arrayy = static::create(
2444 8
                $poppedValue,
2445 8
                $this->iteratorClass,
2446 8
                false
2447
            );
2448
        } else {
2449 4
            $number = (int) $number;
2450 4
            $arrayy = $this->rest(-$number);
2451
        }
2452
2453 12
        return $arrayy;
2454
    }
2455
2456
    /**
2457
     * Get the last value(s) from the current array.
2458
     *
2459
     * @param int|null $number
2460
     *
2461
     * @return static
2462
     *                <p>(Mutable)</p>
2463
     */
2464 13
    public function lastsMutable(int $number = null): self
2465
    {
2466 13
        if ($this->isEmpty()) {
2467 1
            return $this;
2468
        }
2469
2470 12
        if ($number === null) {
2471 8
            $poppedValue = $this->pop();
2472
2473 8
            if ($poppedValue === null) {
2474 1
                $poppedValue = [$poppedValue];
2475
            } else {
2476 7
                $poppedValue = (array) $poppedValue;
2477
            }
2478
2479 8
            $this->array = static::create(
2480 8
                $poppedValue,
2481 8
                $this->iteratorClass,
2482 8
                false
2483 8
            )->getArray();
2484
        } else {
2485 4
            $number = (int) $number;
2486 4
            $this->array = $this->rest(-$number)->getArray();
2487
        }
2488
2489 12
        $this->generator = null;
2490
2491 12
        return $this;
2492
    }
2493
2494
    /**
2495
     * Count the values from the current array.
2496
     *
2497
     * alias: for "Arrayy->count()"
2498
     *
2499
     * @param int $mode
2500
     *
2501
     * @return int
2502
     *
2503
     * @see Arrayy::count()
2504
     */
2505 20
    public function length(int $mode = \COUNT_NORMAL): int
2506
    {
2507 20
        return $this->count($mode);
2508
    }
2509
2510
    /**
2511
     * Apply the given function to the every element of the array,
2512
     * collecting the results.
2513
     *
2514
     * @param callable $callable
2515
     *
2516
     * @return static
2517
     *                <p>(Immutable) Arrayy object with modified elements.</p>
2518
     */
2519 4
    public function map(callable $callable): self
2520
    {
2521 4
        return static::create(
2522 4
            \array_map($callable, $this->getArray()),
2523 4
            $this->iteratorClass,
2524 4
            false
2525
        );
2526
    }
2527
2528
    /**
2529
     * Check if all items in current array match a truth test.
2530
     *
2531
     * @param \Closure $closure
2532
     *
2533
     * @return bool
2534
     */
2535 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...
2536
    {
2537 15
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2538 2
            return false;
2539
        }
2540
2541 13
        foreach ($this->getGenerator() as $key => $value) {
2542 13
            $value = $closure($value, $key);
2543
2544 13
            if ($value === false) {
2545 13
                return false;
2546
            }
2547
        }
2548
2549 7
        return true;
2550
    }
2551
2552
    /**
2553
     * Check if any item in the current array matches a truth test.
2554
     *
2555
     * @param \Closure $closure
2556
     *
2557
     * @return bool
2558
     */
2559 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...
2560
    {
2561 14
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2562 2
            return false;
2563
        }
2564
2565 12
        foreach ($this->getGenerator() as $key => $value) {
2566 12
            $value = $closure($value, $key);
2567
2568 12
            if ($value === true) {
2569 12
                return true;
2570
            }
2571
        }
2572
2573 4
        return false;
2574
    }
2575
2576
    /**
2577
     * Get the max value from an array.
2578
     *
2579
     * @return mixed
2580
     */
2581 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...
2582
    {
2583 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2584 1
            return false;
2585
        }
2586
2587 9
        return \max($this->getArray());
2588
    }
2589
2590
    /**
2591
     * Merge the new $array into the current array.
2592
     *
2593
     * - keep key,value from the current array, also if the index is in the new $array
2594
     *
2595
     * @param array $array
2596
     * @param bool  $recursive
2597
     *
2598
     * @return static
2599
     *                <p>(Immutable)</p>
2600
     */
2601 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...
2602
    {
2603 25
        if ($recursive === true) {
2604 4
            $result = \array_replace_recursive($this->getArray(), $array);
2605
        } else {
2606 21
            $result = \array_replace($this->getArray(), $array);
2607
        }
2608
2609 25
        return static::create(
2610 25
            $result,
2611 25
            $this->iteratorClass,
2612 25
            false
2613
        );
2614
    }
2615
2616
    /**
2617
     * Merge the new $array into the current array.
2618
     *
2619
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2620
     * - create new indexes
2621
     *
2622
     * @param array $array
2623
     * @param bool  $recursive
2624
     *
2625
     * @return static
2626
     *                <p>(Immutable)</p>
2627
     */
2628 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...
2629
    {
2630 16
        if ($recursive === true) {
2631 4
            $result = \array_merge_recursive($this->getArray(), $array);
2632
        } else {
2633 12
            $result = \array_merge($this->getArray(), $array);
2634
        }
2635
2636 16
        return static::create(
2637 16
            $result,
2638 16
            $this->iteratorClass,
2639 16
            false
2640
        );
2641
    }
2642
2643
    /**
2644
     * Merge the the current array into the $array.
2645
     *
2646
     * - use key,value from the new $array, also if the index is in the current array
2647
     *
2648
     * @param array $array
2649
     * @param bool  $recursive
2650
     *
2651
     * @return static
2652
     *                <p>(Immutable)</p>
2653
     */
2654 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...
2655
    {
2656 16
        if ($recursive === true) {
2657 4
            $result = \array_replace_recursive($array, $this->getArray());
2658
        } else {
2659 12
            $result = \array_replace($array, $this->getArray());
2660
        }
2661
2662 16
        return static::create(
2663 16
            $result,
2664 16
            $this->iteratorClass,
2665 16
            false
2666
        );
2667
    }
2668
2669
    /**
2670
     * Merge the current array into the new $array.
2671
     *
2672
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
2673
     * - create new indexes
2674
     *
2675
     * @param array $array
2676
     * @param bool  $recursive
2677
     *
2678
     * @return static
2679
     *                <p>(Immutable)</p>
2680
     */
2681 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...
2682
    {
2683 17
        if ($recursive === true) {
2684 4
            $result = \array_merge_recursive($array, $this->getArray());
2685
        } else {
2686 13
            $result = \array_merge($array, $this->getArray());
2687
        }
2688
2689 17
        return static::create(
2690 17
            $result,
2691 17
            $this->iteratorClass,
2692 17
            false
2693
        );
2694
    }
2695
2696
    /**
2697
     * @return ArrayyMeta|static
2698
     */
2699 14
    public static function meta()
2700
    {
2701 14
        return (new ArrayyMeta())->getMetaObject(static::class);
2702
    }
2703
2704
    /**
2705
     * Get the min value from an array.
2706
     *
2707
     * @return mixed
2708
     */
2709 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...
2710
    {
2711 10
        if (\count($this->getArray(), \COUNT_NORMAL) === 0) {
2712 1
            return false;
2713
        }
2714
2715 9
        return \min($this->getArray());
2716
    }
2717
2718
    /**
2719
     * Move an array element to a new index.
2720
     *
2721
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2722
     *
2723
     * @param int|string $from
2724
     * @param int $to
2725
     *
2726
     * @return static
2727
     *                <p>(Immutable)</p>
2728
     */
2729 1
    public function moveElement($from, $to): self
2730
    {
2731 1
        $array = $this->getArray();
2732
2733 1
        if (\is_int($from)) {
2734 1
            $tmp = \array_splice($array, $from, 1);
2735 1
            \array_splice($array, (int) $to, 0, $tmp);
2736 1
            $output = $array;
2737 1
        } elseif (\is_string($from)) {
2738 1
            $indexToMove = \array_search($from, \array_keys($array), true);
2739 1
            $itemToMove = $array[$from];
2740 1
            if ($indexToMove !== false) {
2741 1
                \array_splice($array, $indexToMove, 1);
2742
            }
2743 1
            $i = 0;
2744 1
            $output = [];
2745 1
            foreach ($array as $key => $item) {
2746 1
                if ($i === $to) {
2747 1
                    $output[$from] = $itemToMove;
2748
                }
2749 1
                $output[$key] = $item;
2750 1
                ++$i;
2751
            }
2752
        } else {
2753
            $output = [];
2754
        }
2755
2756 1
        return static::create(
2757 1
            $output,
2758 1
            $this->iteratorClass,
2759 1
            false
2760
        );
2761
    }
2762
2763
    /**
2764
     * Get a subset of the items from the given array.
2765
     *
2766
     * @param mixed[] $keys
2767
     *
2768
     * @return static
2769
     *                <p>(Immutable)</p>
2770
     */
2771
    public function only(array $keys): self
2772
    {
2773
        $array = $this->getArray();
2774
2775
        return static::create(
2776
            \array_intersect_key($array, \array_flip($keys)),
2777
            $this->iteratorClass,
2778
            false
2779
        );
2780
    }
2781
2782
    /**
2783
     * Pad array to the specified size with a given value.
2784
     *
2785
     * @param int   $size  <p>Size of the result array.</p>
2786
     * @param mixed $value <p>Empty value by default.</p>
2787
     *
2788
     * @return static
2789
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
2790
     */
2791 4
    public function pad(int $size, $value): self
2792
    {
2793 4
        return static::create(
2794 4
            \array_pad($this->getArray(), $size, $value),
2795 4
            $this->iteratorClass,
2796 4
            false
2797
        );
2798
    }
2799
2800
    /**
2801
     * Pop a specified value off the end of the current array.
2802
     *
2803
     * @return mixed
2804
     *               <p>(Mutable) The popped element from the current array.</p>
2805
     */
2806 16
    public function pop()
2807
    {
2808 16
        $this->generatorToArray();
2809
2810 16
        return \array_pop($this->array);
2811
    }
2812
2813
    /**
2814
     * Prepend a (key) + value to the current array.
2815
     *
2816
     * @param mixed $value
2817
     * @param mixed $key
2818
     *
2819
     * @return static
2820
     *                <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2821
     */
2822 8
    public function prepend($value, $key = null): self
2823
    {
2824 8
        $this->generatorToArray();
2825
2826 8
        if ($key === null) {
2827 8
            \array_unshift($this->array, $value);
2828
        } else {
2829
            /** @noinspection AdditionOperationOnArraysInspection */
2830 1
            $this->array = [$key => $value] + $this->array;
2831
        }
2832
2833 8
        return $this;
2834
    }
2835
2836
    /**
2837
     * Add a suffix to each key.
2838
     *
2839
     * @param mixed $suffix
2840
     *
2841
     * @return static
2842
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2843
     */
2844 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...
2845
    {
2846
        // init
2847 10
        $result = [];
2848
2849 10
        foreach ($this->getGenerator() as $key => $item) {
2850 9
            if ($item instanceof self) {
2851
                $result[$key] = $item->prependToEachKey($suffix);
2852 9
            } elseif (\is_array($item)) {
2853
                $result[$key] = self::create(
2854
                    $item,
2855
                    $this->iteratorClass,
2856
                    false
2857
                )->prependToEachKey($suffix)
2858
                    ->toArray();
2859
            } else {
2860 9
                $result[$key . $suffix] = $item;
2861
            }
2862
        }
2863
2864 10
        return self::create(
2865 10
            $result,
2866 10
            $this->iteratorClass,
2867 10
            false
2868
        );
2869
    }
2870
2871
    /**
2872
     * Add a suffix to each value.
2873
     *
2874
     * @param mixed $suffix
2875
     *
2876
     * @return static
2877
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2878
     */
2879 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...
2880
    {
2881
        // init
2882 10
        $result = [];
2883
2884 10
        foreach ($this->getGenerator() as $key => $item) {
2885 9
            if ($item instanceof self) {
2886
                $result[$key] = $item->prependToEachValue($suffix);
2887 9
            } elseif (\is_array($item)) {
2888
                $result[$key] = self::create(
2889
                    $item,
2890
                    $this->iteratorClass,
2891
                    false
2892
                )->prependToEachValue($suffix)
2893
                    ->toArray();
2894 9
            } elseif (\is_object($item)) {
2895 1
                $result[$key] = $item;
2896
            } else {
2897 9
                $result[$key] = $item . $suffix;
2898
            }
2899
        }
2900
2901 10
        return self::create(
2902 10
            $result,
2903 10
            $this->iteratorClass,
2904 10
            false
2905
        );
2906
    }
2907
2908
    /**
2909
     * Push one or more values onto the end of array at once.
2910
     *
2911
     * @return static
2912
     *                <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2913
     */
2914 4
    public function push(/* variadic arguments allowed */): self
2915
    {
2916 4
        $this->generatorToArray();
2917
2918 4
        if (\func_num_args()) {
2919 4
            $args = \array_merge([&$this->array], \func_get_args());
2920 4
            \array_push(...$args);
2921
        }
2922
2923 4
        return $this;
2924
    }
2925
2926
    /**
2927
     * Get a random value from the current array.
2928
     *
2929
     * @param int|null $number <p>How many values you will take?</p>
2930
     *
2931
     * @return static
2932
     *                <p>(Immutable)</p>
2933
     */
2934 18
    public function randomImmutable(int $number = null): self
2935
    {
2936 18
        $this->generatorToArray();
2937
2938 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...
2939 1
            return static::create(
2940 1
                [],
2941 1
                $this->iteratorClass,
2942 1
                false
2943
            );
2944
        }
2945
2946 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...
2947
            /** @noinspection NonSecureArrayRandUsageInspection */
2948 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
2949
2950 13
            return static::create(
2951 13
                $arrayRandValue,
2952 13
                $this->iteratorClass,
2953 13
                false
2954
            );
2955
        }
2956
2957 5
        $arrayTmp = $this->array;
2958
        /** @noinspection NonSecureShuffleUsageInspection */
2959 5
        \shuffle($arrayTmp);
2960
2961 5
        return static::create(
2962 5
            $arrayTmp,
2963 5
            $this->iteratorClass,
2964 5
            false
2965 5
        )->firstsImmutable($number);
2966
    }
2967
2968
    /**
2969
     * Pick a random key/index from the keys of this array.
2970
     *
2971
     * @throws \RangeException If array is empty
2972
     *
2973
     * @return mixed
2974
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2975
     */
2976 4
    public function randomKey()
2977
    {
2978 4
        $result = $this->randomKeys(1);
2979
2980 4
        if (!isset($result[0])) {
2981
            $result[0] = null;
2982
        }
2983
2984 4
        return $result[0];
2985
    }
2986
2987
    /**
2988
     * Pick a given number of random keys/indexes out of this array.
2989
     *
2990
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2991
     *
2992
     * @throws \RangeException If array is empty
2993
     *
2994
     * @return static
2995
     *                <p>(Immutable)</p>
2996
     */
2997 13
    public function randomKeys(int $number): self
2998
    {
2999 13
        $this->generatorToArray();
3000
3001 13
        $count = \count($this->array, \COUNT_NORMAL);
3002
3003 13
        if ($number === 0 || $number > $count) {
3004 2
            throw new \RangeException(
3005 2
                \sprintf(
3006 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
3007 2
                    $number,
3008 2
                    $count
3009
                )
3010
            );
3011
        }
3012
3013 11
        $result = (array) \array_rand($this->array, $number);
3014
3015 11
        return static::create(
3016 11
            $result,
3017 11
            $this->iteratorClass,
3018 11
            false
3019
        );
3020
    }
3021
3022
    /**
3023
     * Get a random value from the current array.
3024
     *
3025
     * @param int|null $number <p>How many values you will take?</p>
3026
     *
3027
     * @return static
3028
     *                <p>(Mutable)</p>
3029
     */
3030 17
    public function randomMutable(int $number = null): self
3031
    {
3032 17
        $this->generatorToArray();
3033
3034 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...
3035
            return static::create(
3036
                [],
3037
                $this->iteratorClass,
3038
                false
3039
            );
3040
        }
3041
3042 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...
3043
            /** @noinspection NonSecureArrayRandUsageInspection */
3044 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
3045 7
            $this->array = $arrayRandValue;
3046
3047 7
            return $this;
3048
        }
3049
3050
        /** @noinspection NonSecureShuffleUsageInspection */
3051 11
        \shuffle($this->array);
3052
3053 11
        return $this->firstsMutable($number);
3054
    }
3055
3056
    /**
3057
     * Pick a random value from the values of this array.
3058
     *
3059
     * @return mixed
3060
     *               <p>Get a random value or null if there wasn't a value.</p>
3061
     */
3062 4
    public function randomValue()
3063
    {
3064 4
        $result = $this->randomImmutable();
3065
3066 4
        if (!isset($result[0])) {
3067
            $result[0] = null;
3068
        }
3069
3070 4
        return $result[0];
3071
    }
3072
3073
    /**
3074
     * Pick a given number of random values out of this array.
3075
     *
3076
     * @param int $number
3077
     *
3078
     * @return static
3079
     *                <p>(Mutable)</p>
3080
     */
3081 7
    public function randomValues(int $number): self
3082
    {
3083 7
        return $this->randomMutable($number);
3084
    }
3085
3086
    /**
3087
     * Get a random value from an array, with the ability to skew the results.
3088
     *
3089
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
3090
     *
3091
     * @param array    $array
3092
     * @param int|null $number <p>How many values you will take?</p>
3093
     *
3094
     * @return static
3095
     *                <p>(Immutable)</p>
3096
     */
3097 9
    public function randomWeighted(array $array, int $number = null): self
3098
    {
3099
        // init
3100 9
        $options = [];
3101
3102 9
        foreach ($array as $option => $weight) {
3103 9
            if ($this->searchIndex($option) !== false) {
3104 9
                for ($i = 0; $i < $weight; ++$i) {
3105 1
                    $options[] = $option;
3106
                }
3107
            }
3108
        }
3109
3110 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
3111
    }
3112
3113
    /**
3114
     * Reduce the current array via callable e.g. anonymous-function.
3115
     *
3116
     * @param \callable $callable
3117
     * @param array     $init
3118
     *
3119
     * @return static
3120
     *                <p>(Immutable)</p>
3121
     */
3122 14
    public function reduce($callable, array $init = []): self
3123
    {
3124 14
        if ($this->generator) {
3125 1
            $result = $init;
3126
3127 1
            foreach ($this->getGenerator() as $value) {
3128 1
                $result = $callable($result, $value);
3129
            }
3130
3131 1
            return static::create(
3132 1
                $result,
3133 1
                $this->iteratorClass,
3134 1
                false
3135
            );
3136
        }
3137
3138 14
        $result = \array_reduce($this->array, $callable, $init);
3139
3140 14
        if ($result === null) {
3141
            $this->array = [];
3142
        } else {
3143 14
            $this->array = (array) $result;
3144
        }
3145
3146 14
        return static::create(
3147 14
            $this->array,
3148 14
            $this->iteratorClass,
3149 14
            false
3150
        );
3151
    }
3152
3153
    /**
3154
     * Create a numerically re-indexed Arrayy object.
3155
     *
3156
     * @return static
3157
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
3158
     */
3159 9
    public function reindex(): self
3160
    {
3161 9
        $this->generatorToArray();
3162
3163 9
        $this->array = \array_values($this->array);
3164
3165 9
        return $this;
3166
    }
3167
3168
    /**
3169
     * Return all items that fail the truth test.
3170
     *
3171
     * @param \Closure $closure
3172
     *
3173
     * @return static
3174
     *                <p>(Immutable)</p>
3175
     */
3176 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...
3177
    {
3178
        // init
3179 1
        $filtered = [];
3180
3181 1
        foreach ($this->getGenerator() as $key => $value) {
3182 1
            if (!$closure($value, $key)) {
3183 1
                $filtered[$key] = $value;
3184
            }
3185
        }
3186
3187 1
        return static::create(
3188 1
            $filtered,
3189 1
            $this->iteratorClass,
3190 1
            false
3191
        );
3192
    }
3193
3194
    /**
3195
     * Remove a value from the current array (optional using dot-notation).
3196
     *
3197
     * @param mixed $key
3198
     *
3199
     * @return static
3200
     *                <p>(Immutable)</p>
3201
     */
3202 18
    public function remove($key): self
3203
    {
3204
        // recursive call
3205 18
        if (\is_array($key)) {
3206
            foreach ($key as $k) {
3207
                $this->internalRemove($k);
3208
            }
3209
3210
            return static::create(
3211
                $this->getArray(),
3212
                $this->iteratorClass,
3213
                false
3214
            );
3215
        }
3216
3217 18
        $this->internalRemove($key);
3218
3219 18
        return static::create(
3220 18
            $this->getArray(),
3221 18
            $this->iteratorClass,
3222 18
            false
3223
        );
3224
    }
3225
3226
    /**
3227
     * Remove the first value from the current array.
3228
     *
3229
     * @return static
3230
     *                <p>(Immutable)</p>
3231
     */
3232 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...
3233
    {
3234 7
        $tmpArray = $this->getArray();
3235
3236 7
        \array_shift($tmpArray);
3237
3238 7
        return static::create(
3239 7
            $tmpArray,
3240 7
            $this->iteratorClass,
3241 7
            false
3242
        );
3243
    }
3244
3245
    /**
3246
     * Remove the last value from the current array.
3247
     *
3248
     * @return static
3249
     *                <p>(Immutable)</p>
3250
     */
3251 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...
3252
    {
3253 7
        $tmpArray = $this->getArray();
3254
3255 7
        \array_pop($tmpArray);
3256
3257 7
        return static::create(
3258 7
            $tmpArray,
3259 7
            $this->iteratorClass,
3260 7
            false
3261
        );
3262
    }
3263
3264
    /**
3265
     * Removes a particular value from an array (numeric or associative).
3266
     *
3267
     * @param mixed $value
3268
     *
3269
     * @return static
3270
     *                <p>(Immutable)</p>
3271
     */
3272 7
    public function removeValue($value): self
3273
    {
3274 7
        $this->generatorToArray();
3275
3276
        // init
3277 7
        $isNumericArray = true;
3278
3279 7
        foreach ($this->getGenerator() as $key => $item) {
3280 6
            if ($item === $value) {
3281 6
                if (!\is_int($key)) {
3282
                    $isNumericArray = false;
3283
                }
3284 6
                unset($this->array[$key]);
3285
            }
3286
        }
3287
3288 7
        if ($isNumericArray) {
3289 7
            $this->array = \array_values($this->array);
3290
        }
3291
3292 7
        return static::create(
3293 7
            $this->array,
3294 7
            $this->iteratorClass,
3295 7
            false
3296
        );
3297
    }
3298
3299
    /**
3300
     * Generate array of repeated arrays.
3301
     *
3302
     * @param int $times <p>How many times has to be repeated.</p>
3303
     *
3304
     * @return static
3305
     *                <p>(Immutable)</p>
3306
     */
3307 1
    public function repeat($times): self
3308
    {
3309 1
        if ($times === 0) {
3310 1
            return new static();
3311
        }
3312
3313 1
        return static::create(
3314 1
            \array_fill(0, (int) $times, $this->getArray()),
3315 1
            $this->iteratorClass,
3316 1
            false
3317
        );
3318
    }
3319
3320
    /**
3321
     * Replace a key with a new key/value pair.
3322
     *
3323
     * @param mixed $replace
3324
     * @param mixed $key
3325
     * @param mixed $value
3326
     *
3327
     * @return static
3328
     *                <p>(Immutable)</p>
3329
     */
3330 2
    public function replace($replace, $key, $value): self
3331
    {
3332 2
        $that = $this->remove($replace);
3333
3334 2
        return $that->set($key, $value);
3335
    }
3336
3337
    /**
3338
     * Create an array using the current array as values and the other array as keys.
3339
     *
3340
     * @param array $keys <p>An array of keys.</p>
3341
     *
3342
     * @return static
3343
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
3344
     */
3345 2
    public function replaceAllKeys(array $keys): self
3346
    {
3347 2
        return static::create(
3348 2
            \array_combine($keys, $this->getArray()),
3349 2
            $this->iteratorClass,
3350 2
            false
3351
        );
3352
    }
3353
3354
    /**
3355
     * Create an array using the current array as keys and the other array as values.
3356
     *
3357
     * @param array $array <p>An array o values.</p>
3358
     *
3359
     * @return static
3360
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3361
     */
3362 2
    public function replaceAllValues(array $array): self
3363
    {
3364 2
        return static::create(
3365 2
            \array_combine($this->array, $array),
3366 2
            $this->iteratorClass,
3367 2
            false
3368
        );
3369
    }
3370
3371
    /**
3372
     * Replace the keys in an array with another set.
3373
     *
3374
     * @param array $keys <p>An array of keys matching the array's size</p>
3375
     *
3376
     * @return static
3377
     *                <p>(Immutable)</p>
3378
     */
3379 1
    public function replaceKeys(array $keys): self
3380
    {
3381 1
        $values = \array_values($this->getArray());
3382 1
        $result = \array_combine($keys, $values);
3383
3384 1
        return static::create(
3385 1
            $result,
3386 1
            $this->iteratorClass,
3387 1
            false
3388
        );
3389
    }
3390
3391
    /**
3392
     * Replace the first matched value in an array.
3393
     *
3394
     * @param mixed $search      <p>The value to replace.</p>
3395
     * @param mixed $replacement <p>The value to replace.</p>
3396
     *
3397
     * @return static
3398
     *                <p>(Immutable)</p>
3399
     */
3400 3
    public function replaceOneValue($search, $replacement = ''): self
3401
    {
3402 3
        $array = $this->getArray();
3403 3
        $key = \array_search($search, $array, true);
3404
3405 3
        if ($key !== false) {
3406 3
            $array[$key] = $replacement;
3407
        }
3408
3409 3
        return static::create(
3410 3
            $array,
3411 3
            $this->iteratorClass,
3412 3
            false
3413
        );
3414
    }
3415
3416
    /**
3417
     * Replace values in the current array.
3418
     *
3419
     * @param mixed $search      <p>The value to replace.</p>
3420
     * @param mixed $replacement <p>What to replace it with.</p>
3421
     *
3422
     * @return static
3423
     *                <p>(Immutable)</p>
3424
     */
3425 1
    public function replaceValues($search, $replacement = ''): self
3426
    {
3427 1
        $array = $this->each(
3428 1
            static function ($value) use ($search, $replacement) {
3429 1
                return \str_replace($search, $replacement, $value);
3430 1
            }
3431
        );
3432
3433 1
        return $array;
3434
    }
3435
3436
    /**
3437
     * Get the last elements from index $from until the end of this array.
3438
     *
3439
     * @param int $from
3440
     *
3441
     * @return static
3442
     *                <p>(Immutable)</p>
3443
     */
3444 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...
3445
    {
3446 15
        $tmpArray = $this->getArray();
3447
3448 15
        return static::create(
3449 15
            \array_splice($tmpArray, $from),
3450 15
            $this->iteratorClass,
3451 15
            false
3452
        );
3453
    }
3454
3455
    /**
3456
     * Return the array in the reverse order.
3457
     *
3458
     * @return static
3459
     *                <p>(Mutable) Return this Arrayy object.</p>
3460
     */
3461 8
    public function reverse(): self
3462
    {
3463 8
        $this->generatorToArray();
3464
3465 8
        $this->array = \array_reverse($this->array);
3466
3467 8
        return $this;
3468
    }
3469
3470
    /**
3471
     * Sort an array in reverse order.
3472
     *
3473
     * @param int $sort_flags [optional] <p>
3474
     *                        You may modify the behavior of the sort using the optional
3475
     *                        parameter sort_flags, for details
3476
     *                        see sort.
3477
     *                        </p>
3478
     *
3479
     * @return static
3480
     *                <p>(Mutable) Return this Arrayy object.</p>
3481
     */
3482 4
    public function rsort(int $sort_flags = 0): self
3483
    {
3484 4
        $this->generatorToArray();
3485
3486 4
        \rsort($this->array, $sort_flags);
3487
3488 4
        return $this;
3489
    }
3490
3491
    /**
3492
     * Search for the first index of the current array via $value.
3493
     *
3494
     * @param mixed $value
3495
     *
3496
     * @return false|float|int|string
3497
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
3498
     */
3499 20
    public function searchIndex($value)
3500
    {
3501 20
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
3502 19
            if ($value === $valueFromArray) {
3503 19
                return $keyFromArray;
3504
            }
3505
        }
3506
3507 11
        return false;
3508
    }
3509
3510
    /**
3511
     * Search for the value of the current array via $index.
3512
     *
3513
     * @param mixed $index
3514
     *
3515
     * @return static
3516
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3517
     */
3518 9
    public function searchValue($index): self
3519
    {
3520 9
        $this->generatorToArray();
3521
3522
        // init
3523 9
        $return = [];
3524
3525 9
        if ($this->array === []) {
3526
            return static::create(
3527
                [],
3528
                $this->iteratorClass,
3529
                false
3530
            );
3531
        }
3532
3533
        // php cast "bool"-index into "int"-index
3534 9
        if ((bool) $index === $index) {
3535 1
            $index = (int) $index;
3536
        }
3537
3538 9
        if (\array_key_exists($index, $this->array) === true) {
3539 7
            $return = [$this->array[$index]];
3540
        }
3541
3542 9
        return static::create(
3543 9
            $return,
3544 9
            $this->iteratorClass,
3545 9
            false
3546
        );
3547
    }
3548
3549
    /**
3550
     * Set a value for the current array (optional using dot-notation).
3551
     *
3552
     * @param string $key   <p>The key to set.</p>
3553
     * @param mixed  $value <p>Its value.</p>
3554
     *
3555
     * @return static
3556
     *                <p>(Mutable)</p>
3557
     */
3558 18
    public function set($key, $value): self
3559
    {
3560 18
        $this->generatorToArray();
3561
3562 18
        $this->internalSet($key, $value);
3563
3564 18
        return $this;
3565
    }
3566
3567
    /**
3568
     * Get a value from a array and set it if it was not.
3569
     *
3570
     * WARNING: this method only set the value, if the $key is not already set
3571
     *
3572
     * @param mixed $key      <p>The key</p>
3573
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
3574
     *
3575
     * @return mixed
3576
     *               <p>(Mutable)</p>
3577
     */
3578 11
    public function setAndGet($key, $fallback = null)
3579
    {
3580 11
        $this->generatorToArray();
3581
3582
        // If the key doesn't exist, set it.
3583 11
        if (!$this->has($key)) {
3584 4
            $this->array = $this->set($key, $fallback)->getArray();
3585
        }
3586
3587 11
        return $this->get($key);
3588
    }
3589
3590
    /**
3591
     * Shifts a specified value off the beginning of array.
3592
     *
3593
     * @return mixed
3594
     *               <p>(Mutable) A shifted element from the current array.</p>
3595
     */
3596 4
    public function shift()
3597
    {
3598 4
        $this->generatorToArray();
3599
3600 4
        return \array_shift($this->array);
3601
    }
3602
3603
    /**
3604
     * Shuffle the current array.
3605
     *
3606
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3607
     * @param array $array  [optional]
3608
     *
3609
     * @return static
3610
     *                <p>(Immutable)</p>
3611
     */
3612 1
    public function shuffle(bool $secure = false, array $array = null): self
3613
    {
3614 1
        if ($array === null) {
3615 1
            $array = $this->getArray();
3616
        }
3617
3618 1
        if ($secure !== true) {
3619
            /** @noinspection NonSecureShuffleUsageInspection */
3620 1
            \shuffle($array);
3621
        } else {
3622 1
            $size = \count($array, \COUNT_NORMAL);
3623 1
            $keys = \array_keys($array);
3624 1
            for ($i = $size - 1; $i > 0; --$i) {
3625
                try {
3626 1
                    $r = \random_int(0, $i);
3627
                } catch (\Exception $e) {
3628
                    /** @noinspection RandomApiMigrationInspection */
3629
                    $r = \mt_rand(0, $i);
3630
                }
3631 1
                if ($r !== $i) {
3632 1
                    $temp = $array[$keys[$r]];
3633 1
                    $array[$keys[$r]] = $array[$keys[$i]];
3634 1
                    $array[$keys[$i]] = $temp;
3635
                }
3636
            }
3637
3638
            // reset indices
3639 1
            $array = \array_values($array);
3640
        }
3641
3642 1
        foreach ($array as $key => $value) {
3643
            // check if recursive is needed
3644 1
            if (\is_array($value) === true) {
3645 1
                $array[$key] = $this->shuffle($secure, $value);
3646
            }
3647
        }
3648
3649 1
        return static::create(
3650 1
            $array,
3651 1
            $this->iteratorClass,
3652 1
            false
3653
        );
3654
    }
3655
3656
    /**
3657
     * Count the values from the current array.
3658
     *
3659
     * alias: for "Arrayy->count()"
3660
     *
3661
     * @param int $mode
3662
     *
3663
     * @return int
3664
     */
3665 20
    public function size(int $mode = \COUNT_NORMAL): int
3666
    {
3667 20
        return $this->count($mode);
3668
    }
3669
3670
    /**
3671
     * Counts all elements in an array, or something in an object.
3672
     *
3673
     * <p>
3674
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3675
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3676
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3677
     * implemented and used in PHP.
3678
     * </p>
3679
     *
3680
     * @return int
3681
     *             <p>
3682
     *             The number of elements in var, which is
3683
     *             typically an array, since anything else will have one
3684
     *             element.
3685
     *             </p>
3686
     *             <p>
3687
     *             If var is not an array or an object with
3688
     *             implemented Countable interface,
3689
     *             1 will be returned.
3690
     *             There is one exception, if var is &null;,
3691
     *             0 will be returned.
3692
     *             </p>
3693
     *             <p>
3694
     *             Caution: count may return 0 for a variable that isn't set,
3695
     *             but it may also return 0 for a variable that has been initialized with an
3696
     *             empty array. Use isset to test if a variable is set.
3697
     *             </p>
3698
     */
3699 10
    public function sizeRecursive(): int
3700
    {
3701 10
        return \count($this->getArray(), \COUNT_RECURSIVE);
3702
    }
3703
3704
    /**
3705
     * Extract a slice of the array.
3706
     *
3707
     * @param int      $offset       <p>Slice begin index.</p>
3708
     * @param int|null $length       <p>Length of the slice.</p>
3709
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3710
     *
3711
     * @return static
3712
     *                <p>A slice of the original array with length $length.</p>
3713
     */
3714 4
    public function slice(int $offset, int $length = null, bool $preserveKeys = false): self
3715
    {
3716 4
        return static::create(
3717 4
            \array_slice(
3718 4
                $this->getArray(),
3719 4
                $offset,
3720 4
                $length,
3721 4
                $preserveKeys
3722
            ),
3723 4
            $this->iteratorClass,
3724 4
            false
3725
        );
3726
    }
3727
3728
    /**
3729
     * Sort the current array and optional you can keep the keys.
3730
     *
3731
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3732
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3733
     *                              <strong>SORT_NATURAL</strong></p>
3734
     * @param bool       $keepKeys
3735
     *
3736
     * @return static
3737
     *                <p>(Mutable) Return this Arrayy object.</p>
3738
     */
3739 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
3740
    {
3741 20
        $this->generatorToArray();
3742
3743 20
        return $this->sorting(
3744 20
            $this->array,
3745 20
            $direction,
3746 20
            $strategy,
3747 20
            $keepKeys
3748
        );
3749
    }
3750
3751
    /**
3752
     * Sort the current array by key.
3753
     *
3754
     * @see http://php.net/manual/en/function.ksort.php
3755
     * @see http://php.net/manual/en/function.krsort.php
3756
     *
3757
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3758
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3759
     *                              <strong>SORT_NATURAL</strong></p>
3760
     *
3761
     * @return static
3762
     *                <p>(Mutable) Return this Arrayy object.</p>
3763
     */
3764 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3765
    {
3766 18
        $this->generatorToArray();
3767
3768 18
        $this->sorterKeys($this->array, $direction, $strategy);
3769
3770 18
        return $this;
3771
    }
3772
3773
    /**
3774
     * Sort the current array by value.
3775
     *
3776
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3777
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3778
     *                              <strong>SORT_NATURAL</strong></p>
3779
     *
3780
     * @return static
3781
     *                <p>(Mutable)</p>
3782
     */
3783 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3784
    {
3785 1
        return $this->sort($direction, $strategy, true);
3786
    }
3787
3788
    /**
3789
     * Sort the current array by value.
3790
     *
3791
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3792
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3793
     *                              <strong>SORT_NATURAL</strong></p>
3794
     *
3795
     * @return static
3796
     *                <p>(Mutable)</p>
3797
     */
3798 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3799
    {
3800 1
        return $this->sort($direction, $strategy, false);
3801
    }
3802
3803
    /**
3804
     * Sort a array by value, by a closure or by a property.
3805
     *
3806
     * - If the sorter is null, the array is sorted naturally.
3807
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3808
     *
3809
     * @param \callable|null $sorter
3810
     * @param int|string     $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3811
     * @param int            $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3812
     *                                  <strong>SORT_NATURAL</strong></p>
3813
     *
3814
     * @return static
3815
     *                <p>(Immutable)</p>
3816
     */
3817 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3818
    {
3819 1
        $array = $this->getArray();
3820 1
        $direction = $this->getDirection($direction);
3821
3822
        // Transform all values into their results.
3823 1
        if ($sorter) {
3824 1
            $arrayy = static::create(
3825 1
                $array,
3826 1
                $this->iteratorClass,
3827 1
                false
3828
            );
3829
3830 1
            $that = $this;
3831 1
            $results = $arrayy->each(
3832 1
                static function ($value) use ($sorter, $that) {
3833 1
                    return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3834 1
                }
3835
            );
3836
3837 1
            $results = $results->getArray();
3838
        } else {
3839 1
            $results = $array;
3840
        }
3841
3842
        // Sort by the results and replace by original values
3843 1
        \array_multisort($results, $direction, $strategy, $array);
3844
3845 1
        return static::create(
3846 1
            $array,
3847 1
            $this->iteratorClass,
3848 1
            false
3849
        );
3850
    }
3851
3852
    /**
3853
     * Split an array in the given amount of pieces.
3854
     *
3855
     * @param int  $numberOfPieces
3856
     * @param bool $keepKeys
3857
     *
3858
     * @return static
3859
     *                <p>(Immutable)</p>
3860
     */
3861 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
3862
    {
3863 1
        $this->generatorToArray();
3864
3865 1
        $arrayCount = \count($this->array, \COUNT_NORMAL);
3866
3867 1
        if ($arrayCount === 0) {
3868 1
            $result = [];
3869
        } else {
3870 1
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
3871 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
3872
        }
3873
3874 1
        return static::create(
3875 1
            $result,
3876 1
            $this->iteratorClass,
3877 1
            false
3878
        );
3879
    }
3880
3881
    /**
3882
     * Stripe all empty items.
3883
     *
3884
     * @return static
3885
     *                <p>(Immutable)</p>
3886
     */
3887 1
    public function stripEmpty(): self
3888
    {
3889 1
        return $this->filter(
3890 1
            static function ($item) {
3891 1
                if ($item === null) {
3892 1
                    return false;
3893
                }
3894
3895 1
                return (bool) \trim((string) $item);
3896 1
            }
3897
        );
3898
    }
3899
3900
    /**
3901
     * Swap two values between positions by key.
3902
     *
3903
     * @param int|string $swapA <p>a key in the array</p>
3904
     * @param int|string $swapB <p>a key in the array</p>
3905
     *
3906
     * @return static
3907
     *                <p>(Immutable)</p>
3908
     */
3909 1
    public function swap($swapA, $swapB): self
3910
    {
3911 1
        $array = $this->getArray();
3912
3913 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3914
3915 1
        return static::create(
3916 1
            $array,
3917 1
            $this->iteratorClass,
3918 1
            false
3919
        );
3920
    }
3921
3922
    /**
3923
     * alias: for "Arrayy->getArray()"
3924
     *
3925
     * @see Arrayy::getArray()
3926
     */
3927 198
    public function toArray()
3928
    {
3929 198
        return $this->getArray();
3930
    }
3931
3932
    /**
3933
     * Convert the current array to JSON.
3934
     *
3935
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3936
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3937
     *
3938
     * @return string
3939
     */
3940 6
    public function toJson(int $options = 0, int $depth = 512): string
3941
    {
3942
        /** @noinspection PhpComposerExtensionStubsInspection */
3943 6
        $return = \json_encode($this->getArray(), $options, $depth);
3944 6
        if ($return === false) {
3945
            return '';
3946
        }
3947
3948 6
        return $return;
3949
    }
3950
3951
    /**
3952
     * Implodes array to a string with specified separator.
3953
     *
3954
     * @param string $separator [optional] <p>The element's separator.</p>
3955
     *
3956
     * @return string
3957
     *                <p>The string representation of array, separated by ",".</p>
3958
     */
3959 19
    public function toString(string $separator = ','): string
3960
    {
3961 19
        return $this->implode($separator);
3962
    }
3963
3964
    /**
3965
     * Return a duplicate free copy of the current array.
3966
     *
3967
     * @return static
3968
     *                <p>(Mutable)</p>
3969
     */
3970 10
    public function unique(): self
3971
    {
3972
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3973
3974 10
        $this->array = $this->reduce(
3975 10
            static function ($resultArray, $value) {
3976 9
                if (!\in_array($value, $resultArray, true)) {
3977 9
                    $resultArray[] = $value;
3978
                }
3979
3980 9
                return $resultArray;
3981 10
            },
3982 10
            []
3983 10
        )->getArray();
3984 10
        $this->generator = null;
3985
3986 10
        return $this;
3987
    }
3988
3989
    /**
3990
     * Return a duplicate free copy of the current array. (with the old keys)
3991
     *
3992
     * @return static
3993
     *                <p>(Mutable)</p>
3994
     */
3995 11
    public function uniqueKeepIndex(): self
3996
    {
3997
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3998
3999
        // init
4000 11
        $array = $this->getArray();
4001
4002 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...
4003 11
            \array_keys($array),
4004 11
            static function ($resultArray, $key) use ($array) {
4005 10
                if (!\in_array($array[$key], $resultArray, true)) {
4006 10
                    $resultArray[$key] = $array[$key];
4007
                }
4008
4009 10
                return $resultArray;
4010 11
            },
4011 11
            []
4012
        );
4013 11
        $this->generator = null;
4014
4015 11
        if ($this->array === null) {
4016
            $this->array = [];
4017
        } else {
4018 11
            $this->array = (array) $this->array;
4019
        }
4020
4021 11
        return $this;
4022
    }
4023
4024
    /**
4025
     * alias: for "Arrayy->unique()"
4026
     *
4027
     * @return static
4028
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
4029
     *
4030
     * @see Arrayy::unique()
4031
     */
4032 10
    public function uniqueNewIndex(): self
4033
    {
4034 10
        return $this->unique();
4035
    }
4036
4037
    /**
4038
     * Prepends one or more values to the beginning of array at once.
4039
     *
4040
     * @return static
4041
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
4042
     */
4043 4
    public function unshift(/* variadic arguments allowed */): self
4044
    {
4045 4
        $this->generatorToArray();
4046
4047 4
        if (\func_num_args()) {
4048 4
            $args = \func_get_args();
4049 4
            \array_unshift(...[&$this->array], ...$args);
0 ignored issues
show
Bug introduced by
array(&$this->array) cannot be passed to array_unshift() as the parameter $array expects a reference.
Loading history...
4050
        }
4051
4052 4
        return $this;
4053
    }
4054
4055
    /**
4056
     * Get all values from a array.
4057
     *
4058
     * @return static
4059
     *                <p>(Immutable)</p>
4060
     */
4061 2
    public function values(): self
4062
    {
4063 2
        return static::create(
4064 2
            \array_values($this->getArray()),
4065 2
            $this->iteratorClass,
4066 2
            false
4067
        );
4068
    }
4069
4070
    /**
4071
     * Apply the given function to every element in the array, discarding the results.
4072
     *
4073
     * @param \callable $callable
4074
     * @param bool      $recursive <p>Whether array will be walked recursively or no</p>
4075
     *
4076
     * @return static
4077
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
4078
     */
4079 37
    public function walk($callable, bool $recursive = false): self
4080
    {
4081 37
        $this->generatorToArray();
4082
4083 37
        if ($recursive === true) {
4084 32
            \array_walk_recursive($this->array, $callable);
4085
        } else {
4086 18
            \array_walk($this->array, $callable);
4087
        }
4088
4089 37
        return $this;
4090
    }
4091
4092
    /**
4093
     * Convert an array into a object.
4094
     *
4095
     * @param array $array PHP array
4096
     *
4097
     * @return \stdClass
4098
     */
4099 4
    protected static function arrayToObject(array $array = []): \stdClass
4100
    {
4101
        // init
4102 4
        $object = new \stdClass();
4103
4104 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
4105 1
            return $object;
4106
        }
4107
4108 3
        foreach ($array as $name => $value) {
4109 3
            if (\is_array($value)) {
4110 1
                $object->{$name} = self::arrayToObject($value);
4111
            } else {
4112 3
                $object->{$name} = $value;
4113
            }
4114
        }
4115
4116 3
        return $object;
4117
    }
4118
4119
    /**
4120
     * @param array|\Generator|null $input        <p>
4121
     *                                            An array containing keys to return.
4122
     *                                            </p>
4123
     * @param mixed                 $search_value [optional] <p>
4124
     *                                            If specified, then only keys containing these values are returned.
4125
     *                                            </p>
4126
     * @param bool                  $strict       [optional] <p>
4127
     *                                            Determines if strict comparison (===) should be used during the
4128
     *                                            search.
4129
     *                                            </p>
4130
     *
4131
     * @return array
4132
     *               <p>an array of all the keys in input</p>
4133
     */
4134 10
    protected function array_keys_recursive(
4135
        $input = null,
4136
        $search_value = null,
4137
        bool $strict = true
4138
    ): array {
4139
        // init
4140 10
        $keys = [];
4141 10
        $keysTmp = [[]]; // the inner empty array covers cases when no loops were made
4142
4143 10
        if ($input === null) {
4144
            $input = $this->getGenerator();
4145
        }
4146
4147 10
        foreach ($input as $key => $value) {
4148
            if (
4149 10
                $search_value === null
4150
                ||
4151
                (
4152
                    \is_array($search_value) === true
4153
                    &&
4154 10
                    \in_array($key, $search_value, $strict)
4155
                )
4156
            ) {
4157 10
                $keys[] = $key;
4158
            }
4159
4160
            // check if recursive is needed
4161 10
            if (\is_array($value) === true) {
4162 10
                $keysTmp[] = $this->array_keys_recursive($value);
4163
            }
4164
        }
4165
4166 10
        return \array_merge($keys, ...$keysTmp);
4167
    }
4168
4169
    /**
4170
     * @param mixed      $path
4171
     * @param \callable  $callable
4172
     * @param array|null $currentOffset
4173
     */
4174 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
4175
    {
4176 4
        $this->generatorToArray();
4177
4178 4
        if ($currentOffset === null) {
4179 4
            $currentOffset = &$this->array;
4180
        }
4181
4182 4
        $explodedPath = \explode($this->pathSeparator, $path);
4183 4
        if ($explodedPath === false) {
4184
            return;
4185
        }
4186
4187 4
        $nextPath = \array_shift($explodedPath);
4188
4189 4
        if (!isset($currentOffset[$nextPath])) {
4190
            return;
4191
        }
4192
4193 4
        if (!empty($explodedPath)) {
4194 1
            $this->callAtPath(
4195 1
                \implode($this->pathSeparator, $explodedPath),
4196 1
                $callable,
4197 1
                $currentOffset[$nextPath]
4198
            );
4199
        } else {
4200 4
            $callable($currentOffset[$nextPath]);
4201
        }
4202 4
    }
4203
4204
    /**
4205
     * create a fallback for array
4206
     *
4207
     * 1. use the current array, if it's a array
4208
     * 2. fallback to empty array, if there is nothing
4209
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
4210
     * 4. call "createFromObject()" on object, if there is a "\Traversable"-object
4211
     * 5. call "__toArray()" on object, if the method exists
4212
     * 6. cast a string or object with "__toString()" into an array
4213
     * 7. throw a "InvalidArgumentException"-Exception
4214
     *
4215
     * @param mixed $data
4216
     *
4217
     * @throws \InvalidArgumentException
4218
     *
4219
     * @return array
4220
     */
4221 922
    protected function fallbackForArray(&$data): array
4222
    {
4223 922
        if (\is_array($data)) {
4224 919
            return $data;
4225
        }
4226
4227 17
        if (!$data) {
4228 6
            return [];
4229
        }
4230
4231 16
        $isObject = \is_object($data);
4232
4233 16
        if ($isObject && $data instanceof self) {
4234 1
            return $data->getArray();
4235
        }
4236
4237 15
        if ($isObject && $data instanceof \ArrayObject) {
4238
            return $data->getArrayCopy();
4239
        }
4240
4241 15
        if ($isObject && $data instanceof \Generator) {
4242
            return static::createFromGeneratorImmutable($data)->getArray();
4243
        }
4244
4245 15
        if ($isObject && $data instanceof \Traversable) {
4246
            return static::createFromObject($data)->getArray();
4247
        }
4248
4249 15
        if (\is_callable($data)) {
4250 6
            $this->generator = new ArrayyRewindableGenerator($data);
4251
4252 6
            return [];
4253
        }
4254
4255 9
        if ($isObject && \method_exists($data, '__toArray')) {
4256
            return (array) $data->__toArray();
4257
        }
4258
4259
        if (
4260 9
            \is_string($data)
4261
            ||
4262 9
            ($isObject && \method_exists($data, '__toString'))
4263
        ) {
4264 7
            return [(string) $data];
4265
        }
4266
4267 2
        throw new \InvalidArgumentException(
4268 2
            'Passed value should be a array'
4269
        );
4270
    }
4271
4272
    /**
4273
     * Get correct PHP constant for direction.
4274
     *
4275
     * @param int|string $direction
4276
     *
4277
     * @return int
4278
     */
4279 39
    protected function getDirection($direction): int
4280
    {
4281 39
        if (\is_string($direction)) {
4282 10
            $direction = \strtolower($direction);
4283
4284 10
            if ($direction === 'desc') {
4285 2
                $direction = \SORT_DESC;
4286
            } else {
4287 8
                $direction = \SORT_ASC;
4288
            }
4289
        }
4290
4291
        if (
4292 39
            $direction !== \SORT_DESC
4293
            &&
4294 39
            $direction !== \SORT_ASC
4295
        ) {
4296
            $direction = \SORT_ASC;
4297
        }
4298
4299 39
        return $direction;
4300
    }
4301
4302
    /**
4303
     * @param mixed               $glue
4304
     * @param array|static|string $pieces
4305
     * @param bool                $useKeys
4306
     *
4307
     * @return string
4308
     */
4309 35
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
4310
    {
4311 35
        if ($pieces instanceof self) {
4312 1
            $pieces = $pieces->getArray();
4313
        }
4314
4315 35
        if (\is_array($pieces)) {
4316 35
            $pieces_count = \count($pieces, \COUNT_NORMAL);
4317 35
            $pieces_count_not_zero = $pieces_count > 0;
4318
4319 35
            return \implode(
4320 35
                $glue,
4321 35
                \array_map(
4322 35
                    [$this, 'implode_recursive'],
4323 35
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
4324 35
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
4325
                )
4326
            );
4327
        }
4328
4329 35
        return (string) $pieces;
4330
    }
4331
4332
    /**
4333
     * @param mixed                 $needle   <p>
4334
     *                                        The searched value.
4335
     *                                        </p>
4336
     *                                        <p>
4337
     *                                        If needle is a string, the comparison is done
4338
     *                                        in a case-sensitive manner.
4339
     *                                        </p>
4340
     * @param array|\Generator|null $haystack <p>
4341
     *                                        The array.
4342
     *                                        </p>
4343
     * @param bool                  $strict   [optional] <p>
4344
     *                                        If the third parameter strict is set to true
4345
     *                                        then the in_array function will also check the
4346
     *                                        types of the
4347
     *                                        needle in the haystack.
4348
     *                                        </p>
4349
     *
4350
     * @return bool
4351
     *              <p>true if needle is found in the array, false otherwise</p>
4352
     */
4353 44
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
4354
    {
4355 44
        if ($haystack === null) {
4356
            $haystack = $this->getGenerator();
4357
        }
4358
4359 44
        foreach ($haystack as $item) {
4360 36
            if (\is_array($item) === true) {
4361 8
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
4362
            } else {
4363 36
                $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
4364
            }
4365
4366 36
            if ($returnTmp === true) {
4367 36
                return true;
4368
            }
4369
        }
4370
4371 18
        return false;
4372
    }
4373
4374
    /**
4375
     * @param mixed $value
4376
     */
4377
    protected function internalGetArray(&$value)
4378
    {
4379
        if ($value instanceof self) {
4380
            $valueTmp = $value->getArray();
4381
            if (\count($valueTmp, \COUNT_NORMAL) === 0) {
4382
                $value = [];
4383
            } else {
4384
                /** @noinspection PhpUnusedLocalVariableInspection */
4385
                $value = &$valueTmp;
4386
            }
4387
        }
4388
4389
        /** @noinspection PhpComposerExtensionStubsInspection */
4390
        /** @noinspection NotOptimalIfConditionsInspection */
4391
        if (
4392
            \class_exists('JsonSerializable')
4393
            &&
4394
            $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...
4395
        ) {
4396
4397
            /** @noinspection PhpUnusedLocalVariableInspection */
4398
            $value = &$value->jsonSerialize();
4399
        }
4400
    }
4401
4402
    /**
4403
     * Internal mechanics of remove method.
4404
     *
4405
     * @param mixed $key
4406
     *
4407
     * @return bool
4408
     */
4409 18
    protected function internalRemove($key): bool
4410
    {
4411 18
        $this->generatorToArray();
4412
4413
        if (
4414 18
            $this->pathSeparator
4415
            &&
4416 18
            \is_string($key)
4417
            &&
4418 18
            \strpos($key, $this->pathSeparator) !== false
4419
        ) {
4420
            $path = \explode($this->pathSeparator, (string) $key);
4421
4422
            if ($path !== false) {
4423
                // crawl though the keys
4424
                while (\count($path, \COUNT_NORMAL) > 1) {
4425
                    $key = \array_shift($path);
4426
4427
                    if (!$this->has($key)) {
4428
                        return false;
4429
                    }
4430
4431
                    $this->array = &$this->array[$key];
4432
                }
4433
4434
                $key = \array_shift($path);
4435
            }
4436
        }
4437
4438 18
        unset($this->array[$key]);
4439
4440 18
        return true;
4441
    }
4442
4443
    /**
4444
     * Internal mechanic of set method.
4445
     *
4446
     * @param int|string|null $key
4447
     * @param mixed           $value
4448
     * @param bool            $checkProperties
4449
     *
4450
     * @return bool
4451
     */
4452 807
    protected function internalSet($key, $value, $checkProperties = true): bool
4453
    {
4454
        if (
4455 807
            $checkProperties === true
4456
            &&
4457 807
            $this->properties !== []
4458
        ) {
4459 13
            if (isset($this->properties[$key]) === false) {
4460
                throw new \InvalidArgumentException('The key ' . $key . ' does not exists as @property in the class (' . \get_class($this) . ').');
4461
            }
4462
4463 13
            $this->properties[$key]->checkType($value);
4464
        }
4465
4466 806
        if ($key === null) {
4467
            return false;
4468
        }
4469
4470 806
        $this->generatorToArray();
4471
4472 806
        $array = &$this->array;
4473
4474
        if (
4475 806
            $this->pathSeparator
4476
            &&
4477 806
            \is_string($key)
4478
            &&
4479 806
            \strpos($key, $this->pathSeparator) !== false
4480
        ) {
4481 3
            $path = \explode($this->pathSeparator, (string) $key);
4482
4483 3
            if ($path !== false) {
4484
                // crawl through the keys
4485 3
                while (\count($path, \COUNT_NORMAL) > 1) {
4486 3
                    $key = \array_shift($path);
4487
4488 3
                    $array = &$array[$key];
4489
                }
4490
4491 3
                $key = \array_shift($path);
4492
            }
4493
        }
4494
4495 806
        $array[$key] = $value;
4496
4497 806
        return true;
4498
    }
4499
4500
    /**
4501
     * Convert a object into an array.
4502
     *
4503
     * @param object $object
4504
     *
4505
     * @return mixed
4506
     */
4507 5
    protected static function objectToArray($object)
4508
    {
4509 5
        if (!\is_object($object)) {
4510 4
            return $object;
4511
        }
4512
4513 5
        if (\is_object($object)) {
4514 5
            $object = \get_object_vars($object);
4515
        }
4516
4517 5
        return \array_map(['static', 'objectToArray'], $object);
4518
    }
4519
4520
    /**
4521
     * sorting keys
4522
     *
4523
     * @param array      $elements
4524
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4525
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4526
     *                              <strong>SORT_NATURAL</strong></p>
4527
     *
4528
     * @return static
4529
     *                <p>(Mutable) Return this Arrayy object.</p>
4530
     */
4531 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4532
    {
4533 18
        $direction = $this->getDirection($direction);
4534
4535
        switch ($direction) {
4536 18
            case 'desc':
4537 18
            case \SORT_DESC:
4538 6
                \krsort($elements, $strategy);
4539
4540 6
                break;
4541 13
            case 'asc':
4542 13
            case \SORT_ASC:
4543
            default:
4544 13
                \ksort($elements, $strategy);
4545
        }
4546
4547 18
        return $this;
4548
    }
4549
4550
    /**
4551
     * @param array      $elements  <p>Warning: used as reference</p>
4552
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4553
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4554
     *                              <strong>SORT_NATURAL</strong></p>
4555
     * @param bool       $keepKeys
4556
     *
4557
     * @return static
4558
     *                <p>(Mutable) Return this Arrayy object.</p>
4559
     */
4560 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4561
    {
4562 20
        $direction = $this->getDirection($direction);
4563
4564 20
        if (!$strategy) {
4565 20
            $strategy = \SORT_REGULAR;
4566
        }
4567
4568
        switch ($direction) {
4569 20
            case 'desc':
4570 20
            case \SORT_DESC:
4571 9
                if ($keepKeys) {
4572 5
                    \arsort($elements, $strategy);
4573
                } else {
4574 4
                    \rsort($elements, $strategy);
4575
                }
4576
4577 9
                break;
4578 11
            case 'asc':
4579 11
            case \SORT_ASC:
4580
            default:
4581 11
                if ($keepKeys) {
4582 4
                    \asort($elements, $strategy);
4583
                } else {
4584 7
                    \sort($elements, $strategy);
4585
                }
4586
        }
4587
4588 20
        return $this;
4589
    }
4590
4591
    /**
4592
     * @return bool
4593
     */
4594 846
    private function generatorToArray(): bool
4595
    {
4596 846
        if ($this->generator) {
4597 1
            $this->array = $this->getArray();
4598 1
            $this->generator = null;
4599
4600 1
            return true;
4601
        }
4602
4603 846
        return false;
4604
    }
4605
4606
    /**
4607
     * @return Property[]
4608
     */
4609 15
    private function getPropertiesFromPhpDoc(): array
4610
    {
4611 15
        static $PROPERTY_CACHE = [];
4612 15
        $cacheKey = 'Class::' . static::class;
4613
4614 15
        if (isset($PROPERTY_CACHE[$cacheKey])) {
4615 14
            return $PROPERTY_CACHE[$cacheKey];
4616
        }
4617
4618
        // init
4619 2
        $properties = [];
4620
4621 2
        $reflector = new \ReflectionClass($this);
4622 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
4623 2
        $docComment = $reflector->getDocComment();
4624 2
        if ($docComment) {
4625 2
            $docblock = $factory->create($docComment);
4626 2
            foreach ($docblock->getTagsByName('property') as $tag) {
4627
                /* @var $tag \phpDocumentor\Reflection\DocBlock\Tags\Property */
4628 2
                $properties[$tag->getVariableName()] = Property::fromPhpDocumentorProperty($tag);
4629
            }
4630
        }
4631
4632 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
4633
    }
4634
}
4635