Completed
Push — master ( 96bbd5...16a209 )
by Lars
02:22
created

Arrayy::isEmpty()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

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

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

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

Loading history...
2715
    {
2716 4
        $this->generatorToArray();
2717
2718 4
        if (\func_num_args()) {
2719 4
            $args = \array_merge([&$this->array], \func_get_args());
2720 4
            \array_push(...$args);
2721
        }
2722
2723 4
        return $this;
2724
    }
2725
2726
    /**
2727
     * Get a random value from the current array.
2728
     *
2729
     * @param int|null $number <p>How many values you will take?</p>
2730
     *
2731
     * @return static
2732
     *                <p>(Immutable)</p>
2733
     */
2734 18
    public function randomImmutable(int $number = null): self
2735
    {
2736 18
        $this->generatorToArray();
2737
2738 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...
2739 1
            return static::create([], $this->iteratorClass, false);
2740
        }
2741
2742 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...
2743
            /** @noinspection NonSecureArrayRandUsageInspection */
2744 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
2745
2746 13
            return static::create($arrayRandValue, $this->iteratorClass, false);
2747
        }
2748
2749 5
        $arrayTmp = $this->array;
2750
        /** @noinspection NonSecureShuffleUsageInspection */
2751 5
        \shuffle($arrayTmp);
2752
2753 5
        return static::create($arrayTmp, $this->iteratorClass, false)->firstsImmutable($number);
2754
    }
2755
2756
    /**
2757
     * Pick a random key/index from the keys of this array.
2758
     *
2759
     * @throws \RangeException If array is empty
2760
     *
2761
     * @return mixed
2762
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2763
     */
2764 4
    public function randomKey()
2765
    {
2766 4
        $result = $this->randomKeys(1);
2767
2768 4
        if (!isset($result[0])) {
2769
            $result[0] = null;
2770
        }
2771
2772 4
        return $result[0];
2773
    }
2774
2775
    /**
2776
     * Pick a given number of random keys/indexes out of this array.
2777
     *
2778
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2779
     *
2780
     * @throws \RangeException If array is empty
2781
     *
2782
     * @return static
2783
     *                <p>(Immutable)</p>
2784
     */
2785 13
    public function randomKeys(int $number): self
2786
    {
2787 13
        $this->generatorToArray();
2788
2789 13
        $count = \count($this->array, \COUNT_NORMAL);
2790
2791 13
        if ($number === 0 || $number > $count) {
2792 2
            throw new \RangeException(
2793 2
                \sprintf(
2794 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2795 2
                    $number,
2796 2
                    $count
2797
                )
2798
            );
2799
        }
2800
2801 11
        $result = (array) \array_rand($this->array, $number);
2802
2803 11
        return static::create($result, $this->iteratorClass, false);
2804
    }
2805
2806
    /**
2807
     * Get a random value from the current array.
2808
     *
2809
     * @param int|null $number <p>How many values you will take?</p>
2810
     *
2811
     * @return static
2812
     *                <p>(Mutable)</p>
2813
     */
2814 17
    public function randomMutable(int $number = null): self
2815
    {
2816 17
        $this->generatorToArray();
2817
2818 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...
2819
            return static::create([], $this->iteratorClass, false);
2820
        }
2821
2822 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...
2823
            /** @noinspection NonSecureArrayRandUsageInspection */
2824 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
2825 7
            $this->array = $arrayRandValue;
2826
2827 7
            return $this;
2828
        }
2829
2830
        /** @noinspection NonSecureShuffleUsageInspection */
2831 11
        \shuffle($this->array);
2832
2833 11
        return $this->firstsMutable($number);
2834
    }
2835
2836
    /**
2837
     * Pick a random value from the values of this array.
2838
     *
2839
     * @return mixed
2840
     *               <p>Get a random value or null if there wasn't a value.</p>
2841
     */
2842 4
    public function randomValue()
2843
    {
2844 4
        $result = $this->randomImmutable();
2845
2846 4
        if (!isset($result[0])) {
2847
            $result[0] = null;
2848
        }
2849
2850 4
        return $result[0];
2851
    }
2852
2853
    /**
2854
     * Pick a given number of random values out of this array.
2855
     *
2856
     * @param int $number
2857
     *
2858
     * @return static
2859
     *                <p>(Mutable)</p>
2860
     */
2861 7
    public function randomValues(int $number): self
2862
    {
2863 7
        return $this->randomMutable($number);
2864
    }
2865
2866
    /**
2867
     * Get a random value from an array, with the ability to skew the results.
2868
     *
2869
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2870
     *
2871
     * @param array    $array
2872
     * @param int|null $number <p>How many values you will take?</p>
2873
     *
2874
     * @return static
2875
     *                <p>(Immutable)</p>
2876
     */
2877 9
    public function randomWeighted(array $array, int $number = null): self
2878
    {
2879
        // init
2880 9
        $options = [];
2881
2882 9
        foreach ($array as $option => $weight) {
2883 9
            if ($this->searchIndex($option) !== false) {
2884 2
                for ($i = 0; $i < $weight; ++$i) {
2885 1
                    $options[] = $option;
2886
                }
2887
            }
2888
        }
2889
2890 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2891
    }
2892
2893
    /**
2894
     * Reduce the current array via callable e.g. anonymous-function.
2895
     *
2896
     * @param \callable $callable
2897
     * @param array     $init
2898
     *
2899
     * @return static
2900
     *                <p>(Immutable)</p>
2901
     */
2902 14
    public function reduce($callable, array $init = []): self
2903
    {
2904 14
        if ($this->generator) {
2905 1
            $result = $init;
2906
2907 1
            foreach($this->getGenerator() as $value) {
2908 1
                $result = $callable($result, $value);
2909
            }
2910
2911 1
            return static::create($result, $this->iteratorClass, false);
2912
        }
2913
2914 14
        $result = \array_reduce($this->array, $callable, $init);
2915
2916 14
        if ($result === null) {
2917
            $this->array = [];
2918
        } else {
2919 14
            $this->array = (array) $result;
2920
        }
2921
2922 14
        return static::create($this->array, $this->iteratorClass, false);
2923
    }
2924
2925
    /**
2926
     * Create a numerically re-indexed Arrayy object.
2927
     *
2928
     * @return static
2929
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2930
     */
2931 9
    public function reindex(): self
2932
    {
2933 9
        $this->generatorToArray();
2934
2935 9
        $this->array = \array_values($this->array);
2936
2937 9
        return $this;
2938
    }
2939
2940
    /**
2941
     * Return all items that fail the truth test.
2942
     *
2943
     * @param \Closure $closure
2944
     *
2945
     * @return static
2946
     *                <p>(Immutable)</p>
2947
     */
2948 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...
2949
    {
2950
        // init
2951 1
        $filtered = [];
2952
2953 1
        foreach ($this->getGenerator() as $key => $value) {
2954 1
            if (!$closure($value, $key)) {
2955 1
                $filtered[$key] = $value;
2956
            }
2957
        }
2958
2959 1
        return static::create($filtered, $this->iteratorClass, false);
2960
    }
2961
2962
    /**
2963
     * Remove a value from the current array (optional using dot-notation).
2964
     *
2965
     * @param mixed $key
2966
     *
2967
     * @return static
2968
     *                <p>(Immutable)</p>
2969
     */
2970 18
    public function remove($key): self
2971
    {
2972
        // recursive call
2973 18
        if (\is_array($key)) {
2974
            foreach ($key as $k) {
2975
                $this->internalRemove($k);
2976
            }
2977
2978
            return static::create($this->getArray(), $this->iteratorClass, false);
2979
        }
2980
2981 18
        $this->internalRemove($key);
2982
2983 18
        return static::create($this->getArray(), $this->iteratorClass, false);
2984
    }
2985
2986
    /**
2987
     * Remove the first value from the current array.
2988
     *
2989
     * @return static
2990
     *                <p>(Immutable)</p>
2991
     */
2992 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...
2993
    {
2994 7
        $tmpArray = $this->getArray();
2995
2996 7
        \array_shift($tmpArray);
2997
2998 7
        return static::create($tmpArray, $this->iteratorClass, false);
2999
    }
3000
3001
    /**
3002
     * Remove the last value from the current array.
3003
     *
3004
     * @return static
3005
     *                <p>(Immutable)</p>
3006
     */
3007 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...
3008
    {
3009 7
        $tmpArray = $this->getArray();
3010
3011 7
        \array_pop($tmpArray);
3012
3013 7
        return static::create($tmpArray, $this->iteratorClass, false);
3014
    }
3015
3016
    /**
3017
     * Removes a particular value from an array (numeric or associative).
3018
     *
3019
     * @param mixed $value
3020
     *
3021
     * @return static
3022
     *                <p>(Immutable)</p>
3023
     */
3024 7
    public function removeValue($value): self
3025
    {
3026 7
        $this->generatorToArray();
3027
3028
        // init
3029 7
        $isNumericArray = true;
3030
3031 7
        foreach ($this->getGenerator() as $key => $item) {
3032 6
            if ($item === $value) {
3033 6
                if (!\is_int($key)) {
3034
                    $isNumericArray = false;
3035
                }
3036 6
                unset($this->array[$key]);
3037
            }
3038
        }
3039
3040 7
        if ($isNumericArray) {
3041 7
            $this->array = \array_values($this->array);
3042
        }
3043
3044 7
        return static::create($this->array, $this->iteratorClass, false);
3045
    }
3046
3047
    /**
3048
     * Generate array of repeated arrays.
3049
     *
3050
     * @param int $times <p>How many times has to be repeated.</p>
3051
     *
3052
     * @return static
3053
     *                <p>(Immutable)</p>
3054
     */
3055 1
    public function repeat($times): self
3056
    {
3057 1
        if ($times === 0) {
3058 1
            return new static();
3059
        }
3060
3061 1
        return static::create(
3062 1
            \array_fill(0, (int) $times, $this->getArray()),
3063 1
            $this->iteratorClass,
3064 1
            false
3065
        );
3066
    }
3067
3068
    /**
3069
     * Replace a key with a new key/value pair.
3070
     *
3071
     * @param mixed $replace
3072
     * @param mixed $key
3073
     * @param mixed $value
3074
     *
3075
     * @return static
3076
     *                <p>(Immutable)</p>
3077
     */
3078 2
    public function replace($replace, $key, $value): self
3079
    {
3080 2
        $that = $this->remove($replace);
3081
3082 2
        return $that->set($key, $value);
3083
    }
3084
3085
    /**
3086
     * Create an array using the current array as values and the other array as keys.
3087
     *
3088
     * @param array $keys <p>An array of keys.</p>
3089
     *
3090
     * @return static
3091
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
3092
     */
3093 2
    public function replaceAllKeys(array $keys): self
3094
    {
3095 2
        return static::create(
3096 2
            \array_combine($keys, $this->getArray()),
3097 2
            $this->iteratorClass,
3098 2
            false
3099
        );
3100
    }
3101
3102
    /**
3103
     * Create an array using the current array as keys and the other array as values.
3104
     *
3105
     * @param array $array <p>An array o values.</p>
3106
     *
3107
     * @return static
3108
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3109
     */
3110 2
    public function replaceAllValues(array $array): self
3111
    {
3112 2
        return static::create(
3113 2
            \array_combine($this->array, $array),
3114 2
            $this->iteratorClass,
3115 2
            false
3116
        );
3117
    }
3118
3119
    /**
3120
     * Replace the keys in an array with another set.
3121
     *
3122
     * @param array $keys <p>An array of keys matching the array's size</p>
3123
     *
3124
     * @return static
3125
     *                <p>(Immutable)</p>
3126
     */
3127 1
    public function replaceKeys(array $keys): self
3128
    {
3129 1
        $values = \array_values($this->getArray());
3130 1
        $result = \array_combine($keys, $values);
3131
3132 1
        return static::create($result, $this->iteratorClass, false);
3133
    }
3134
3135
    /**
3136
     * Replace the first matched value in an array.
3137
     *
3138
     * @param mixed $search      <p>The value to replace.</p>
3139
     * @param mixed $replacement <p>The value to replace.</p>
3140
     *
3141
     * @return static
3142
     *                <p>(Immutable)</p>
3143
     */
3144 3
    public function replaceOneValue($search, $replacement = ''): self
3145
    {
3146 3
        $array = $this->getArray();
3147 3
        $key = \array_search($search, $array, true);
3148
3149 3
        if ($key !== false) {
3150 3
            $array[$key] = $replacement;
3151
        }
3152
3153 3
        return static::create($array, $this->iteratorClass, false);
3154
    }
3155
3156
    /**
3157
     * Replace values in the current array.
3158
     *
3159
     * @param mixed $search      <p>The value to replace.</p>
3160
     * @param mixed $replacement <p>What to replace it with.</p>
3161
     *
3162
     * @return static
3163
     *                <p>(Immutable)</p>
3164
     */
3165 1
    public function replaceValues($search, $replacement = ''): self
3166
    {
3167 1
        $array = $this->each(
3168
            static function ($value) use ($search, $replacement) {
3169 1
                return \str_replace($search, $replacement, $value);
3170 1
            }
3171
        );
3172
3173 1
        return $array;
3174
    }
3175
3176
    /**
3177
     * Get the last elements from index $from until the end of this array.
3178
     *
3179
     * @param int $from
3180
     *
3181
     * @return static
3182
     *                <p>(Immutable)</p>
3183
     */
3184 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...
3185
    {
3186 15
        $tmpArray = $this->getArray();
3187
3188 15
        return static::create(
3189 15
            \array_splice($tmpArray, $from),
3190 15
            $this->iteratorClass,
3191 15
            false
3192
        );
3193
    }
3194
3195
    /**
3196
     * Return the array in the reverse order.
3197
     *
3198
     * @return static
3199
     *                <p>(Mutable) Return this Arrayy object.</p>
3200
     */
3201 8
    public function reverse(): self
3202
    {
3203 8
        $this->generatorToArray();
3204
3205 8
        $this->array = \array_reverse($this->array);
3206
3207 8
        return $this;
3208
    }
3209
3210
    /**
3211
     * Sort an array in reverse order.
3212
     *
3213
     * @param int $sort_flags [optional] <p>
3214
     *                        You may modify the behavior of the sort using the optional
3215
     *                        parameter sort_flags, for details
3216
     *                        see sort.
3217
     *                        </p>
3218
     *
3219
     * @return static
3220
     *                <p>(Mutable) Return this Arrayy object.</p>
3221
     */
3222 4
    public function rsort(int $sort_flags = 0): self
3223
    {
3224 4
        $this->generatorToArray();
3225
3226 4
        \rsort($this->array, $sort_flags);
3227
3228 4
        return $this;
3229
    }
3230
3231
    /**
3232
     * Search for the first index of the current array via $value.
3233
     *
3234
     * @param mixed $value
3235
     *
3236
     * @return float|int|string|false
3237
     *                                <p>Will return <b>FALSE</b> if the value can't be found.</p>
3238
     */
3239 20
    public function searchIndex($value)
3240
    {
3241 20
        foreach ($this->getGenerator() as $keyFromArray => $valueFromArray) {
3242 19
            if ($value === $valueFromArray) {
3243 9
                return $keyFromArray;
3244
            }
3245
        }
3246
3247 11
        return false;
3248
    }
3249
3250
    /**
3251
     * Search for the value of the current array via $index.
3252
     *
3253
     * @param mixed $index
3254
     *
3255
     * @return static
3256
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3257
     */
3258 9
    public function searchValue($index): self
3259
    {
3260 9
        $this->generatorToArray();
3261
3262
        // init
3263 9
        $return = [];
3264
3265 9
        if ($this->isEmpty()) {
3266
            return static::create([], $this->iteratorClass, false);
3267
        }
3268
3269
        // php cast "bool"-index into "int"-index
3270 9
        if ((bool) $index === $index) {
3271 1
            $index = (int) $index;
3272
        }
3273
3274 9
        if (\array_key_exists($index, $this->array) === true) {
3275 7
            $return = [$this->array[$index]];
3276
        }
3277
3278 9
        return static::create($return, $this->iteratorClass, false);
3279
    }
3280
3281
    /**
3282
     * Set a value for the current array (optional using dot-notation).
3283
     *
3284
     * @param string $key   <p>The key to set.</p>
3285
     * @param mixed  $value <p>Its value.</p>
3286
     *
3287
     * @return static
3288
     *                <p>(Mutable)</p>
3289
     */
3290 17
    public function set($key, $value): self
3291
    {
3292 17
        $this->generatorToArray();
3293
3294 17
        $this->internalSet($key, $value);
3295
3296 17
        return $this;
3297
    }
3298
3299
    /**
3300
     * Get a value from a array and set it if it was not.
3301
     *
3302
     * WARNING: this method only set the value, if the $key is not already set
3303
     *
3304
     * @param mixed $key      <p>The key</p>
3305
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
3306
     *
3307
     * @return mixed
3308
     *               <p>(Mutable)</p>
3309
     */
3310 11
    public function setAndGet($key, $fallback = null)
3311
    {
3312 11
        $this->generatorToArray();
3313
3314
        // If the key doesn't exist, set it.
3315 11
        if (!$this->has($key)) {
3316 4
            $this->array = $this->set($key, $fallback)->getArray();
3317
        }
3318
3319 11
        return $this->get($key);
3320
    }
3321
3322
    /**
3323
     * Shifts a specified value off the beginning of array.
3324
     *
3325
     * @return mixed
3326
     *               <p>(Mutable) A shifted element from the current array.</p>
3327
     */
3328 4
    public function shift()
3329
    {
3330 4
        $this->generatorToArray();
3331
3332 4
        return \array_shift($this->array);
3333
    }
3334
3335
    /**
3336
     * Shuffle the current array.
3337
     *
3338
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3339
     * @param array $array  [optional]
3340
     *
3341
     * @return static
3342
     *                <p>(Immutable)</p>
3343
     */
3344 1
    public function shuffle(bool $secure = false, array $array = null): self
3345
    {
3346 1
        if ($array === null) {
3347 1
            $array = $this->getArray();
3348
        }
3349
3350 1
        if ($secure !== true) {
3351
            /** @noinspection NonSecureShuffleUsageInspection */
3352 1
            \shuffle($array);
3353
        } else {
3354 1
            $size = \count($array, \COUNT_NORMAL);
3355 1
            $keys = \array_keys($array);
3356 1
            for ($i = $size - 1; $i > 0; --$i) {
3357
                try {
3358 1
                    $r = \random_int(0, $i);
3359
                } catch (\Exception $e) {
3360
                    /** @noinspection RandomApiMigrationInspection */
3361
                    $r = \mt_rand(0, $i);
3362
                }
3363 1
                if ($r !== $i) {
3364
                    $temp = $array[$keys[$r]];
3365
                    $array[$keys[$r]] = $array[$keys[$i]];
3366
                    $array[$keys[$i]] = $temp;
3367
                }
3368
            }
3369
3370
            // reset indices
3371 1
            $array = \array_values($array);
3372
        }
3373
3374 1
        foreach ($array as $key => $value) {
3375
            // check if recursive is needed
3376 1
            if (\is_array($value) === true) {
3377
                $array[$key] = $this->shuffle($secure, $value);
3378
            }
3379
        }
3380
3381 1
        return static::create($array, $this->iteratorClass, false);
3382
    }
3383
3384
    /**
3385
     * Count the values from the current array.
3386
     *
3387
     * alias: for "Arrayy->count()"
3388
     *
3389
     * @param int $mode
3390
     *
3391
     * @return int
3392
     */
3393 20
    public function size(int $mode = \COUNT_NORMAL): int
3394
    {
3395 20
        return $this->count($mode);
3396
    }
3397
3398
    /**
3399
     * Counts all elements in an array, or something in an object.
3400
     *
3401
     * <p>
3402
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3403
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3404
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3405
     * implemented and used in PHP.
3406
     * </p>
3407
     *
3408
     * @return int
3409
     *             <p>
3410
     *             The number of elements in var, which is
3411
     *             typically an array, since anything else will have one
3412
     *             element.
3413
     *             </p>
3414
     *             <p>
3415
     *             If var is not an array or an object with
3416
     *             implemented Countable interface,
3417
     *             1 will be returned.
3418
     *             There is one exception, if var is &null;,
3419
     *             0 will be returned.
3420
     *             </p>
3421
     *             <p>
3422
     *             Caution: count may return 0 for a variable that isn't set,
3423
     *             but it may also return 0 for a variable that has been initialized with an
3424
     *             empty array. Use isset to test if a variable is set.
3425
     *             </p>
3426
     */
3427 10
    public function sizeRecursive(): int
3428
    {
3429 10
        return \count($this->getArray(), \COUNT_RECURSIVE);
3430
    }
3431
3432
    /**
3433
     * Extract a slice of the array.
3434
     *
3435
     * @param int      $offset       <p>Slice begin index.</p>
3436
     * @param int|null $length       <p>Length of the slice.</p>
3437
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3438
     *
3439
     * @return static
3440
     *                <p>A slice of the original array with length $length.</p>
3441
     */
3442 4
    public function slice(int $offset, int $length = null, bool $preserveKeys = false): self
3443
    {
3444 4
        return static::create(
3445 4
            \array_slice(
3446 4
                $this->getArray(),
3447 4
                $offset,
3448 4
                $length,
3449 4
                $preserveKeys
3450
            ),
3451 4
            $this->iteratorClass,
3452 4
            false
3453
        );
3454
    }
3455
3456
    /**
3457
     * Sort the current array and optional you can keep the keys.
3458
     *
3459
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3460
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3461
     *                              <strong>SORT_NATURAL</strong></p>
3462
     * @param bool       $keepKeys
3463
     *
3464
     * @return static
3465
     *                <p>(Mutable) Return this Arrayy object.</p>
3466
     */
3467 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
3468
    {
3469 20
        $this->generatorToArray();
3470
3471 20
        return $this->sorting(
3472 20
            $this->array,
3473 20
            $direction,
3474 20
            $strategy,
3475 20
            $keepKeys
3476
        );
3477
    }
3478
3479
    /**
3480
     * Sort the current array by key.
3481
     *
3482
     * @see http://php.net/manual/en/function.ksort.php
3483
     * @see http://php.net/manual/en/function.krsort.php
3484
     *
3485
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3486
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3487
     *                              <strong>SORT_NATURAL</strong></p>
3488
     *
3489
     * @return static
3490
     *                <p>(Mutable) Return this Arrayy object.</p>
3491
     */
3492 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3493
    {
3494 18
        $this->generatorToArray();
3495
3496 18
        $this->sorterKeys($this->array, $direction, $strategy);
3497
3498 18
        return $this;
3499
    }
3500
3501
    /**
3502
     * Sort the current array by value.
3503
     *
3504
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3505
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3506
     *                              <strong>SORT_NATURAL</strong></p>
3507
     *
3508
     * @return static
3509
     *                <p>(Mutable)</p>
3510
     */
3511 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3512
    {
3513 1
        return $this->sort($direction, $strategy, true);
3514
    }
3515
3516
    /**
3517
     * Sort the current array by value.
3518
     *
3519
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3520
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3521
     *                              <strong>SORT_NATURAL</strong></p>
3522
     *
3523
     * @return static
3524
     *                <p>(Mutable)</p>
3525
     */
3526 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3527
    {
3528 1
        return $this->sort($direction, $strategy, false);
3529
    }
3530
3531
    /**
3532
     * Sort a array by value, by a closure or by a property.
3533
     *
3534
     * - If the sorter is null, the array is sorted naturally.
3535
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3536
     *
3537
     * @param \callable|null $sorter
3538
     * @param int|string     $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3539
     * @param int            $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3540
     *                                  <strong>SORT_NATURAL</strong></p>
3541
     *
3542
     * @return static
3543
     *                <p>(Immutable)</p>
3544
     */
3545 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3546
    {
3547 1
        $array = $this->getArray();
3548 1
        $direction = $this->getDirection($direction);
3549
3550
        // Transform all values into their results.
3551 1
        if ($sorter) {
3552 1
            $arrayy = static::create($array, $this->iteratorClass, false);
3553
3554 1
            $that = $this;
3555 1
            $results = $arrayy->each(
3556
                static function ($value) use ($sorter, $that) {
3557 1
                    return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3558 1
                }
3559
            );
3560
3561 1
            $results = $results->getArray();
3562
        } else {
3563 1
            $results = $array;
3564
        }
3565
3566
        // Sort by the results and replace by original values
3567 1
        \array_multisort($results, $direction, $strategy, $array);
3568
3569 1
        return static::create($array, $this->iteratorClass, false);
3570
    }
3571
3572
    /**
3573
     * Split an array in the given amount of pieces.
3574
     *
3575
     * @param int  $numberOfPieces
3576
     * @param bool $keepKeys
3577
     *
3578
     * @return static
3579
     *                <p>(Immutable)</p>
3580
     */
3581 1
    public function split(int $numberOfPieces = 2, bool $keepKeys = false): self
3582
    {
3583 1
        $this->generatorToArray();
3584
3585 1
        $arrayCount = \count($this->array, \COUNT_NORMAL);
3586
3587 1
        if ($arrayCount === 0) {
3588 1
            $result = [];
3589
        } else {
3590 1
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
3591 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
3592
        }
3593
3594 1
        return static::create($result, $this->iteratorClass, false);
3595
    }
3596
3597
    /**
3598
     * Stripe all empty items.
3599
     *
3600
     * @return static
3601
     *                <p>(Immutable)</p>
3602
     */
3603 1
    public function stripEmpty(): self
3604
    {
3605 1
        return $this->filter(
3606
            static function ($item) {
3607 1
                if ($item === null) {
3608 1
                    return false;
3609
                }
3610
3611 1
                return (bool) \trim((string) $item);
3612 1
            }
3613
        );
3614
    }
3615
3616
    /**
3617
     * Swap two values between positions by key.
3618
     *
3619
     * @param int|string $swapA <p>a key in the array</p>
3620
     * @param int|string $swapB <p>a key in the array</p>
3621
     *
3622
     * @return static
3623
     *                <p>(Immutable)</p>
3624
     */
3625 1
    public function swap($swapA, $swapB): self
3626
    {
3627 1
        $array = $this->getArray();
3628
3629 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3630
3631 1
        return static::create($array, $this->iteratorClass, false);
3632
    }
3633
3634
    /**
3635
     * alias: for "Arrayy->getArray()"
3636
     *
3637
     * @see Arrayy::getArray()
3638
     */
3639 192
    public function toArray()
3640
    {
3641 192
        return $this->getArray();
3642
    }
3643
3644
    /**
3645
     * Convert the current array to JSON.
3646
     *
3647
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3648
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3649
     *
3650
     * @return string
3651
     */
3652 6
    public function toJson(int $options = 0, int $depth = 512): string
3653
    {
3654
        /** @noinspection PhpComposerExtensionStubsInspection */
3655 6
        return \json_encode($this->getArray(), $options, $depth);
3656
    }
3657
3658
    /**
3659
     * Implodes array to a string with specified separator.
3660
     *
3661
     * @param string $separator [optional] <p>The element's separator.</p>
3662
     *
3663
     * @return string
3664
     *                <p>The string representation of array, separated by ",".</p>
3665
     */
3666 19
    public function toString(string $separator = ','): string
3667
    {
3668 19
        return $this->implode($separator);
3669
    }
3670
3671
    /**
3672
     * Return a duplicate free copy of the current array.
3673
     *
3674
     * @return static
3675
     *                <p>(Mutable)</p>
3676
     */
3677 10
    public function unique(): self
3678
    {
3679
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3680
3681 10
        $this->array = $this->reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->reduce(static fun...esultArray; }, array()) of type this<Arrayy\Arrayy> 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...
3682
            static function ($resultArray, $value) {
3683 9
                if (!\in_array($value, $resultArray, true)) {
3684 9
                    $resultArray[] = $value;
3685
                }
3686
3687 9
                return $resultArray;
3688 10
            },
3689 10
            []
3690
        );
3691 10
        $this->generator = null;
3692
3693 10
        return $this;
3694
    }
3695
3696
    /**
3697
     * Return a duplicate free copy of the current array. (with the old keys)
3698
     *
3699
     * @return static
3700
     *                <p>(Mutable)</p>
3701
     */
3702 11
    public function uniqueKeepIndex(): self
3703
    {
3704
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3705
3706
        // init
3707 11
        $array = $this->getArray();
3708
3709 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...
3710 11
            \array_keys($array),
3711
            static function ($resultArray, $key) use ($array) {
3712 10
                if (!\in_array($array[$key], $resultArray, true)) {
3713 10
                    $resultArray[$key] = $array[$key];
3714
                }
3715
3716 10
                return $resultArray;
3717 11
            },
3718 11
            []
3719
        );
3720 11
        $this->generator = null;
3721
3722 11
        if ($this->array === null) {
3723
            $this->array = [];
3724
        } else {
3725 11
            $this->array = (array) $this->array;
3726
        }
3727
3728 11
        return $this;
3729
    }
3730
3731
    /**
3732
     * alias: for "Arrayy->unique()"
3733
     *
3734
     * @return static
3735
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3736
     *
3737
     * @see Arrayy::unique()
3738
     */
3739 10
    public function uniqueNewIndex(): self
3740
    {
3741 10
        return $this->unique();
3742
    }
3743
3744
    /**
3745
     * Prepends one or more values to the beginning of array at once.
3746
     *
3747
     * @return static
3748
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3749
     */
3750 4 View Code Duplication
    public function unshift(/* variadic arguments allowed */): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3751
    {
3752 4
        $this->generatorToArray();
3753
3754 4
        if (\func_num_args()) {
3755 4
            $args = \array_merge([&$this->array], \func_get_args());
3756 4
            \array_unshift(...$args);
3757
        }
3758
3759 4
        return $this;
3760
    }
3761
3762
    /**
3763
     * Get all values from a array.
3764
     *
3765
     * @return static
3766
     *                <p>(Immutable)</p>
3767
     */
3768 2
    public function values(): self
3769
    {
3770 2
        return static::create(
3771 2
            \array_values( $this->getArray()),
3772 2
            $this->iteratorClass,
3773 2
            false
3774
        );
3775
    }
3776
3777
    /**
3778
     * Apply the given function to every element in the array, discarding the results.
3779
     *
3780
     * @param \callable $callable
3781
     * @param bool      $recursive <p>Whether array will be walked recursively or no</p>
3782
     *
3783
     * @return static
3784
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3785
     */
3786 37
    public function walk($callable, bool $recursive = false): self
3787
    {
3788 37
        $this->generatorToArray();
3789
3790 37
        if ($recursive === true) {
3791 32
            \array_walk_recursive($this->array, $callable);
3792
        } else {
3793 18
            \array_walk($this->array, $callable);
3794
        }
3795
3796 37
        return $this;
3797
    }
3798
3799
    /**
3800
     * Convert an array into a object.
3801
     *
3802
     * @param array $array PHP array
3803
     *
3804
     * @return \stdClass
3805
     */
3806 4
    protected static function arrayToObject(array $array = []): \stdClass
3807
    {
3808
        // init
3809 4
        $object = new \stdClass();
3810
3811 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
3812 1
            return $object;
3813
        }
3814
3815 3
        foreach ($array as $name => $value) {
3816 3
            if (\is_array($value)) {
3817 1
                $object->{$name} = self::arrayToObject($value);
3818
            } else {
3819 3
                $object->{$name} = $value;
3820
            }
3821
        }
3822
3823 3
        return $object;
3824
    }
3825
3826
    /**
3827
     * @param array|\Generator|null $input        <p>
3828
     *                                            An array containing keys to return.
3829
     *                                            </p>
3830
     * @param mixed                 $search_value [optional] <p>
3831
     *                                            If specified, then only keys containing these values are returned.
3832
     *                                            </p>
3833
     * @param bool                  $strict       [optional] <p>
3834
     *                                            Determines if strict comparison (===) should be used during the
3835
     *                                            search.
3836
     *                                            </p>
3837
     *
3838
     * @return array
3839
     *               <p>an array of all the keys in input</p>
3840
     */
3841 10
    protected function array_keys_recursive(
3842
        $input = null,
3843
        $search_value = null,
3844
        bool $strict = true
3845
    ): array
3846
    {
3847
        // init
3848 10
        $keys = [];
3849 10
        $keysTmp = [[]]; // the inner empty array covers cases when no loops were made
3850
3851 10
        if ($input === null) {
3852
            $input = $this->getGenerator();
3853
        }
3854
3855 10
        foreach ($input as $key => $value) {
3856
            if (
3857 10
                $search_value === null
3858
                ||
3859
                (
3860
                    \is_array($search_value) === true
3861
                    &&
3862 10
                    \in_array($key, $search_value, $strict)
3863
                )
3864
            ) {
3865 10
                $keys[] = $key;
3866
            }
3867
3868
            // check if recursive is needed
3869 10
            if (\is_array($value) === true) {
3870 4
                $keysTmp[] = $this->array_keys_recursive($value);
3871
            }
3872
        }
3873
3874 10
        return \array_merge($keys, ...$keysTmp);
3875
    }
3876
3877
    /**
3878
     * @param mixed      $path
3879
     * @param \callable  $callable
3880
     * @param array|null $currentOffset
3881
     */
3882 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
3883
    {
3884 4
        $this->generatorToArray();
3885
3886 4
        if ($currentOffset === null) {
3887 4
            $currentOffset = &$this->array;
3888
        }
3889
3890 4
        $explodedPath = \explode($this->pathSeparator, $path);
3891 4
        $nextPath = \array_shift($explodedPath);
3892
3893 4
        if (!isset($currentOffset[$nextPath])) {
3894
            return;
3895
        }
3896
3897 4
        if (!empty($explodedPath)) {
3898 1
            $this->callAtPath(
3899 1
                \implode($this->pathSeparator, $explodedPath),
3900 1
                $callable,
3901 1
                $currentOffset[$nextPath]
3902
            );
3903
        } else {
3904 4
            $callable($currentOffset[$nextPath]);
3905
        }
3906 4
    }
3907
3908
    /**
3909
     * create a fallback for array
3910
     *
3911
     * 1. use the current array, if it's a array
3912
     * 2. fallback to empty array, if there is nothing
3913
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
3914
     * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
3915
     * 5. call "__toArray()" on object, if the method exists
3916
     * 6. cast a string or object with "__toString()" into an array
3917
     * 7. throw a "InvalidArgumentException"-Exception
3918
     *
3919
     * @param mixed $array
3920
     *
3921
     * @throws \InvalidArgumentException
3922
     *
3923
     * @return array
3924
     */
3925 891
    protected function fallbackForArray(&$array): array
3926
    {
3927 891
        if (\is_array($array)) {
3928 888
            return $array;
3929
        }
3930
3931 16
        if (!$array) {
3932 6
            return [];
3933
        }
3934
3935 15
        $isObject = \is_object($array);
3936
3937 15
        if ($isObject && $array instanceof self) {
3938 1
            return $array->getArray();
3939
        }
3940
3941 14
        if ($isObject && $array instanceof \ArrayAccess) {
3942
            return static::createFromObject($array)->getArray();
3943
        }
3944
3945 14
        if ($isObject && $array instanceof \ArrayObject) {
3946
            return $array->getArrayCopy();
3947
        }
3948
3949 14
        if ($isObject && $array instanceof \Generator) {
3950 5
            $this->generator = $array;
3951
3952 5
            return [];
3953
        }
3954
3955 9
        if ($isObject && \method_exists($array, '__toArray')) {
3956
            return (array) $array->__toArray();
3957
        }
3958
3959
        if (
3960 9
            \is_string($array)
3961
            ||
3962 9
            ($isObject && \method_exists($array, '__toString'))
3963
        ) {
3964 7
            return [(string) $array];
3965
        }
3966
3967 2
        throw new \InvalidArgumentException(
3968 2
            'Passed value should be a array'
3969
        );
3970
    }
3971
3972
    /**
3973
     * Get correct PHP constant for direction.
3974
     *
3975
     * @param int|string $direction
3976
     *
3977
     * @return int
3978
     */
3979 39
    protected function getDirection($direction): int
3980
    {
3981 39
        if (\is_string($direction)) {
3982 10
            $direction = \strtolower($direction);
3983
3984 10
            if ($direction === 'desc') {
3985 2
                $direction = \SORT_DESC;
3986
            } else {
3987 8
                $direction = \SORT_ASC;
3988
            }
3989
        }
3990
3991
        if (
3992 39
            $direction !== \SORT_DESC
3993
            &&
3994 39
            $direction !== \SORT_ASC
3995
        ) {
3996
            $direction = \SORT_ASC;
3997
        }
3998
3999 39
        return $direction;
4000
    }
4001
4002
    /**
4003
     * @return array|Property[]
4004
     */
4005 10
    protected function getPublicProperties(): array
4006
    {
4007 10
        static $PROPERTY_CACHE = [];
4008 10
        $cacheKey = 'Class::' . static::class;
4009
4010 10
        if (isset($PROPERTY_CACHE[$cacheKey])) {
4011 9
            return $PROPERTY_CACHE[$cacheKey];
4012
        }
4013
4014
        // init
4015 2
        $properties = [];
4016
4017 2
        $reflector = new \ReflectionClass($this);
4018 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
4019 2
        $docblock = $factory->create($reflector->getDocComment());
4020 2
        foreach ($docblock->getTagsByName('property') as $tag) {
4021
            /* @var $tag \phpDocumentor\Reflection\DocBlock\Tags\Property */
4022 2
            $properties[$tag->getVariableName()] = Property::fromPhpDocumentorProperty($tag);
4023
        }
4024
4025 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
4026
    }
4027
4028
    /**
4029
     * @param mixed               $glue
4030
     * @param array|static|string $pieces
4031
     * @param bool                $useKeys
4032
     *
4033
     * @return string
4034
     */
4035 35
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
4036
    {
4037 35
        if ($pieces instanceof self) {
4038
            $pieces = $pieces->getArray();
4039
        }
4040
4041 35
        if (\is_array($pieces)) {
4042 35
            $pieces_count = \count($pieces, \COUNT_NORMAL);
4043 35
            $pieces_count_not_zero = $pieces_count > 0;
4044
4045 35
            return \implode(
4046 35
                $glue,
4047 35
                \array_map(
4048 35
                    [$this, 'implode_recursive'],
4049 35
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
4050 35
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
4051
                )
4052
            );
4053
        }
4054
4055 35
        return (string) $pieces;
4056
    }
4057
4058
    /**
4059
     * @param mixed                 $needle   <p>
4060
     *                                        The searched value.
4061
     *                                        </p>
4062
     *                                        <p>
4063
     *                                        If needle is a string, the comparison is done
4064
     *                                        in a case-sensitive manner.
4065
     *                                        </p>
4066
     * @param array|\Generator|null $haystack <p>
4067
     *                                        The array.
4068
     *                                        </p>
4069
     * @param bool                  $strict   [optional] <p>
4070
     *                                        If the third parameter strict is set to true
4071
     *                                        then the in_array function will also check the
4072
     *                                        types of the
4073
     *                                        needle in the haystack.
4074
     *                                        </p>
4075
     *
4076
     * @return bool
4077
     *              <p>true if needle is found in the array, false otherwise</p>
4078
     */
4079 44
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
4080
    {
4081 44
        if ($haystack === null) {
4082
            $haystack = $this->getGenerator();
4083
        }
4084
4085 44
        foreach ($haystack as $item) {
4086 36
            if (\is_array($item) === true) {
4087 8
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
4088
            } else {
4089 36
                $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
4090
            }
4091
4092 36
            if ($returnTmp === true) {
4093 26
                return true;
4094
            }
4095
        }
4096
4097 18
        return false;
4098
    }
4099
4100
    /**
4101
     * @param mixed $value
4102
     */
4103
    protected function internalGetArray(&$value)
4104
    {
4105
        if ($value instanceof self) {
4106
            $valueTmp = $value->getArray();
4107
            if (\count($valueTmp, \COUNT_NORMAL) === 0) {
4108
                $value = [];
4109
            } else {
4110
                /** @noinspection PhpUnusedLocalVariableInspection */
4111
                $value = &$valueTmp;
4112
            }
4113
        }
4114
4115
        /** @noinspection PhpComposerExtensionStubsInspection */
4116
        /** @noinspection NotOptimalIfConditionsInspection */
4117
        if (
4118
            \class_exists('JsonSerializable')
4119
            &&
4120
            $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...
4121
        ) {
4122
4123
            /** @noinspection PhpUnusedLocalVariableInspection */
4124
            $value = &$value->jsonSerialize();
4125
        }
4126
    }
4127
4128
    /**
4129
     * Internal mechanics of remove method.
4130
     *
4131
     * @param mixed $key
4132
     *
4133
     * @return bool
4134
     */
4135 18
    protected function internalRemove($key): bool
4136
    {
4137 18
        $this->generatorToArray();
4138
4139 18
        $path = \explode($this->pathSeparator, (string) $key);
4140
4141
        // Crawl though the keys
4142 18
        while (\count($path, \COUNT_NORMAL) > 1) {
4143
            $key = \array_shift($path);
4144
4145
            if (!$this->has($key)) {
4146
                return false;
4147
            }
4148
4149
            $this->array = &$this->array[$key];
4150
        }
4151
4152 18
        $key = \array_shift($path);
4153
4154 18
        unset($this->array[$key]);
4155
4156 18
        return true;
4157
    }
4158
4159
    /**
4160
     * Internal mechanic of set method.
4161
     *
4162
     * @param string|null $key
4163
     * @param mixed       $value
4164
     *
4165
     * @return bool
4166
     */
4167 780
    protected function internalSet($key, $value): bool
4168
    {
4169 780
        if ($this->checkPropertyTypes === true) {
4170 8
            if (isset($this->properties[$key]) === false) {
4171
                throw new \InvalidArgumentException('The key ' . $key . ' does not exists as @property in the class (' . \get_class($this) . ').');
4172
            }
4173
4174 8
            $this->properties[$key]->checkType($value);
4175
        }
4176
4177 779
        if ($key === null) {
4178
            return false;
4179
        }
4180
4181 779
        $this->generatorToArray();
4182
4183
        // init
4184 779
        $array = &$this->array;
4185 779
        $path = \explode($this->pathSeparator, (string) $key);
4186
4187
        // Crawl through the keys
4188 779
        while (\count($path, \COUNT_NORMAL) > 1) {
4189 3
            $key = \array_shift($path);
4190
4191 3
            $array = &$array[$key];
4192
        }
4193
4194 779
        $array[\array_shift($path)] = $value;
4195
4196 779
        return true;
4197
    }
4198
4199
    /**
4200
     * Convert a object into an array.
4201
     *
4202
     * @param object $object
4203
     *
4204
     * @return mixed
4205
     */
4206 5
    protected static function objectToArray($object)
4207
    {
4208 5
        if (!\is_object($object)) {
4209 4
            return $object;
4210
        }
4211
4212 5
        if (\is_object($object)) {
4213 5
            $object = \get_object_vars($object);
4214
        }
4215
4216 5
        return \array_map(['self', 'objectToArray'], $object);
4217
    }
4218
4219
    /**
4220
     * sorting keys
4221
     *
4222
     * @param array      $elements
4223
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4224
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4225
     *                              <strong>SORT_NATURAL</strong></p>
4226
     *
4227
     * @return static
4228
     *                <p>(Mutable) Return this Arrayy object.</p>
4229
     */
4230 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4231
    {
4232 18
        $direction = $this->getDirection($direction);
4233
4234 18
        switch ($direction) {
4235 18
            case 'desc':
4236
            case \SORT_DESC:
4237 6
                \krsort($elements, $strategy);
4238
4239 6
                break;
4240 13
            case 'asc':
4241 13
            case \SORT_ASC:
4242
            default:
4243 13
                \ksort($elements, $strategy);
4244
        }
4245
4246 18
        return $this;
4247
    }
4248
4249
    /**
4250
     * @param array      $elements  <p>Warning: used as reference</p>
4251
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4252
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4253
     *                              <strong>SORT_NATURAL</strong></p>
4254
     * @param bool       $keepKeys
4255
     *
4256
     * @return static
4257
     *                <p>(Mutable) Return this Arrayy object.</p>
4258
     */
4259 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4260
    {
4261 20
        $direction = $this->getDirection($direction);
4262
4263 20
        if (!$strategy) {
4264 20
            $strategy = \SORT_REGULAR;
4265
        }
4266
4267 20
        switch ($direction) {
4268 20
            case 'desc':
4269
            case \SORT_DESC:
4270 9
                if ($keepKeys) {
4271 5
                    \arsort($elements, $strategy);
4272
                } else {
4273 4
                    \rsort($elements, $strategy);
4274
                }
4275
4276 9
                break;
4277 11
            case 'asc':
4278 11
            case \SORT_ASC:
4279
            default:
4280 11
                if ($keepKeys) {
4281 4
                    \asort($elements, $strategy);
4282
                } else {
4283 7
                    \sort($elements, $strategy);
4284
                }
4285
        }
4286
4287 20
        return $this;
4288
    }
4289
}
4290