Completed
Push — master ( 66ac21...449db5 )
by Lars
01:50
created

Arrayy::indexBy()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 13
ccs 6
cts 6
cp 1
crap 3
rs 9.8333
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 string
25
     */
26
    protected $iteratorClass = ArrayyIterator::class;
27
28
    /**
29
     * @var string
30
     */
31
    protected $pathSeparator = '.';
32
33
    /**
34
     * @var bool
35
     */
36
    protected $checkPropertyTypes = false;
37
38
    /**
39
     * @var bool
40
     */
41
    protected $checkForMissingPropertiesInConstructor = false;
42
43
    /**
44
     * @var bool
45
     */
46
    protected $checkPropertiesMismatchInConstructor = false;
47
48
    /**
49
     * @var array|Property[]
50
     */
51
    protected $properties = [];
52
53
    /** @noinspection MagicMethodsValidityInspection */
54
    /** @noinspection PhpMissingParentConstructorInspection */
55
56
    /**
57
     * Initializes
58
     *
59
     * @param mixed  $array                                  <p>
60
     *                                                       Should be an array, otherwise it will try to convert
61
     *                                                       it into an array.
62
     *                                                       </p>
63
     * @param string $iteratorClass                          optional <p>
64
     *                                                       You can overwrite the ArrayyIterator, but mostly you don't
65
     *                                                       need this option.
66
     *                                                       </p>
67
     * @param bool   $checkForMissingPropertiesInConstructor optional <p>
68
     *                                                       You need to extend the "Arrayy"-class and you need to set
69
     *                                                       the $checkPropertiesMismatchInConstructor class property to
70
     *                                                       true, otherwise this option didn't not work anyway.
71
     *                                                       </p>
72
     */
73 891
    public function __construct(
74
        $array = [],
75
        string $iteratorClass = ArrayyIterator::class,
76
        bool $checkForMissingPropertiesInConstructor = true
77
    ) {
78 891
        $array = $this->fallbackForArray($array);
79
80
        // used only for serialize + unserialize, all other methods are overwritten
81 889
        parent::__construct([], 0, $iteratorClass);
82
83
        if (
84 889
            $this->checkPropertyTypes === true
85
            ||
86
            (
87 879
                $this->checkForMissingPropertiesInConstructor === true
88
                &&
89 889
                $checkForMissingPropertiesInConstructor === true
90
            )
91
        ) {
92 10
            $this->properties = $this->getPublicProperties();
93
        }
94
95
        if (
96 889
            $this->checkPropertiesMismatchInConstructor === true
97
            &&
98 889
            \count($array) !== 0
99
            &&
100 889
            \count(\array_diff_key($this->properties, $array)) > 0
101
        ) {
102 1
            throw new \InvalidArgumentException('Property mismatch - input: ' . \print_r(\array_keys($array), true) . ' | expected: ' . \print_r(\array_keys($this->properties), true));
103
        }
104
105 888
        \array_walk(
106
            $array,
107 888
            function (&$value, &$key) {
108 776
                $this->internalSet($key, $value);
109 888
            }
110
        );
111
112 884
        $this->setIteratorClass($iteratorClass);
113 884
    }
114
115
    /**
116
     * Call object as function.
117
     *
118
     * @param mixed $key
119
     *
120
     * @return mixed
121
     */
122 1
    public function __invoke($key = null)
123
    {
124 1
        if ($key !== null) {
125 1
            return $this->array[$key] ?? false;
126
        }
127
128
        return (array) $this->array;
129
    }
130
131
    /**
132
     * Whether or not an element exists by key.
133
     *
134
     * @param mixed $key
135
     *
136
     * @return bool
137
     *              <p>True is the key/index exists, otherwise false.</p>
138
     */
139
    public function __isset($key): bool
140
    {
141
        return $this->offsetExists($key);
142
    }
143
144
    /**
145
     * Assigns a value to the specified element.
146
     *
147
     * @param mixed $key
148
     * @param mixed $value
149
     */
150 2
    public function __set($key, $value)
151
    {
152 2
        $this->internalSet($key, $value);
153 2
    }
154
155
    /**
156
     * magic to string
157
     *
158
     * @return string
159
     */
160 15
    public function __toString(): string
161
    {
162 15
        return $this->toString();
163
    }
164
165
    /**
166
     * Unset element by key.
167
     *
168
     * @param mixed $key
169
     */
170
    public function __unset($key)
171
    {
172
        $this->internalRemove($key);
173
    }
174
175
    /**
176
     * Get a value by key.
177
     *
178
     * @param mixed $key
179
     *
180
     * @return mixed
181
     *               <p>Get a Value from the current array.</p>
182
     */
183 4
    public function &__get($key)
184
    {
185 4
        $return = $this->get($key);
186
187 4
        if (\is_array($return)) {
188
            return static::create($return, $this->iteratorClass, false);
189
        }
190
191 4
        return $return;
192
    }
193
194
    /**
195
     * alias: for "Arrayy->append()"
196
     *
197
     * @param mixed $value
198
     *
199
     * @return static
200
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
201
     *
202
     * @see Arrayy::append()
203
     */
204 1
    public function add($value): self
205
    {
206 1
        return $this->append($value);
207
    }
208
209
    /**
210
     * Append a (key) + value to the current array.
211
     *
212
     * @param mixed $value
213
     * @param mixed $key
214
     *
215
     * @return static
216
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
217
     */
218 9
    public function append($value, $key = null): self
219
    {
220 9
        if ($key !== null) {
221
            if (
222
                isset($this->array[$key])
223
                &&
224
                \is_array($this->array[$key])
225
            ) {
226
                $this->array[$key][] = $value;
227
            } else {
228
                $this->array[$key] = $value;
229
            }
230
        } else {
231 9
            $this->array[] = $value;
232
        }
233
234 9
        return $this;
235
    }
236
237
    /**
238
     * Sort the entries by value.
239
     *
240
     * @param int $sort_flags [optional] <p>
241
     *                        You may modify the behavior of the sort using the optional
242
     *                        parameter sort_flags, for details
243
     *                        see sort.
244
     *                        </p>
245
     *
246
     * @return static
247
     *                <p>(Mutable) Return this Arrayy object.</p>
248
     */
249 4
    public function asort(int $sort_flags = 0): self
250
    {
251 4
        \asort($this->array, $sort_flags);
252
253 4
        return $this;
254
    }
255
256
    /**
257
     * Counts all elements in an array, or something in an object.
258
     *
259
     * <p>
260
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
261
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
262
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
263
     * implemented and used in PHP.
264
     * </p>
265
     *
266
     * @see http://php.net/manual/en/function.count.php
267
     *
268
     * @param int $mode [optional] If the optional mode parameter is set to
269
     *                  COUNT_RECURSIVE (or 1), count
270
     *                  will recursively count the array. This is particularly useful for
271
     *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
272
     *
273
     * @return int
274
     *             <p>
275
     *             The number of elements in var, which is
276
     *             typically an array, since anything else will have one
277
     *             element.
278
     *             </p>
279
     *             <p>
280
     *             If var is not an array or an object with
281
     *             implemented Countable interface,
282
     *             1 will be returned.
283
     *             There is one exception, if var is &null;,
284
     *             0 will be returned.
285
     *             </p>
286
     *             <p>
287
     *             Caution: count may return 0 for a variable that isn't set,
288
     *             but it may also return 0 for a variable that has been initialized with an
289
     *             empty array. Use isset to test if a variable is set.
290
     *             </p>
291
     */
292 38
    public function count(int $mode = \COUNT_NORMAL): int
293
    {
294 38
        return \count($this->array, $mode);
295
    }
296
297
    /**
298
     * Exchange the array for another one.
299
     *
300
     * @param array|static $data
301
     *
302
     * @return array
303
     */
304 1
    public function exchangeArray($data): array
305
    {
306 1
        $this->array = $this->fallbackForArray($data);
307
308 1
        return $this->array;
309
    }
310
311
    /**
312
     * Creates a copy of the ArrayyObject.
313
     *
314
     * @return array
315
     */
316 1
    public function getArrayCopy(): array
317
    {
318 1
        return $this->array;
319
    }
320
321
    /**
322
     * Returns a new ArrayyIterator, thus implementing the \ArrayIterator interface.
323
     *
324
     * @return \ArrayIterator
325
     *                        <p>An iterator for the values in the array.</p>
326
     */
327 12
    public function getIterator(): \ArrayIterator
328
    {
329 12
        $iterator = $this->getIteratorClass();
330
331 12
        return new $iterator($this->array);
332
    }
333
334
    /**
335
     * Gets the iterator classname for the ArrayObject.
336
     *
337
     * @return string
338
     */
339 12
    public function getIteratorClass(): string
340
    {
341 12
        return $this->iteratorClass;
342
    }
343
344
    /**
345
     * Sort the entries by key
346
     *
347
     * @param int $sort_flags [optional] <p>
348
     *                        You may modify the behavior of the sort using the optional
349
     *                        parameter sort_flags, for details
350
     *                        see sort.
351
     *                        </p>
352
     *
353
     * @return static
354
     *                <p>(Mutable) Return this Arrayy object.</p>
355
     */
356 4
    public function ksort(int $sort_flags = 0): self
357
    {
358 4
        \ksort($this->array, $sort_flags);
359
360 4
        return $this;
361
    }
362
363
    /**
364
     * Sort an array using a case insensitive "natural order" algorithm
365
     *
366
     * @return static
367
     *                <p>(Mutable) Return this Arrayy object.</p>
368
     */
369
    public function natcasesort(): self
370
    {
371
        \natcasesort($this->array);
372
373
        return $this;
374
    }
375
376
    /**
377
     * Sort entries using a "natural order" algorithm
378
     *
379
     * @return static
380
     *                <p>(Mutable) Return this Arrayy object.</p>
381
     */
382 1
    public function natsort(): self
383
    {
384 1
        \natsort($this->array);
385
386 1
        return $this;
387
    }
388
389
    /**
390
     * Whether or not an offset exists.
391
     *
392
     * @param bool|float|int|string $offset
393
     *
394
     * @return bool
395
     */
396 44
    public function offsetExists($offset): bool
397
    {
398 44
        if ($this->isEmpty()) {
399 4
            return false;
400
        }
401
402
        // php cast "bool"-index into "int"-index
403 40
        if ((bool) $offset === $offset) {
404 1
            $offset = (int) $offset;
405
        }
406
407 40
        $tmpReturn = \array_key_exists($offset, $this->array);
408
409
        if (
410 40
            $tmpReturn === true
411
            ||
412
            (
413 16
                $tmpReturn === false
414
                &&
415 40
                \strpos((string) $offset, $this->pathSeparator) === false
416
            )
417
        ) {
418 38
            return $tmpReturn;
419
        }
420
421 3
        $offsetExists = false;
422
423 3
        if (\strpos((string) $offset, $this->pathSeparator) !== false) {
424 3
            $offsetExists = false;
425 3
            $explodedPath = \explode($this->pathSeparator, (string) $offset);
426 3
            $lastOffset = \array_pop($explodedPath);
427 3
            $containerPath = \implode($this->pathSeparator, $explodedPath);
428
429 3
            $this->callAtPath(
430 3
                $containerPath,
431 3
                static function ($container) use ($lastOffset, &$offsetExists) {
432 3
                    $offsetExists = \array_key_exists($lastOffset, $container);
433 3
                }
434
            );
435
        }
436
437 3
        return $offsetExists;
438
    }
439
440
    /**
441
     * Returns the value at specified offset.
442
     *
443
     * @param float|int|string $offset
444
     *
445
     * @return mixed
446
     *               <p>Will return null if the offset did not exists.</p>
447
     */
448 30
    public function offsetGet($offset)
449
    {
450 30
        return $this->offsetExists($offset) ? $this->get($offset) : null;
451
    }
452
453
    /**
454
     * Assigns a value to the specified offset.
455
     *
456
     * @param int|string|null $offset
457
     * @param mixed           $value
458
     */
459 20
    public function offsetSet($offset, $value)
460
    {
461 20
        if ($offset === null) {
462 4
            $this->array[] = $value;
463
        } else {
464 16
            $this->internalSet($offset, $value);
465
        }
466 20
    }
467
468
    /**
469
     * Unset an offset.
470
     *
471
     * @param float|int|string $offset
472
     */
473 7
    public function offsetUnset($offset)
474
    {
475 7
        if ($this->isEmpty()) {
476 1
            return;
477
        }
478
479 6
        if (\array_key_exists($offset, $this->array)) {
480 4
            unset($this->array[$offset]);
481
482 4
            return;
483
        }
484
485 3
        if (\strpos((string) $offset, $this->pathSeparator) !== false) {
486 2
            $path = \explode($this->pathSeparator, (string) $offset);
487 2
            $pathToUnset = \array_pop($path);
488
489 2
            $this->callAtPath(
490 2
                \implode($this->pathSeparator, $path),
491 2
                static function (&$offset) use ($pathToUnset) {
492 2
                    unset($offset[$pathToUnset]);
493 2
                }
494
            );
495
        }
496 3
    }
497
498
    /** @noinspection SenselessProxyMethodInspection | can not add return type, because of the "Serializable" interface */
499
500
    /**
501
     * Serialize the current "Arrayy"-object.
502
     *
503
     * @return string
504
     */
505 2
    public function serialize(): string
506
    {
507 2
        return parent::serialize();
508
    }
509
510
    /**
511
     * Sets the iterator classname for the current "Arrayy"-object.
512
     *
513
     * @param string $class
514
     *
515
     * @throws \InvalidArgumentException
516
     */
517 884
    public function setIteratorClass($class)
518
    {
519 884
        if (\class_exists($class)) {
520 884
            $this->iteratorClass = $class;
521
522 884
            return;
523
        }
524
525
        if (\strpos($class, '\\') === 0) {
526
            $class = '\\' . $class;
527
            if (\class_exists($class)) {
528
                $this->iteratorClass = $class;
529
530
                return;
531
            }
532
        }
533
534
        throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
535
    }
536
537
    /**
538
     * Sort the entries with a user-defined comparison function and maintain key association.
539
     *
540
     * @param \callable $function
541
     *
542
     * @throws \InvalidArgumentException
543
     *
544
     * @return static
545
     *                <p>(Mutable) Return this Arrayy object.</p>
546
     */
547 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...
548
    {
549
        if (!\is_callable($function)) {
550
            throw new \InvalidArgumentException(
551
                'Passed function must be callable'
552
            );
553
        }
554
555
        \uasort($this->array, $function);
556
557
        return $this;
558
    }
559
560
    /**
561
     * Sort the entries by keys using a user-defined comparison function.
562
     *
563
     * @param \callable $function
564
     *
565
     * @throws \InvalidArgumentException
566
     *
567
     * @return static
568
     *                <p>(Mutable) Return this Arrayy object.</p>
569
     */
570 5
    public function uksort($function): self
571
    {
572 5
        return $this->customSortKeys($function);
573
    }
574
575
    /**
576
     * Unserialize an string and return the instance of the "Arrayy"-class.
577
     *
578
     * @param string $string
579
     *
580
     * @return static
581
     */
582 2
    public function unserialize($string): self
583
    {
584 2
        parent::unserialize($string);
585
586 2
        return $this;
587
    }
588
589
    /**
590
     * Append a (key) + values to the current array.
591
     *
592
     * @param array $values
593
     * @param mixed $key
594
     *
595
     * @return static
596
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
597
     */
598 1
    public function appendArrayValues(array $values, $key = null): self
599
    {
600 1
        if ($key !== null) {
601
            if (
602 1
                isset($this->array[$key])
603
                &&
604 1
                \is_array($this->array[$key])
605
            ) {
606 1
                foreach ($values as $value) {
607 1
                    $this->array[$key][] = $value;
608
                }
609
            } else {
610
                foreach ($values as $value) {
611 1
                    $this->array[$key] = $value;
612
                }
613
            }
614
        } else {
615
            foreach ($values as $value) {
616
                $this->array[] = $value;
617
            }
618
        }
619
620 1
        return $this;
621
    }
622
623
    /**
624
     * Add a suffix to each key.
625
     *
626
     * @param mixed $prefix
627
     *
628
     * @return static
629
     *                <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
630
     */
631 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...
632
    {
633
        // init
634 10
        $result = [];
635
636 10
        foreach ($this->getGenerator() as $key => $item) {
637 9
            if ($item instanceof self) {
638
                $result[$prefix . $key] = $item->appendToEachKey($prefix);
639 9
            } elseif (\is_array($item)) {
640
                $result[$prefix . $key] = self::create($item, $this->iteratorClass, false)
641
                    ->appendToEachKey($prefix)
642
                    ->toArray();
643
            } else {
644 9
                $result[$prefix . $key] = $item;
645
            }
646
        }
647
648 10
        return self::create($result, $this->iteratorClass, false);
649
    }
650
651
    /**
652
     * Add a prefix to each value.
653
     *
654
     * @param mixed $prefix
655
     *
656
     * @return static
657
     *                <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
658
     */
659 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...
660
    {
661
        // init
662 10
        $result = [];
663
664 10
        foreach ($this->getGenerator() as $key => $item) {
665 9
            if ($item instanceof self) {
666
                $result[$key] = $item->appendToEachValue($prefix);
667 9
            } elseif (\is_array($item)) {
668
                $result[$key] = self::create($item, $this->iteratorClass, false)->appendToEachValue($prefix)->toArray();
669 9
            } elseif (\is_object($item)) {
670 1
                $result[$key] = $item;
671
            } else {
672 9
                $result[$key] = $prefix . $item;
673
            }
674
        }
675
676 10
        return self::create($result, $this->iteratorClass, false);
677
    }
678
679
    /**
680
     * Sort an array in reverse order and maintain index association.
681
     *
682
     * @return static
683
     *                <p>(Mutable) Return this Arrayy object.</p>
684
     */
685 4
    public function arsort(): self
686
    {
687 4
        \arsort($this->array);
688
689 4
        return $this;
690
    }
691
692
    /**
693
     * Iterate over the current array and execute a callback for each loop.
694
     *
695
     * @param \Closure $closure
696
     *
697
     * @return static
698
     *                <p>(Immutable)</p>
699
     */
700 2
    public function at(\Closure $closure): self
701
    {
702 2
        $arrayy = clone $this;
703
704 2
        foreach ($arrayy->getGenerator() as $key => $value) {
705 2
            $closure($value, $key);
706
        }
707
708 2
        return static::create(
709 2
            $arrayy->toArray(),
710 2
            $this->iteratorClass,
711 2
            false
712
        );
713
    }
714
715
    /**
716
     * Returns the average value of the current array.
717
     *
718
     * @param int $decimals <p>The number of decimal-numbers to return.</p>
719
     *
720
     * @return float|int
721
     *                   <p>The average value.</p>
722
     */
723 10
    public function average($decimals = 0)
724
    {
725 10
        $count = \count($this->array, \COUNT_NORMAL);
726
727 10
        if (!$count) {
728 2
            return 0;
729
        }
730
731 8
        if (!\is_int($decimals)) {
732 3
            $decimals = 0;
733
        }
734
735 8
        return \round(\array_sum($this->array) / $count, $decimals);
736
    }
737
738
    /**
739
     * Changes all keys in an array.
740
     *
741
     * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
742
     *                  or <strong>CASE_LOWER</strong> (default)</p>
743
     *
744
     * @return static
745
     *                <p>(Immutable)</p>
746
     */
747 1
    public function changeKeyCase(int $case = \CASE_LOWER): self
748
    {
749
        if (
750 1
            $case !== \CASE_LOWER
751
            &&
752 1
            $case !== \CASE_UPPER
753
        ) {
754
            $case = \CASE_LOWER;
755
        }
756
757 1
        $return = [];
758 1
        foreach ($this->array as $key => $value) {
759 1
            if ($case === \CASE_LOWER) {
760
                /** @noinspection PhpComposerExtensionStubsInspection */
761 1
                $key = \mb_strtolower((string) $key);
762
            } else {
763
                /** @noinspection PhpComposerExtensionStubsInspection */
764 1
                $key = \mb_strtoupper((string) $key);
765
            }
766
767 1
            $return[$key] = $value;
768
        }
769
770 1
        return static::create(
771 1
            $return,
772 1
            $this->iteratorClass,
773 1
            false
774
        );
775
    }
776
777
    /**
778
     * Change the path separator of the array wrapper.
779
     *
780
     * By default, the separator is: "."
781
     *
782
     * @param string $separator <p>Separator to set.</p>
783
     *
784
     * @return static
785
     *                <p>Mutable</p>
786
     */
787 1
    public function changeSeparator($separator): self
788
    {
789 1
        $this->pathSeparator = $separator;
790
791 1
        return $this;
792
    }
793
794
    /**
795
     * Create a chunked version of the current array.
796
     *
797
     * @param int  $size         <p>Size of each chunk.</p>
798
     * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
799
     *
800
     * @return static
801
     *                <p>(Immutable) A new array of chunks from the original array.</p>
802
     */
803 4
    public function chunk($size, $preserveKeys = false): self
804
    {
805 4
        return static::create(
806 4
            \array_chunk($this->array, $size, $preserveKeys),
807 4
            $this->iteratorClass,
808 4
            false
809
        );
810
    }
811
812
    /**
813
     * Clean all falsy values from the current array.
814
     *
815
     * @return static
816
     *                <p>(Immutable)</p>
817
     */
818 8
    public function clean(): self
819
    {
820 8
        return $this->filter(
821 8
            static function ($value) {
822 7
                return (bool) $value;
823 8
            }
824
        );
825
    }
826
827
    /**
828
     * WARNING!!! -> Clear the current array.
829
     *
830
     * @return static
831
     *                <p>(Mutable) Return this Arrayy object, with an empty array.</p>
832
     */
833 4
    public function clear(): self
834
    {
835 4
        $this->array = [];
836
837 4
        return $this;
838
    }
839
840
    /**
841
     * Check if an item is in the current array.
842
     *
843
     * @param float|int|string $value
844
     * @param bool             $recursive
845
     * @param bool             $strict
846
     *
847
     * @return bool
848
     */
849 22
    public function contains($value, $recursive = false, $strict = true): bool
850
    {
851 22
        if ($recursive === true) {
852 18
            return $this->in_array_recursive($value, $this->array, $strict);
853
        }
854
855 13
        return \in_array($value, $this->array, $strict);
856
    }
857
858
    /**
859
     * Check if an (case-insensitive) string is in the current array.
860
     *
861
     * @param string $value
862
     * @param bool   $recursive
863
     *
864
     * @return bool
865
     */
866 26
    public function containsCaseInsensitive($value, $recursive = false): bool
867
    {
868 26
        if ($recursive === true) {
869
            /** @noinspection PhpComposerExtensionStubsInspection */
870 26
            return $this->in_array_recursive(
871 26
                \mb_strtoupper((string) $value),
872 26
                $this->walk(
873 26
                    static function (&$val) {
874
                        /** @noinspection PhpComposerExtensionStubsInspection */
875 22
                        $val = \mb_strtoupper((string) $val);
876 26
                    },
877 26
                    true
878 26
                )->getArray(),
879 26
                true
880
            );
881
        }
882
883
        /** @noinspection PhpComposerExtensionStubsInspection */
884 13
        return \in_array(
885 13
            \mb_strtoupper((string) $value),
886 13
            $this->walk(
887 13
                static function (&$val) {
888
                    /** @noinspection PhpComposerExtensionStubsInspection */
889 11
                    $val = \mb_strtoupper((string) $val);
890 13
                },
891 13
                false
892 13
            )->getArray(),
893 13
            true
894
        );
895
    }
896
897
    /**
898
     * Check if the given key/index exists in the array.
899
     *
900
     * @param float|int|string $key <p>key/index to search for</p>
901
     *
902
     * @return bool
903
     *              <p>Returns true if the given key/index exists in the array, false otherwise.</p>
904
     */
905 4
    public function containsKey($key): bool
906
    {
907 4
        return $this->offsetExists($key);
908
    }
909
910
    /**
911
     * Check if all given needles are present in the array as key/index.
912
     *
913
     * @param array $needles   <p>The keys you are searching for.</p>
914
     * @param bool  $recursive
915
     *
916
     * @return bool
917
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
918
     */
919 2
    public function containsKeys(array $needles, $recursive = false): bool
920
    {
921 2
        if ($recursive === true) {
922 2
            return \count(
923 2
                       \array_intersect($needles, $this->keys(true)->getArray()),
924 2
                       \COUNT_RECURSIVE
925
                   )
926
                   ===
927 2
                   \count(
928 2
                       $needles,
929 2
                       \COUNT_RECURSIVE
930
                   );
931
        }
932
933 1
        return \count(
934 1
                   \array_intersect($needles, $this->keys()->getArray()),
935 1
                   \COUNT_NORMAL
936
               )
937
               ===
938 1
               \count(
939 1
                   $needles,
940 1
                   \COUNT_NORMAL
941
               );
942
    }
943
944
    /**
945
     * Check if all given needles are present in the array as key/index.
946
     *
947
     * @param array $needles <p>The keys you are searching for.</p>
948
     *
949
     * @return bool
950
     *              <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
951
     */
952 1
    public function containsKeysRecursive(array $needles): bool
953
    {
954 1
        return $this->containsKeys($needles, true);
955
    }
956
957
    /**
958
     * alias: for "Arrayy->contains()"
959
     *
960
     * @param float|int|string $value
961
     *
962
     * @return bool
963
     *
964
     * @see Arrayy::contains()
965
     */
966 9
    public function containsValue($value): bool
967
    {
968 9
        return $this->contains($value);
969
    }
970
971
    /**
972
     * alias: for "Arrayy->contains($value, true)"
973
     *
974
     * @param float|int|string $value
975
     *
976
     * @return bool
977
     *
978
     * @see Arrayy::contains()
979
     */
980 18
    public function containsValueRecursive($value): bool
981
    {
982 18
        return $this->contains($value, true);
983
    }
984
985
    /**
986
     * Check if all given needles are present in the array.
987
     *
988
     * @param array $needles
989
     *
990
     * @return bool
991
     *              <p>Returns true if all the given values exists in the array, false otherwise.</p>
992
     */
993 1
    public function containsValues(array $needles): bool
994
    {
995 1
        return \count(\array_intersect($needles, $this->array), \COUNT_NORMAL)
996
               ===
997 1
               \count($needles, \COUNT_NORMAL);
998
    }
999
1000
    /**
1001
     * Counts all the values of an array
1002
     *
1003
     * @see http://php.net/manual/en/function.array-count-values.php
1004
     *
1005
     * @return static
1006
     *                <p>
1007
     *                (Immutable)
1008
     *                An associative Arrayy-object of values from input as
1009
     *                keys and their count as value.
1010
     *                </p>
1011
     */
1012 1
    public function countValues(): self
1013
    {
1014 1
        return new static(\array_count_values($this->array));
1015
    }
1016
1017
    /**
1018
     * Creates an Arrayy object.
1019
     *
1020
     * @param mixed  $array
1021
     * @param string $iteratorClass
1022
     * @param bool   $checkForMissingPropertiesInConstructor
1023
     *
1024
     * @return static
1025
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1026
     */
1027 535
    public static function create($array = [], string $iteratorClass = ArrayyIterator::class, bool $checkForMissingPropertiesInConstructor = true): self
1028
    {
1029 535
        return new static($array, $iteratorClass, $checkForMissingPropertiesInConstructor);
1030
    }
1031
1032
    /**
1033
     * WARNING: Creates an Arrayy object by reference.
1034
     *
1035
     * @param array $array
1036
     *
1037
     * @return static
1038
     *                <p>(Mutable) Return this Arrayy object.</p>
1039
     */
1040 1
    public function createByReference(array &$array = []): self
1041
    {
1042 1
        $array = $this->fallbackForArray($array);
1043
1044 1
        $this->array = &$array;
1045
1046 1
        return $this;
1047
    }
1048
1049
    /**
1050
     * Create an new instance filled with a copy of values from a "Generator"-object.
1051
     *
1052
     * @param \Generator $generator
1053
     *
1054
     * @return static
1055
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1056
     */
1057 4
    public static function createFromGeneratorImmutable(\Generator $generator): self
1058
    {
1059
        // init
1060 4
        $array = new static();
1061
1062 4
        foreach ($generator as $key => $value) {
1063 3
            $array[$key] = $value;
1064
        }
1065
1066 4
        return $array;
1067
    }
1068
1069
    /**
1070
     * Create an new Arrayy object via JSON.
1071
     *
1072
     * @param string $json
1073
     *
1074
     * @return static
1075
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1076
     */
1077 5
    public static function createFromJson(string $json): self
1078
    {
1079
        /** @noinspection PhpComposerExtensionStubsInspection */
1080 5
        return static::create(\json_decode($json, true));
1081
    }
1082
1083
    /**
1084
     * Create an new instance filled with values from an object that have implemented ArrayAccess.
1085
     *
1086
     * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
1087
     *
1088
     * @return static
1089
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1090
     */
1091 4
    public static function createFromObject(\ArrayAccess $object): self
1092
    {
1093
        // init
1094 4
        $array = new static();
1095
1096 4
        if ($object instanceof self) {
1097 4
            $objectArray = $object->getGenerator();
1098
        } else {
1099
            $objectArray = $object;
1100
        }
1101
1102 4
        foreach ($objectArray as $key => $value) {
1103 3
            $array[$key] = $value;
1104
        }
1105
1106 4
        return $array;
1107
    }
1108
1109
    /**
1110
     * Create an new instance filled with values from an object.
1111
     *
1112
     * @param object $object
1113
     *
1114
     * @return static
1115
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1116
     */
1117 5
    public static function createFromObjectVars($object): self
1118
    {
1119 5
        return new static(self::objectToArray($object));
1120
    }
1121
1122
    /**
1123
     * Create an new Arrayy object via string.
1124
     *
1125
     * @param string      $str       <p>The input string.</p>
1126
     * @param string|null $delimiter <p>The boundary string.</p>
1127
     * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
1128
     *                               used.</p>
1129
     *
1130
     * @return static
1131
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1132
     */
1133 8
    public static function createFromString(string $str, string $delimiter = null, string $regEx = null): self
1134
    {
1135 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...
1136 1
            \preg_match_all($regEx, $str, $array);
1137
1138 1
            if (!empty($array)) {
1139 1
                $array = $array[0];
1140
            }
1141
        } else {
1142 7
            $array = \explode($delimiter, $str);
1143
        }
1144
1145
        // trim all string in the array
1146 8
        \array_walk(
1147
            $array,
1148 8
            static function (&$val) {
1149 8
                if (\is_string($val)) {
1150 8
                    $val = \trim($val);
1151
                }
1152 8
            }
1153
        );
1154
1155 8
        return static::create($array);
1156
    }
1157
1158
    /**
1159
     * Create an new instance containing a range of elements.
1160
     *
1161
     * @param mixed $low  <p>First value of the sequence.</p>
1162
     * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1163
     * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1164
     *
1165
     * @return static
1166
     *                <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1167
     */
1168 1
    public static function createWithRange($low, $high, int $step = 1): self
1169
    {
1170 1
        return static::create(\range($low, $high, $step));
1171
    }
1172
1173
    /**
1174
     * Custom sort by index via "uksort".
1175
     *
1176
     * @see http://php.net/manual/en/function.uksort.php
1177
     *
1178
     * @param \callable $function
1179
     *
1180
     * @throws \InvalidArgumentException
1181
     *
1182
     * @return static
1183
     *                <p>(Mutable) Return this Arrayy object.</p>
1184
     */
1185 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...
1186
    {
1187 5
        if (!\is_callable($function)) {
1188
            throw new \InvalidArgumentException(
1189
                'Passed function must be callable'
1190
            );
1191
        }
1192
1193 5
        \uksort($this->array, $function);
1194
1195 5
        return $this;
1196
    }
1197
1198
    /**
1199
     * Custom sort by value via "usort".
1200
     *
1201
     * @see http://php.net/manual/en/function.usort.php
1202
     *
1203
     * @param \callable $function
1204
     *
1205
     * @throws \InvalidArgumentException
1206
     *
1207
     * @return static
1208
     *                <p>(Mutable) Return this Arrayy object.</p>
1209
     */
1210 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...
1211
    {
1212 5
        if (!\is_callable($function)) {
1213
            throw new \InvalidArgumentException(
1214
                'Passed function must be callable'
1215
            );
1216
        }
1217
1218 5
        \usort($this->array, $function);
1219
1220 5
        return $this;
1221
    }
1222
1223
    /**
1224
     * Return values that are only in the current array.
1225
     *
1226
     * @param array $array
1227
     *
1228
     * @return static
1229
     *                <p>(Immutable)</p>
1230
     */
1231 12
    public function diff(array $array = []): self
1232
    {
1233 12
        $result = \array_diff($this->array, $array);
1234
1235 12
        return static::create($result, $this->iteratorClass, false);
1236
    }
1237
1238
    /**
1239
     * Return values that are only in the current multi-dimensional array.
1240
     *
1241
     * @param array      $array
1242
     * @param array|null $helperVariableForRecursion <p>(only for internal usage)</p>
1243
     *
1244
     * @return static
1245
     *                <p>(Immutable)</p>
1246
     */
1247 1
    public function diffRecursive(array $array = [], $helperVariableForRecursion = null): self
1248
    {
1249
        // init
1250 1
        $result = [];
1251
1252
        if (
1253 1
            $helperVariableForRecursion !== null
1254
            &&
1255 1
            \is_array($helperVariableForRecursion)
1256
        ) {
1257
            $arrayForTheLoop = $helperVariableForRecursion;
1258
        } else {
1259 1
            $arrayForTheLoop = $this->getGenerator();
1260
        }
1261
1262 1
        foreach ($arrayForTheLoop as $key => $value) {
1263 1
            if ($value instanceof self) {
1264
                $value = $value->getArray();
1265
            }
1266
1267 1
            if (\array_key_exists($key, $array)) {
1268 1
                if ($value !== $array[$key]) {
1269 1
                    $result[$key] = $value;
1270
                }
1271
            } else {
1272 1
                $result[$key] = $value;
1273
            }
1274
        }
1275
1276 1
        return static::create($result, $this->iteratorClass, false);
1277
    }
1278
1279
    /**
1280
     * Return values that are only in the new $array.
1281
     *
1282
     * @param array $array
1283
     *
1284
     * @return static
1285
     *                <p>(Immutable)</p>
1286
     */
1287 8
    public function diffReverse(array $array = []): self
1288
    {
1289 8
        return static::create(
1290 8
            \array_diff($array, $this->array),
1291 8
            $this->iteratorClass,
1292 8
            false
1293
        );
1294
    }
1295
1296
    /**
1297
     * Divide an array into two arrays. One with keys and the other with values.
1298
     *
1299
     * @return static
1300
     *                <p>(Immutable)</p>
1301
     */
1302 1
    public function divide(): self
1303
    {
1304 1
        return static::create(
1305
            [
1306 1
                $this->keys(),
1307 1
                $this->values(),
1308
            ],
1309 1
            $this->iteratorClass,
1310 1
            false
1311
        );
1312
    }
1313
1314
    /**
1315
     * Iterate over the current array and modify the array's value.
1316
     *
1317
     * @param \Closure $closure
1318
     *
1319
     * @return static
1320
     *                <p>(Immutable)</p>
1321
     */
1322 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...
1323
    {
1324
        // init
1325 4
        $array = [];
1326
1327 4
        foreach ($this->getGenerator() as $key => $value) {
1328 4
            $array[$key] = $closure($value, $key);
1329
        }
1330
1331 4
        return static::create($array, $this->iteratorClass, false);
1332
    }
1333
1334
    /**
1335
     * Check if a value is in the current array using a closure.
1336
     *
1337
     * @param \Closure $closure
1338
     *
1339
     * @return bool
1340
     *              <p>Returns true if the given value is found, false otherwise.</p>
1341
     */
1342 4
    public function exists(\Closure $closure): bool
1343
    {
1344
        // init
1345 4
        $isExists = false;
1346
1347 4
        foreach ($this->getGenerator() as $key => $value) {
1348 3
            if ($closure($value, $key)) {
1349 1
                $isExists = true;
1350
1351 3
                break;
1352
            }
1353
        }
1354
1355 4
        return $isExists;
1356
    }
1357
1358
    /**
1359
     * Fill the array until "$num" with "$default" values.
1360
     *
1361
     * @param int   $num
1362
     * @param mixed $default
1363
     *
1364
     * @return static
1365
     *                <p>(Immutable)</p>
1366
     */
1367 8
    public function fillWithDefaults(int $num, $default = null): self
1368
    {
1369 8
        if ($num < 0) {
1370 1
            throw new \InvalidArgumentException('The $num parameter can only contain non-negative values.');
1371
        }
1372
1373 7
        $tmpArray = $this->array;
1374
1375 7
        $count = \count($tmpArray);
1376
1377 7
        while ($count < $num) {
1378 4
            $tmpArray[] = $default;
1379 4
            ++$count;
1380
        }
1381
1382 7
        return static::create($tmpArray, $this->iteratorClass, false);
1383
    }
1384
1385
    /**
1386
     * Find all items in an array that pass the truth test.
1387
     *
1388
     * @param \Closure|null $closure [optional] <p>
1389
     *                               The callback function to use
1390
     *                               </p>
1391
     *                               <p>
1392
     *                               If no callback is supplied, all entries of
1393
     *                               input equal to false (see
1394
     *                               converting to
1395
     *                               boolean) will be removed.
1396
     *                               </p>
1397
     *                               * @param int $flag [optional] <p>
1398
     *                               Flag determining what arguments are sent to <i>callback</i>:
1399
     *                               </p><ul>
1400
     *                               <li>
1401
     *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1402
     *                               to <i>callback</i> instead of the value</span>
1403
     *                               </li>
1404
     *                               <li>
1405
     *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1406
     *                               arguments to <i>callback</i> instead of the value</span>
1407
     *                               </li>
1408
     *                               </ul>
1409
     *
1410
     * @return static
1411
     *                <p>(Immutable)</p>
1412
     */
1413 10
    public function filter($closure = null, int $flag = \ARRAY_FILTER_USE_BOTH): self
1414
    {
1415 10
        if (!$closure) {
1416 1
            return $this->clean();
1417
        }
1418
1419 10
        return static::create(
1420 10
            \array_filter($this->array, $closure, $flag),
1421 10
            $this->iteratorClass,
1422 10
            false
1423
        );
1424
    }
1425
1426
    /**
1427
     * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular
1428
     * property within that.
1429
     *
1430
     * @param string          $property
1431
     * @param string|string[] $value
1432
     * @param string          $comparisonOp
1433
     *                                      <p>
1434
     *                                      'eq' (equals),<br />
1435
     *                                      'gt' (greater),<br />
1436
     *                                      'gte' || 'ge' (greater or equals),<br />
1437
     *                                      'lt' (less),<br />
1438
     *                                      'lte' || 'le' (less or equals),<br />
1439
     *                                      'ne' (not equals),<br />
1440
     *                                      'contains',<br />
1441
     *                                      'notContains',<br />
1442
     *                                      'newer' (via strtotime),<br />
1443
     *                                      'older' (via strtotime),<br />
1444
     *                                      </p>
1445
     *
1446
     * @return static
1447
     *                <p>(Immutable)</p>
1448
     */
1449 1
    public function filterBy(string $property, $value, string $comparisonOp = null): self
1450
    {
1451 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...
1452 1
            $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1453
        }
1454
1455
        $ops = [
1456 1
            'eq' => static function ($item, $prop, $value) {
1457 1
                return $item[$prop] === $value;
1458 1
            },
1459 1
            'gt' => static function ($item, $prop, $value) {
1460
                return $item[$prop] > $value;
1461 1
            },
1462 1
            'ge' => static function ($item, $prop, $value) {
1463
                return $item[$prop] >= $value;
1464 1
            },
1465 1
            'gte' => static function ($item, $prop, $value) {
1466
                return $item[$prop] >= $value;
1467 1
            },
1468 1
            'lt' => static function ($item, $prop, $value) {
1469 1
                return $item[$prop] < $value;
1470 1
            },
1471 1
            'le' => static function ($item, $prop, $value) {
1472
                return $item[$prop] <= $value;
1473 1
            },
1474 1
            'lte' => static function ($item, $prop, $value) {
1475
                return $item[$prop] <= $value;
1476 1
            },
1477 1
            'ne' => static function ($item, $prop, $value) {
1478
                return $item[$prop] !== $value;
1479 1
            },
1480 1
            'contains' => static function ($item, $prop, $value) {
1481 1
                return \in_array($item[$prop], (array) $value, true);
1482 1
            },
1483 1
            'notContains' => static function ($item, $prop, $value) {
1484
                return !\in_array($item[$prop], (array) $value, true);
1485 1
            },
1486 1
            'newer' => static function ($item, $prop, $value) {
1487
                return \strtotime($item[$prop]) > \strtotime($value);
1488 1
            },
1489 1
            'older' => static function ($item, $prop, $value) {
1490
                return \strtotime($item[$prop]) < \strtotime($value);
1491 1
            },
1492
        ];
1493
1494 1
        $result = \array_values(
1495 1
            \array_filter(
1496 1
                (array) $this->array,
1497 1
                static function ($item) use (
1498 1
                    $property,
1499 1
                    $value,
1500 1
                    $ops,
1501 1
                    $comparisonOp
1502
                ) {
1503 1
                    $item = (array) $item;
1504 1
                    $itemArrayy = new self($item);
1505 1
                    $item[$property] = $itemArrayy->get($property, []);
1506
1507 1
                    return $ops[$comparisonOp]($item, $property, $value);
1508 1
                }
1509
            )
1510
        );
1511
1512 1
        return static::create($result, $this->iteratorClass, false);
1513
    }
1514
1515
    /**
1516
     * Find the first item in an array that passes the truth test,
1517
     *  otherwise return false
1518
     *
1519
     * @param \Closure $closure
1520
     *
1521
     * @return false|mixed
1522
     *                     <p>Return false if we did not find the value.</p>
1523
     */
1524 8
    public function find(\Closure $closure)
1525
    {
1526 8
        foreach ($this->getGenerator() as $key => $value) {
1527 6
            if ($closure($value, $key)) {
1528 6
                return $value;
1529
            }
1530
        }
1531
1532 3
        return false;
1533
    }
1534
1535
    /**
1536
     * find by ...
1537
     *
1538
     * @param string          $property
1539
     * @param string|string[] $value
1540
     * @param string          $comparisonOp
1541
     *
1542
     * @return static
1543
     *                <p>(Immutable)</p>
1544
     */
1545
    public function findBy(string $property, $value, string $comparisonOp = 'eq'): self
1546
    {
1547
        return $this->filterBy($property, $value, $comparisonOp);
1548
    }
1549
1550
    /**
1551
     * Get the first value from the current array.
1552
     *
1553
     * @return mixed
1554
     *               <p>Return null if there wasn't a element.</p>
1555
     */
1556 13
    public function first()
1557
    {
1558 13
        $tmpArray = $this->array;
1559
1560 13
        return \array_shift($tmpArray);
1561
    }
1562
1563
    /**
1564
     * Get the first value(s) from the current array.
1565
     *
1566
     * @param int|null $number <p>How many values you will take?</p>
1567
     *
1568
     * @return static
1569
     *                <p>(Immutable)</p>
1570
     */
1571 29 View Code Duplication
    public function firstsImmutable(int $number = null): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1572
    {
1573 29
        if ($number === null) {
1574 7
            $arrayTmp = $this->array;
1575 7
            $array = (array) \array_shift($arrayTmp);
1576
        } else {
1577 22
            $number = (int) $number;
1578 22
            $arrayTmp = $this->array;
1579 22
            $array = \array_splice($arrayTmp, 0, $number);
1580
        }
1581
1582 29
        return static::create($array, $this->iteratorClass, false);
1583
    }
1584
1585
    /**
1586
     * Get the first value(s) from the current array.
1587
     *
1588
     * @param int|null $number <p>How many values you will take?</p>
1589
     *
1590
     * @return static
1591
     *                <p>(Mutable)</p>
1592
     */
1593 26
    public function firstsMutable(int $number = null): self
1594
    {
1595 26
        if ($number === null) {
1596 11
            $this->array = (array) \array_shift($this->array);
1597
        } else {
1598 15
            $number = (int) $number;
1599 15
            $this->array = \array_splice($this->array, 0, $number);
1600
        }
1601
1602 26
        return $this;
1603
    }
1604
1605
    /**
1606
     * Exchanges all keys with their associated values in an array.
1607
     *
1608
     * @return static
1609
     *                <p>(Immutable)</p>
1610
     */
1611 1
    public function flip(): self
1612
    {
1613 1
        return static::create(
1614 1
            \array_flip($this->array),
1615 1
            $this->iteratorClass,
1616 1
            false
1617
        );
1618
    }
1619
1620
    /**
1621
     * Get a value from an array (optional using dot-notation).
1622
     *
1623
     * @param mixed $key      <p>The key to look for.</p>
1624
     * @param mixed $fallback <p>Value to fallback to.</p>
1625
     * @param array $array    <p>The array to get from, if it's set to "null" we use the current array from the
1626
     *                        class.</p>
1627
     *
1628
     * @return mixed|static
1629
     */
1630 68
    public function get($key, $fallback = null, array $array = null)
1631
    {
1632 68
        if ($array !== null) {
1633 4
            $usedArray = $array;
1634
        } else {
1635 64
            $usedArray = $this->array;
1636
        }
1637
1638 68
        if ($key === null) {
1639 1
            return static::create($usedArray, $this->iteratorClass, false);
1640
        }
1641
1642
        // php cast "bool"-index into "int"-index
1643 68
        if ((bool) $key === $key) {
1644 3
            $key = (int) $key;
1645
        }
1646
1647 68
        if (\array_key_exists($key, $usedArray) === true) {
1648 58
            if (\is_array($usedArray[$key])) {
1649 8
                return static::create($usedArray[$key], $this->iteratorClass, false);
1650
            }
1651
1652 52
            return $usedArray[$key];
1653
        }
1654
1655
        // Crawl through array, get key according to object or not
1656 22
        foreach (\explode($this->pathSeparator, (string) $key) as $segment) {
1657 22
            if (!isset($usedArray[$segment])) {
1658 21
                return $fallback instanceof \Closure ? $fallback() : $fallback;
1659
            }
1660
1661 6
            $usedArray = $usedArray[$segment];
1662
        }
1663
1664 6
        if (\is_array($usedArray)) {
1665 1
            return static::create($usedArray, $this->iteratorClass, false);
1666
        }
1667
1668 6
        return $usedArray;
1669
    }
1670
1671
    /**
1672
     * Get the current array from the "Arrayy"-object.
1673
     *
1674
     * @return array
1675
     */
1676 581
    public function getArray(): array
1677
    {
1678
        // init
1679 581
        $array = [];
1680
1681 581
        foreach ($this->array as $key => &$value) {
1682 478
            if ($value instanceof self) {
1683
                $array[$key] = $value->getArray();
1684
            } else {
1685 478
                $array[$key] = $value;
1686
            }
1687
        }
1688
1689 581
        return $array;
1690
    }
1691
1692
    /**
1693
     * Returns the values from a single column of the input array, identified by
1694
     * the $columnKey, can be used to extract data-columns from multi-arrays.
1695
     *
1696
     * Info: Optionally, you may provide an $indexKey to index the values in the returned
1697
     * array by the values from the $indexKey column in the input array.
1698
     *
1699
     * @param mixed $columnKey
1700
     * @param mixed $indexKey
1701
     *
1702
     * @return static
1703
     *                <p>(Immutable)</p>
1704
     */
1705 1
    public function getColumn($columnKey = null, $indexKey = null): self
1706
    {
1707 1
        return static::create(
1708 1
            \array_column($this->array, $columnKey, $indexKey),
1709 1
            $this->iteratorClass,
1710 1
            false
1711
        );
1712
    }
1713
1714
    /**
1715
     * Get the current array from the "Arrayy"-object as generator.
1716
     *
1717
     * @return \Generator
1718
     */
1719 125
    public function getGenerator(): \Generator
1720
    {
1721 125
        yield from $this->array;
1722 93
    }
1723
1724
    /**
1725
     * alias: for "Arrayy->keys()"
1726
     *
1727
     * @return static
1728
     *                <p>(Immutable)</p>
1729
     *
1730
     * @see Arrayy::keys()
1731
     */
1732 1
    public function getKeys(): self
1733
    {
1734 1
        return $this->keys();
1735
    }
1736
1737
    /**
1738
     * Get the current array from the "Arrayy"-object as object.
1739
     *
1740
     * @return \stdClass
1741
     */
1742 4
    public function getObject(): \stdClass
1743
    {
1744 4
        return self::arrayToObject($this->getArray());
1745
    }
1746
1747
    /**
1748
     * alias: for "Arrayy->randomImmutable()"
1749
     *
1750
     * @return static
1751
     *                <p>(Immutable)</p>
1752
     *
1753
     * @see Arrayy::randomImmutable()
1754
     */
1755 4
    public function getRandom(): self
1756
    {
1757 4
        return $this->randomImmutable();
1758
    }
1759
1760
    /**
1761
     * alias: for "Arrayy->randomKey()"
1762
     *
1763
     * @return mixed
1764
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
1765
     *
1766
     * @see Arrayy::randomKey()
1767
     */
1768 3
    public function getRandomKey()
1769
    {
1770 3
        return $this->randomKey();
1771
    }
1772
1773
    /**
1774
     * alias: for "Arrayy->randomKeys()"
1775
     *
1776
     * @param int $number
1777
     *
1778
     * @return static
1779
     *                <p>(Immutable)</p>
1780
     *
1781
     * @see Arrayy::randomKeys()
1782
     */
1783 8
    public function getRandomKeys(int $number): self
1784
    {
1785 8
        return $this->randomKeys($number);
1786
    }
1787
1788
    /**
1789
     * alias: for "Arrayy->randomValue()"
1790
     *
1791
     * @return mixed
1792
     *               <p>Get a random value or null if there wasn't a value.</p>
1793
     *
1794
     * @see Arrayy::randomValue()
1795
     */
1796 3
    public function getRandomValue()
1797
    {
1798 3
        return $this->randomValue();
1799
    }
1800
1801
    /**
1802
     * alias: for "Arrayy->randomValues()"
1803
     *
1804
     * @param int $number
1805
     *
1806
     * @return static
1807
     *                <p>(Immutable)</p>
1808
     *
1809
     * @see Arrayy::randomValues()
1810
     */
1811 6
    public function getRandomValues(int $number): self
1812
    {
1813 6
        return $this->randomValues($number);
1814
    }
1815
1816
    /**
1817
     * Group values from a array according to the results of a closure.
1818
     *
1819
     * @param \callable $grouper  <p>A callable function name.</p>
1820
     * @param bool      $saveKeys
1821
     *
1822
     * @return static
1823
     *                <p>(Immutable)</p>
1824
     */
1825 4
    public function group($grouper, bool $saveKeys = false): self
1826
    {
1827
        // init
1828 4
        $result = [];
1829
1830
        // Iterate over values, group by property/results from closure.
1831 4
        foreach ($this->getGenerator() as $key => $value) {
1832 4
            $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $this->array);
1833 4
            $newValue = $this->get($groupKey, null, $result);
1834
1835 4
            if ($groupKey instanceof self) {
1836
                $groupKey = $groupKey->getArray();
1837
            }
1838
1839 4
            if ($newValue instanceof self) {
1840 4
                $newValue = $newValue->getArray();
1841
            }
1842
1843
            // Add to results.
1844 4
            if ($groupKey !== null) {
1845 3
                if ($saveKeys) {
1846 2
                    $result[$groupKey] = $newValue;
1847 2
                    $result[$groupKey][$key] = $value;
1848
                } else {
1849 1
                    $result[$groupKey] = $newValue;
1850 4
                    $result[$groupKey][] = $value;
1851
                }
1852
            }
1853
        }
1854
1855 4
        return static::create($result, $this->iteratorClass, false);
1856
    }
1857
1858
    /**
1859
     * Check if an array has a given key.
1860
     *
1861
     * @param mixed $key
1862
     *
1863
     * @return bool
1864
     */
1865 23
    public function has($key): bool
1866
    {
1867 23
        static $UN_FOUND = null;
1868
1869 23
        if ($UN_FOUND === null) {
1870
            // Generate unique string to use as marker.
1871 1
            $UN_FOUND = \uniqid('arrayy', true);
1872
        }
1873
1874 23
        return $this->get($key, $UN_FOUND) !== $UN_FOUND;
1875
    }
1876
1877
    /**
1878
     * Implodes the values of this array.
1879
     *
1880
     * @param string $glue
1881
     *
1882
     * @return string
1883
     */
1884 27
    public function implode(string $glue = ''): string
1885
    {
1886 27
        return $this->implode_recursive($glue, $this->array, false);
1887
    }
1888
1889
    /**
1890
     * Implodes the keys of this array.
1891
     *
1892
     * @param string $glue
1893
     *
1894
     * @return string
1895
     */
1896 8
    public function implodeKeys(string $glue = ''): string
1897
    {
1898 8
        return $this->implode_recursive($glue, $this->array, true);
1899
    }
1900
1901
    /**
1902
     * Given a list and an iterate-function that returns
1903
     * a key for each element in the list (or a property name),
1904
     * returns an object with an index of each item.
1905
     *
1906
     * @param mixed $key
1907
     *
1908
     * @return static
1909
     *                <p>(Immutable)</p>
1910
     */
1911 4
    public function indexBy($key): self
1912
    {
1913
        // init
1914 4
        $results = [];
1915
1916 4
        foreach ($this->getGenerator() as $a) {
1917 4
            if (\array_key_exists($key, $a) === true) {
1918 4
                $results[$a[$key]] = $a;
1919
            }
1920
        }
1921
1922 4
        return static::create($results, $this->iteratorClass, false);
1923
    }
1924
1925
    /**
1926
     * alias: for "Arrayy->searchIndex()"
1927
     *
1928
     * @param mixed $value <p>The value to search for.</p>
1929
     *
1930
     * @return mixed
1931
     *
1932
     * @see Arrayy::searchIndex()
1933
     */
1934 4
    public function indexOf($value)
1935
    {
1936 4
        return $this->searchIndex($value);
1937
    }
1938
1939
    /**
1940
     * Get everything but the last..$to items.
1941
     *
1942
     * @param int $to
1943
     *
1944
     * @return static
1945
     *                <p>(Immutable)</p>
1946
     */
1947 12
    public function initial(int $to = 1): self
1948
    {
1949 12
        return $this->firstsImmutable(\count($this->array, \COUNT_NORMAL) - $to);
1950
    }
1951
1952
    /**
1953
     * Return an array with all elements found in input array.
1954
     *
1955
     * @param array $search
1956
     *
1957
     * @return static
1958
     *                <p>(Immutable)</p>
1959
     */
1960 2
    public function intersection(array $search): self
1961
    {
1962 2
        return static::create(
1963 2
            \array_values(\array_intersect($this->array, $search)),
1964 2
            $this->iteratorClass,
1965 2
            false
1966
        );
1967
    }
1968
1969
    /**
1970
     * Return a boolean flag which indicates whether the two input arrays have any common elements.
1971
     *
1972
     * @param array $search
1973
     *
1974
     * @return bool
1975
     */
1976 1
    public function intersects(array $search): bool
1977
    {
1978 1
        return \count($this->intersection($search)->array, \COUNT_NORMAL) > 0;
1979
    }
1980
1981
    /**
1982
     * Invoke a function on all of an array's values.
1983
     *
1984
     * @param mixed $callable
1985
     * @param mixed $arguments
1986
     *
1987
     * @return static
1988
     *                <p>(Immutable)</p>
1989
     */
1990 1
    public function invoke($callable, $arguments = []): self
1991
    {
1992
        // If one argument given for each iteration, create an array for it.
1993 1
        if (!\is_array($arguments)) {
1994 1
            $arguments = StaticArrayy::repeat(
1995 1
                $arguments,
1996 1
                \count($this->array, \COUNT_NORMAL)
1997 1
            )->getArray();
1998
        }
1999
2000
        // If the callable has arguments, pass them.
2001 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...
2002 1
            $array = \array_map($callable, $this->array, $arguments);
2003
        } else {
2004 1
            $array = \array_map($callable, $this->array);
2005
        }
2006
2007 1
        return static::create($array, $this->iteratorClass, false);
2008
    }
2009
2010
    /**
2011
     * Check whether array is associative or not.
2012
     *
2013
     * @param bool $recursive
2014
     *
2015
     * @return bool
2016
     *              <p>Returns true if associative, false otherwise.</p>
2017
     */
2018 15
    public function isAssoc(bool $recursive = false): bool
2019
    {
2020 15
        if ($this->isEmpty()) {
2021 3
            return false;
2022
        }
2023
2024 13
        foreach ($this->keys($recursive)->getGenerator() as $key) {
2025 13
            if (!\is_string($key)) {
2026 13
                return false;
2027
            }
2028
        }
2029
2030 3
        return true;
2031
    }
2032
2033
    /**
2034
     * Check whether the array is empty or not.
2035
     *
2036
     * @return bool
2037
     *              <p>Returns true if empty, false otherwise.</p>
2038
     */
2039 92
    public function isEmpty(): bool
2040
    {
2041 92
        return !$this->array;
2042
    }
2043
2044
    /**
2045
     * Check if the current array is equal to the given "$array" or not.
2046
     *
2047
     * @param array $array
2048
     *
2049
     * @return bool
2050
     */
2051
    public function isEqual(array $array): bool
2052
    {
2053
        return $this->array === $array;
2054
    }
2055
2056
    /**
2057
     * Check if the current array is a multi-array.
2058
     *
2059
     * @return bool
2060
     */
2061 14
    public function isMultiArray(): bool
2062
    {
2063
        return !(
2064 14
            \count($this->array, \COUNT_NORMAL)
2065
            ===
2066 14
            \count($this->array, \COUNT_RECURSIVE)
2067
        );
2068
    }
2069
2070
    /**
2071
     * Check whether array is numeric or not.
2072
     *
2073
     * @return bool
2074
     *              <p>Returns true if numeric, false otherwise.</p>
2075
     */
2076 5
    public function isNumeric(): bool
2077
    {
2078 5
        if ($this->isEmpty()) {
2079 2
            return false;
2080
        }
2081
2082 4
        foreach ($this->keys()->getGenerator() as $key) {
2083 4
            if (!\is_int($key)) {
2084 4
                return false;
2085
            }
2086
        }
2087
2088 2
        return true;
2089
    }
2090
2091
    /**
2092
     * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2093
     *
2094
     * @param bool $recursive
2095
     *
2096
     * @return bool
2097
     */
2098 1
    public function isSequential(bool $recursive = false): bool
2099
    {
2100
2101
        // recursive
2102
2103 1
        if ($recursive === true) {
2104
            return $this->array_keys_recursive($this->array)
2105
                   ===
2106
                   \range(0, \count($this->array, \COUNT_RECURSIVE) - 1);
2107
        }
2108
2109
        // non recursive
2110
2111 1
        return \array_keys($this->array)
2112
               ===
2113 1
               \range(0, \count($this->array, \COUNT_NORMAL) - 1);
2114
    }
2115
2116
    /**
2117
     * @return array
2118
     */
2119
    public function jsonSerialize(): array
2120
    {
2121
        return $this->getArray();
2122
    }
2123
2124
    /**
2125
     * Get all keys from the current array.
2126
     *
2127
     * @param bool  $recursive    [optional] <p>
2128
     *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2129
     *                            </p>
2130
     * @param mixed $search_value [optional] <p>
2131
     *                            If specified, then only keys containing these values are returned.
2132
     *                            </p>
2133
     * @param bool  $strict       [optional] <p>
2134
     *                            Determines if strict comparison (===) should be used during the search.
2135
     *                            </p>
2136
     *
2137
     * @return static
2138
     *                <p>(Immutable) An array of all the keys in input.</p>
2139
     */
2140 26
    public function keys(bool $recursive = false, $search_value = null, bool $strict = true): self
2141
    {
2142
2143
        // recursive
2144
2145 26
        if ($recursive === true) {
2146 3
            if ($search_value === null) {
2147 3
                $array = $this->array_keys_recursive($this->array);
2148
            } else {
2149
                $array = $this->array_keys_recursive($this->array, $search_value, $strict);
2150
            }
2151
2152 3
            return static::create($array, $this->iteratorClass, false);
2153
        }
2154
2155
        // non recursive
2156
2157 25
        if ($search_value === null) {
2158 25
            $array = \array_keys($this->array);
2159
        } else {
2160
            $array = \array_keys($this->array, $search_value, $strict);
2161
        }
2162
2163 25
        return static::create($array, $this->iteratorClass, false);
2164
    }
2165
2166
    /**
2167
     * Sort an array by key in reverse order.
2168
     *
2169
     * @param int $sort_flags [optional] <p>
2170
     *                        You may modify the behavior of the sort using the optional
2171
     *                        parameter sort_flags, for details
2172
     *                        see sort.
2173
     *                        </p>
2174
     *
2175
     * @return static
2176
     *                <p>(Mutable) Return this Arrayy object.</p>
2177
     */
2178 4
    public function krsort(int $sort_flags = 0): self
2179
    {
2180 4
        \krsort($this->array, $sort_flags);
2181
2182 4
        return $this;
2183
    }
2184
2185
    /**
2186
     * Get the last value from the current array.
2187
     *
2188
     * @return mixed
2189
     *               <p>Return null if there wasn't a element.</p>
2190
     */
2191 4
    public function last()
2192
    {
2193 4
        return $this->pop();
2194
    }
2195
2196
    /**
2197
     * Get the last value(s) from the current array.
2198
     *
2199
     * @param int|null $number
2200
     *
2201
     * @return static
2202
     *                <p>(Immutable)</p>
2203
     */
2204 13
    public function lastsImmutable(int $number = null): self
2205
    {
2206 13
        if ($this->isEmpty()) {
2207 1
            return static::create([], $this->iteratorClass, false);
2208
        }
2209
2210 12
        if ($number === null) {
2211 8
            $poppedValue = $this->pop();
2212
2213 8
            if ($poppedValue === null) {
2214 1
                $poppedValue = [$poppedValue];
2215
            } else {
2216 7
                $poppedValue = (array) $poppedValue;
2217
            }
2218
2219 8
            $arrayy = static::create($poppedValue, $this->iteratorClass, false);
2220
        } else {
2221 4
            $number = (int) $number;
2222 4
            $arrayy = $this->rest(-$number);
2223
        }
2224
2225 12
        return $arrayy;
2226
    }
2227
2228
    /**
2229
     * Get the last value(s) from the current array.
2230
     *
2231
     * @param int|null $number
2232
     *
2233
     * @return static
2234
     *                <p>(Mutable)</p>
2235
     */
2236 13
    public function lastsMutable(int $number = null): self
2237
    {
2238 13
        if ($this->isEmpty()) {
2239 1
            return $this;
2240
        }
2241
2242 12
        if ($number === null) {
2243 8
            $poppedValue = $this->pop();
2244
2245 8
            if ($poppedValue === null) {
2246 1
                $poppedValue = [$poppedValue];
2247
            } else {
2248 7
                $poppedValue = (array) $poppedValue;
2249
            }
2250
2251 8
            $this->array = static::create($poppedValue, $this->iteratorClass, false)->array;
2252
        } else {
2253 4
            $number = (int) $number;
2254 4
            $this->array = $this->rest(-$number)->array;
2255
        }
2256
2257 12
        return $this;
2258
    }
2259
2260
    /**
2261
     * Count the values from the current array.
2262
     *
2263
     * alias: for "Arrayy->count()"
2264
     *
2265
     * @param int $mode
2266
     *
2267
     * @return int
2268
     *
2269
     * @see Arrayy::count()
2270
     */
2271 20
    public function length(int $mode = \COUNT_NORMAL): int
2272
    {
2273 20
        return $this->count($mode);
2274
    }
2275
2276
    /**
2277
     * Apply the given function to the every element of the array,
2278
     * collecting the results.
2279
     *
2280
     * @param \callable $callable
2281
     *
2282
     * @return static
2283
     *                <p>(Immutable) Arrayy object with modified elements.</p>
2284
     */
2285 4
    public function map($callable): self
2286
    {
2287 4
        return static::create(
2288 4
            \array_map($callable, $this->array),
2289 4
            $this->iteratorClass,
2290 4
            false
2291
        );
2292
    }
2293
2294
    /**
2295
     * Check if all items in current array match a truth test.
2296
     *
2297
     * @param \Closure $closure
2298
     *
2299
     * @return bool
2300
     */
2301 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...
2302
    {
2303 15
        if (\count($this->array, \COUNT_NORMAL) === 0) {
2304 2
            return false;
2305
        }
2306
2307 13
        foreach ($this->getGenerator() as $key => $value) {
2308 13
            $value = $closure($value, $key);
2309
2310 13
            if ($value === false) {
2311 13
                return false;
2312
            }
2313
        }
2314
2315 7
        return true;
2316
    }
2317
2318
    /**
2319
     * Check if any item in the current array matches a truth test.
2320
     *
2321
     * @param \Closure $closure
2322
     *
2323
     * @return bool
2324
     */
2325 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...
2326
    {
2327 14
        if (\count($this->array, \COUNT_NORMAL) === 0) {
2328 2
            return false;
2329
        }
2330
2331 12
        foreach ($this->getGenerator() as $key => $value) {
2332 12
            $value = $closure($value, $key);
2333
2334 12
            if ($value === true) {
2335 12
                return true;
2336
            }
2337
        }
2338
2339 4
        return false;
2340
    }
2341
2342
    /**
2343
     * Get the max value from an array.
2344
     *
2345
     * @return mixed
2346
     */
2347 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...
2348
    {
2349 10
        if (\count($this->array, \COUNT_NORMAL) === 0) {
2350 1
            return false;
2351
        }
2352
2353 9
        return \max($this->array);
2354
    }
2355
2356
    /**
2357
     * Merge the new $array into the current array.
2358
     *
2359
     * - keep key,value from the current array, also if the index is in the new $array
2360
     *
2361
     * @param array $array
2362
     * @param bool  $recursive
2363
     *
2364
     * @return static
2365
     *                <p>(Immutable)</p>
2366
     */
2367 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...
2368
    {
2369 25
        if ($recursive === true) {
2370 4
            $result = \array_replace_recursive($this->array, $array);
2371
        } else {
2372 21
            $result = \array_replace($this->array, $array);
2373
        }
2374
2375 25
        return static::create($result, $this->iteratorClass, false);
2376
    }
2377
2378
    /**
2379
     * Merge the new $array into the current array.
2380
     *
2381
     * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2382
     * - create new indexes
2383
     *
2384
     * @param array $array
2385
     * @param bool  $recursive
2386
     *
2387
     * @return static
2388
     *                <p>(Immutable)</p>
2389
     */
2390 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...
2391
    {
2392 16
        if ($recursive === true) {
2393 4
            $result = \array_merge_recursive($this->array, $array);
2394
        } else {
2395 12
            $result = \array_merge($this->array, $array);
2396
        }
2397
2398 16
        return static::create($result, $this->iteratorClass, false);
2399
    }
2400
2401
    /**
2402
     * Merge the the current array into the $array.
2403
     *
2404
     * - use key,value from the new $array, also if the index is in the current array
2405
     *
2406
     * @param array $array
2407
     * @param bool  $recursive
2408
     *
2409
     * @return static
2410
     *                <p>(Immutable)</p>
2411
     */
2412 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...
2413
    {
2414 16
        if ($recursive === true) {
2415 4
            $result = \array_replace_recursive($array, $this->array);
2416
        } else {
2417 12
            $result = \array_replace($array, $this->array);
2418
        }
2419
2420 16
        return static::create($result, $this->iteratorClass, false);
2421
    }
2422
2423
    /**
2424
     * Merge the current array into the new $array.
2425
     *
2426
     * - replace duplicate assoc-keys from new $array with the key,values from the current array
2427
     * - create new indexes
2428
     *
2429
     * @param array $array
2430
     * @param bool  $recursive
2431
     *
2432
     * @return static
2433
     *                <p>(Immutable)</p>
2434
     */
2435 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...
2436
    {
2437 17
        if ($recursive === true) {
2438 4
            $result = \array_merge_recursive($array, $this->array);
2439
        } else {
2440 13
            $result = \array_merge($array, $this->array);
2441
        }
2442
2443 17
        return static::create($result, $this->iteratorClass, false);
2444
    }
2445
2446
    /**
2447
     * @return ArrayyMeta|static
2448
     */
2449 9
    public static function meta()
2450
    {
2451 9
        return (new ArrayyMeta())->getMetaObject(static::class);
2452
    }
2453
2454
    /**
2455
     * Get the min value from an array.
2456
     *
2457
     * @return mixed
2458
     */
2459 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...
2460
    {
2461 10
        if (\count($this->array, \COUNT_NORMAL) === 0) {
2462 1
            return false;
2463
        }
2464
2465 9
        return \min($this->array);
2466
    }
2467
2468
    /**
2469
     * Move an array element to a new index.
2470
     *
2471
     * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2472
     *
2473
     * @param int|string $from
2474
     * @param int|string $to
2475
     *
2476
     * @return static
2477
     *                <p>(Immutable)</p>
2478
     */
2479 1
    public function moveElement($from, $to): self
2480
    {
2481 1
        $array = $this->array;
2482
2483 1
        if (\is_int($from)) {
2484 1
            $tmp = \array_splice($array, $from, 1);
2485 1
            \array_splice($array, $to, 0, $tmp);
2486 1
            $output = $array;
2487 1
        } elseif (\is_string($from)) {
2488 1
            $indexToMove = \array_search($from, \array_keys($array), true);
2489 1
            $itemToMove = $array[$from];
2490 1
            \array_splice($array, $indexToMove, 1);
2491 1
            $i = 0;
2492 1
            $output = [];
2493 1
            foreach ($array as $key => $item) {
2494 1
                if ($i === $to) {
2495 1
                    $output[$from] = $itemToMove;
2496
                }
2497 1
                $output[$key] = $item;
2498 1
                ++$i;
2499
            }
2500
        } else {
2501
            $output = [];
2502
        }
2503
2504 1
        return static::create($output, $this->iteratorClass, false);
2505
    }
2506
2507
    /**
2508
     * Get a subset of the items from the given array.
2509
     *
2510
     * @param mixed[] $keys
2511
     *
2512
     * @return static
2513
     *                <p>(Immutable)</p>
2514
     */
2515
    public function only(array $keys): self
2516
    {
2517
        $array = $this->array;
2518
2519
        return static::create(
2520
            \array_intersect_key($array, \array_flip($keys)),
2521
            $this->iteratorClass,
2522
            false
2523
        );
2524
    }
2525
2526
    /**
2527
     * Pad array to the specified size with a given value.
2528
     *
2529
     * @param int   $size  <p>Size of the result array.</p>
2530
     * @param mixed $value <p>Empty value by default.</p>
2531
     *
2532
     * @return static
2533
     *                <p>(Immutable) Arrayy object padded to $size with $value.</p>
2534
     */
2535 4
    public function pad(int $size, $value): self
2536
    {
2537 4
        return static::create(
2538 4
            \array_pad($this->array, $size, $value),
2539 4
            $this->iteratorClass,
2540 4
            false
2541
        );
2542
    }
2543
2544
    /**
2545
     * Pop a specified value off the end of the current array.
2546
     *
2547
     * @return mixed
2548
     *               <p>(Mutable) The popped element from the current array.</p>
2549
     */
2550 16
    public function pop()
2551
    {
2552 16
        return \array_pop($this->array);
2553
    }
2554
2555
    /**
2556
     * Prepend a (key) + value to the current array.
2557
     *
2558
     * @param mixed $value
2559
     * @param mixed $key
2560
     *
2561
     * @return static
2562
     *                <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2563
     */
2564 8
    public function prepend($value, $key = null): self
2565
    {
2566 8
        if ($key === null) {
2567 8
            \array_unshift($this->array, $value);
2568
        } else {
2569
            /** @noinspection AdditionOperationOnArraysInspection */
2570 1
            $this->array = [$key => $value] + $this->array;
2571
        }
2572
2573 8
        return $this;
2574
    }
2575
2576
    /**
2577
     * Add a suffix to each key.
2578
     *
2579
     * @param mixed $suffix
2580
     *
2581
     * @return static
2582
     *                <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2583
     */
2584 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...
2585
    {
2586
        // init
2587 10
        $result = [];
2588
2589 10
        foreach ($this->getGenerator() as $key => $item) {
2590 9
            if ($item instanceof self) {
2591
                $result[$key] = $item->prependToEachKey($suffix);
2592 9
            } elseif (\is_array($item)) {
2593
                $result[$key] = self::create($item, $this->iteratorClass, false)->prependToEachKey($suffix)->toArray();
2594
            } else {
2595 9
                $result[$key . $suffix] = $item;
2596
            }
2597
        }
2598
2599 10
        return self::create($result, $this->iteratorClass, false);
2600
    }
2601
2602
    /**
2603
     * Add a suffix to each value.
2604
     *
2605
     * @param mixed $suffix
2606
     *
2607
     * @return static
2608
     *                <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2609
     */
2610 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...
2611
    {
2612
        // init
2613 10
        $result = [];
2614
2615 10
        foreach ($this->getGenerator() as $key => $item) {
2616 9
            if ($item instanceof self) {
2617
                $result[$key] = $item->prependToEachValue($suffix);
2618 9
            } elseif (\is_array($item)) {
2619
                $result[$key] = self::create($item, $this->iteratorClass, false)
2620
                    ->prependToEachValue($suffix)
2621
                    ->toArray();
2622 9
            } elseif (\is_object($item)) {
2623 1
                $result[$key] = $item;
2624
            } else {
2625 9
                $result[$key] = $item . $suffix;
2626
            }
2627
        }
2628
2629 10
        return self::create($result, $this->iteratorClass, false);
2630
    }
2631
2632
    /**
2633
     * Push one or more values onto the end of array at once.
2634
     *
2635
     * @return static
2636
     *                <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2637
     */
2638 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...
2639
    {
2640 4
        if (\func_num_args()) {
2641 4
            $args = \array_merge([&$this->array], \func_get_args());
2642 4
            \array_push(...$args);
2643
        }
2644
2645 4
        return $this;
2646
    }
2647
2648
    /**
2649
     * Get a random value from the current array.
2650
     *
2651
     * @param int|null $number <p>How many values you will take?</p>
2652
     *
2653
     * @return static
2654
     *                <p>(Immutable)</p>
2655
     */
2656 18
    public function randomImmutable(int $number = null): self
2657
    {
2658 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...
2659 1
            return static::create([], $this->iteratorClass, false);
2660
        }
2661
2662 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...
2663
            /** @noinspection NonSecureArrayRandUsageInspection */
2664 13
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
2665
2666 13
            return static::create($arrayRandValue, $this->iteratorClass, false);
2667
        }
2668
2669 5
        $arrayTmp = $this->array;
2670
        /** @noinspection NonSecureShuffleUsageInspection */
2671 5
        \shuffle($arrayTmp);
2672
2673 5
        return static::create($arrayTmp, $this->iteratorClass, false)->firstsImmutable($number);
2674
    }
2675
2676
    /**
2677
     * Pick a random key/index from the keys of this array.
2678
     *
2679
     * @throws \RangeException If array is empty
2680
     *
2681
     * @return mixed
2682
     *               <p>Get a key/index or null if there wasn't a key/index.</p>
2683
     */
2684 4
    public function randomKey()
2685
    {
2686 4
        $result = $this->randomKeys(1);
2687
2688 4
        if (!isset($result[0])) {
2689
            $result[0] = null;
2690
        }
2691
2692 4
        return $result[0];
2693
    }
2694
2695
    /**
2696
     * Pick a given number of random keys/indexes out of this array.
2697
     *
2698
     * @param int $number <p>The number of keys/indexes (should be <= \count($this->array))</p>
2699
     *
2700
     * @throws \RangeException If array is empty
2701
     *
2702
     * @return static
2703
     *                <p>(Immutable)</p>
2704
     */
2705 13
    public function randomKeys(int $number): self
2706
    {
2707 13
        $count = \count($this->array, \COUNT_NORMAL);
2708
2709 13
        if ($number === 0 || $number > $count) {
2710 2
            throw new \RangeException(
2711 2
                \sprintf(
2712 2
                    'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2713 2
                    $number,
2714 2
                    $count
2715
                )
2716
            );
2717
        }
2718
2719 11
        $result = (array) \array_rand($this->array, $number);
2720
2721 11
        return static::create($result, $this->iteratorClass, false);
2722
    }
2723
2724
    /**
2725
     * Get a random value from the current array.
2726
     *
2727
     * @param int|null $number <p>How many values you will take?</p>
2728
     *
2729
     * @return static
2730
     *                <p>(Mutable)</p>
2731
     */
2732 17
    public function randomMutable(int $number = null): self
2733
    {
2734 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...
2735
            return static::create([], $this->iteratorClass, false);
2736
        }
2737
2738 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...
2739
            /** @noinspection NonSecureArrayRandUsageInspection */
2740 7
            $arrayRandValue = [$this->array[\array_rand($this->array)]];
2741 7
            $this->array = $arrayRandValue;
2742
2743 7
            return $this;
2744
        }
2745
2746
        /** @noinspection NonSecureShuffleUsageInspection */
2747 11
        \shuffle($this->array);
2748
2749 11
        return $this->firstsMutable($number);
2750
    }
2751
2752
    /**
2753
     * Pick a random value from the values of this array.
2754
     *
2755
     * @return mixed
2756
     *               <p>Get a random value or null if there wasn't a value.</p>
2757
     */
2758 4
    public function randomValue()
2759
    {
2760 4
        $result = $this->randomImmutable();
2761
2762 4
        if (!isset($result[0])) {
2763
            $result[0] = null;
2764
        }
2765
2766 4
        return $result[0];
2767
    }
2768
2769
    /**
2770
     * Pick a given number of random values out of this array.
2771
     *
2772
     * @param int $number
2773
     *
2774
     * @return static
2775
     *                <p>(Mutable)</p>
2776
     */
2777 7
    public function randomValues(int $number): self
2778
    {
2779 7
        return $this->randomMutable($number);
2780
    }
2781
2782
    /**
2783
     * Get a random value from an array, with the ability to skew the results.
2784
     *
2785
     * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2786
     *
2787
     * @param array    $array
2788
     * @param int|null $number <p>How many values you will take?</p>
2789
     *
2790
     * @return static
2791
     *                <p>(Immutable)</p>
2792
     */
2793 9
    public function randomWeighted(array $array, int $number = null): self
2794
    {
2795
        // init
2796 9
        $options = [];
2797
2798 9
        foreach ($array as $option => $weight) {
2799 9
            if ($this->searchIndex($option) !== false) {
2800 9
                for ($i = 0; $i < $weight; ++$i) {
2801 1
                    $options[] = $option;
2802
                }
2803
            }
2804
        }
2805
2806 9
        return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2807
    }
2808
2809
    /**
2810
     * Reduce the current array via callable e.g. anonymous-function.
2811
     *
2812
     * @param \callable $callable
2813
     * @param array     $init
2814
     *
2815
     * @return static
2816
     *                <p>(Immutable)</p>
2817
     */
2818 4
    public function reduce($callable, array $init = []): self
2819
    {
2820 4
        $result = \array_reduce($this->array, $callable, $init);
2821
2822 4
        if ($result === null) {
2823
            $this->array = [];
2824
        } else {
2825 4
            $this->array = (array) $result;
2826
        }
2827
2828 4
        return static::create($this->array, $this->iteratorClass, false);
2829
    }
2830
2831
    /**
2832
     * Create a numerically re-indexed Arrayy object.
2833
     *
2834
     * @return static
2835
     *                <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2836
     */
2837 9
    public function reindex(): self
2838
    {
2839 9
        $this->array = \array_values($this->array);
2840
2841 9
        return $this;
2842
    }
2843
2844
    /**
2845
     * Return all items that fail the truth test.
2846
     *
2847
     * @param \Closure $closure
2848
     *
2849
     * @return static
2850
     *                <p>(Immutable)</p>
2851
     */
2852 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...
2853
    {
2854 1
        $filtered = [];
2855
2856 1
        foreach ($this->getGenerator() as $key => $value) {
2857 1
            if (!$closure($value, $key)) {
2858 1
                $filtered[$key] = $value;
2859
            }
2860
        }
2861
2862 1
        return static::create($filtered, $this->iteratorClass, false);
2863
    }
2864
2865
    /**
2866
     * Remove a value from the current array (optional using dot-notation).
2867
     *
2868
     * @param mixed $key
2869
     *
2870
     * @return static
2871
     *                <p>(Immutable)</p>
2872
     */
2873 18
    public function remove($key): self
2874
    {
2875
        // recursive call
2876 18
        if (\is_array($key)) {
2877
            foreach ($key as $k) {
2878
                $this->internalRemove($k);
2879
            }
2880
2881
            return static::create($this->array, $this->iteratorClass, false);
2882
        }
2883
2884 18
        $this->internalRemove($key);
2885
2886 18
        return static::create($this->array, $this->iteratorClass, false);
2887
    }
2888
2889
    /**
2890
     * Remove the first value from the current array.
2891
     *
2892
     * @return static
2893
     *                <p>(Immutable)</p>
2894
     */
2895 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...
2896
    {
2897 7
        $tmpArray = $this->array;
2898 7
        \array_shift($tmpArray);
2899
2900 7
        return static::create($tmpArray, $this->iteratorClass, false);
2901
    }
2902
2903
    /**
2904
     * Remove the last value from the current array.
2905
     *
2906
     * @return static
2907
     *                <p>(Immutable)</p>
2908
     */
2909 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...
2910
    {
2911 7
        $tmpArray = $this->array;
2912 7
        \array_pop($tmpArray);
2913
2914 7
        return static::create($tmpArray, $this->iteratorClass, false);
2915
    }
2916
2917
    /**
2918
     * Removes a particular value from an array (numeric or associative).
2919
     *
2920
     * @param mixed $value
2921
     *
2922
     * @return static
2923
     *                <p>(Immutable)</p>
2924
     */
2925 7
    public function removeValue($value): self
2926
    {
2927 7
        $isNumericArray = true;
2928 7
        foreach ($this->getGenerator() as $key => $item) {
2929 6
            if ($item === $value) {
2930 6
                if (!\is_int($key)) {
2931
                    $isNumericArray = false;
2932
                }
2933 6
                unset($this->array[$key]);
2934
            }
2935
        }
2936
2937 7
        if ($isNumericArray) {
2938 7
            $this->array = \array_values($this->array);
2939
        }
2940
2941 7
        return static::create($this->array, $this->iteratorClass, false);
2942
    }
2943
2944
    /**
2945
     * Generate array of repeated arrays.
2946
     *
2947
     * @param int $times <p>How many times has to be repeated.</p>
2948
     *
2949
     * @return static
2950
     *                <p>(Immutable)</p>
2951
     */
2952 1
    public function repeat($times): self
2953
    {
2954 1
        if ($times === 0) {
2955 1
            return new static();
2956
        }
2957
2958 1
        return static::create(
2959 1
            \array_fill(0, (int) $times, $this->array),
2960 1
            $this->iteratorClass,
2961 1
            false
2962
        );
2963
    }
2964
2965
    /**
2966
     * Replace a key with a new key/value pair.
2967
     *
2968
     * @param mixed $replace
2969
     * @param mixed $key
2970
     * @param mixed $value
2971
     *
2972
     * @return static
2973
     *                <p>(Immutable)</p>
2974
     */
2975 2
    public function replace($replace, $key, $value): self
2976
    {
2977 2
        $that = $this->remove($replace);
2978
2979 2
        return $that->set($key, $value);
2980
    }
2981
2982
    /**
2983
     * Create an array using the current array as values and the other array as keys.
2984
     *
2985
     * @param array $keys <p>An array of keys.</p>
2986
     *
2987
     * @return static
2988
     *                <p>(Immutable) Arrayy object with keys from the other array.</p>
2989
     */
2990 2
    public function replaceAllKeys(array $keys): self
2991
    {
2992 2
        return static::create(
2993 2
            \array_combine($keys, $this->array),
2994 2
            $this->iteratorClass,
2995 2
            false
2996
        );
2997
    }
2998
2999
    /**
3000
     * Create an array using the current array as keys and the other array as values.
3001
     *
3002
     * @param array $array <p>An array o values.</p>
3003
     *
3004
     * @return static
3005
     *                <p>(Immutable) Arrayy object with values from the other array.</p>
3006
     */
3007 2
    public function replaceAllValues(array $array): self
3008
    {
3009 2
        return static::create(
3010 2
            \array_combine($this->array, $array),
3011 2
            $this->iteratorClass,
3012 2
            false
3013
        );
3014
    }
3015
3016
    /**
3017
     * Replace the keys in an array with another set.
3018
     *
3019
     * @param array $keys <p>An array of keys matching the array's size</p>
3020
     *
3021
     * @return static
3022
     *                <p>(Immutable)</p>
3023
     */
3024 1
    public function replaceKeys(array $keys): self
3025
    {
3026 1
        $values = \array_values($this->array);
3027 1
        $result = \array_combine($keys, $values);
3028
3029 1
        return static::create($result, $this->iteratorClass, false);
3030
    }
3031
3032
    /**
3033
     * Replace the first matched value in an array.
3034
     *
3035
     * @param mixed $search      <p>The value to replace.</p>
3036
     * @param mixed $replacement <p>The value to replace.</p>
3037
     *
3038
     * @return static
3039
     *                <p>(Immutable)</p>
3040
     */
3041 3
    public function replaceOneValue($search, $replacement = ''): self
3042
    {
3043 3
        $array = $this->array;
3044 3
        $key = \array_search($search, $array, true);
3045
3046 3
        if ($key !== false) {
3047 3
            $array[$key] = $replacement;
3048
        }
3049
3050 3
        return static::create($array, $this->iteratorClass, false);
3051
    }
3052
3053
    /**
3054
     * Replace values in the current array.
3055
     *
3056
     * @param mixed $search      <p>The value to replace.</p>
3057
     * @param mixed $replacement <p>What to replace it with.</p>
3058
     *
3059
     * @return static
3060
     *                <p>(Immutable)</p>
3061
     */
3062 1
    public function replaceValues($search, $replacement = ''): self
3063
    {
3064 1
        $array = $this->each(
3065 1
            static function ($value) use ($search, $replacement) {
3066 1
                return \str_replace($search, $replacement, $value);
3067 1
            }
3068
        );
3069
3070 1
        return $array;
3071
    }
3072
3073
    /**
3074
     * Get the last elements from index $from until the end of this array.
3075
     *
3076
     * @param int $from
3077
     *
3078
     * @return static
3079
     *                <p>(Immutable)</p>
3080
     */
3081 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...
3082
    {
3083 15
        $tmpArray = $this->array;
3084
3085 15
        return static::create(
3086 15
            \array_splice($tmpArray, $from),
3087 15
            $this->iteratorClass,
3088 15
            false
3089
        );
3090
    }
3091
3092
    /**
3093
     * Return the array in the reverse order.
3094
     *
3095
     * @return static
3096
     *                <p>(Mutable) Return this Arrayy object.</p>
3097
     */
3098 8
    public function reverse(): self
3099
    {
3100 8
        $this->array = \array_reverse($this->array);
3101
3102 8
        return $this;
3103
    }
3104
3105
    /**
3106
     * Sort an array in reverse order.
3107
     *
3108
     * @param int $sort_flags [optional] <p>
3109
     *                        You may modify the behavior of the sort using the optional
3110
     *                        parameter sort_flags, for details
3111
     *                        see sort.
3112
     *                        </p>
3113
     *
3114
     * @return static
3115
     *                <p>(Mutable) Return this Arrayy object.</p>
3116
     */
3117 4
    public function rsort(int $sort_flags = 0): self
3118
    {
3119 4
        \rsort($this->array, $sort_flags);
3120
3121 4
        return $this;
3122
    }
3123
3124
    /**
3125
     * Search for the first index of the current array via $value.
3126
     *
3127
     * @param mixed $value
3128
     *
3129
     * @return float|int|string
3130
     */
3131 20
    public function searchIndex($value)
3132
    {
3133 20
        return \array_search($value, $this->array, true);
3134
    }
3135
3136
    /**
3137
     * Search for the value of the current array via $index.
3138
     *
3139
     * @param mixed $index
3140
     *
3141
     * @return static
3142
     *                <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3143
     */
3144 9
    public function searchValue($index): self
3145
    {
3146
        // init
3147 9
        $return = [];
3148
3149 9
        if ($this->isEmpty()) {
3150
            return static::create([], $this->iteratorClass, false);
3151
        }
3152
3153
        // php cast "bool"-index into "int"-index
3154 9
        if ((bool) $index === $index) {
3155 1
            $index = (int) $index;
3156
        }
3157
3158 9
        if (\array_key_exists($index, $this->array) === true) {
3159 7
            $return = [$this->array[$index]];
3160
        }
3161
3162 9
        return static::create($return, $this->iteratorClass, false);
3163
    }
3164
3165
    /**
3166
     * Set a value for the current array (optional using dot-notation).
3167
     *
3168
     * @param string $key   <p>The key to set.</p>
3169
     * @param mixed  $value <p>Its value.</p>
3170
     *
3171
     * @return static
3172
     *                <p>(Mutable)</p>
3173
     */
3174 17
    public function set($key, $value): self
3175
    {
3176 17
        $this->internalSet($key, $value);
3177
3178 17
        return $this;
3179
    }
3180
3181
    /**
3182
     * Get a value from a array and set it if it was not.
3183
     *
3184
     * WARNING: this method only set the value, if the $key is not already set
3185
     *
3186
     * @param mixed $key      <p>The key</p>
3187
     * @param mixed $fallback <p>The default value to set if it isn't.</p>
3188
     *
3189
     * @return mixed
3190
     *               <p>(Mutable)</p>
3191
     */
3192 11
    public function setAndGet($key, $fallback = null)
3193
    {
3194
        // If the key doesn't exist, set it.
3195 11
        if (!$this->has($key)) {
3196 4
            $this->array = $this->set($key, $fallback)->getArray();
3197
        }
3198
3199 11
        return $this->get($key);
3200
    }
3201
3202
    /**
3203
     * Shifts a specified value off the beginning of array.
3204
     *
3205
     * @return mixed
3206
     *               <p>(Mutable) A shifted element from the current array.</p>
3207
     */
3208 4
    public function shift()
3209
    {
3210 4
        return \array_shift($this->array);
3211
    }
3212
3213
    /**
3214
     * Shuffle the current array.
3215
     *
3216
     * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3217
     * @param array $array  [optional]
3218
     *
3219
     * @return static
3220
     *                <p>(Immutable)</p>
3221
     */
3222 1
    public function shuffle(bool $secure = false, array $array = null): self
3223
    {
3224 1
        if ($array === null) {
3225 1
            $array = $this->array;
3226
        }
3227
3228 1
        if ($secure !== true) {
3229
            /** @noinspection NonSecureShuffleUsageInspection */
3230 1
            \shuffle($array);
3231
        } else {
3232 1
            $size = \count($array, \COUNT_NORMAL);
3233 1
            $keys = \array_keys($array);
3234 1
            for ($i = $size - 1; $i > 0; --$i) {
3235
                try {
3236 1
                    $r = \random_int(0, $i);
3237
                } catch (\Exception $e) {
3238
                    /** @noinspection RandomApiMigrationInspection */
3239
                    $r = \mt_rand(0, $i);
3240
                }
3241 1
                if ($r !== $i) {
3242
                    $temp = $array[$keys[$r]];
3243
                    $array[$keys[$r]] = $array[$keys[$i]];
3244
                    $array[$keys[$i]] = $temp;
3245
                }
3246
            }
3247
3248
            // reset indices
3249 1
            $array = \array_values($array);
3250
        }
3251
3252 1
        foreach ($array as $key => $value) {
3253
            // check if recursive is needed
3254 1
            if (\is_array($value) === true) {
3255 1
                $array[$key] = $this->shuffle($secure, $value);
3256
            }
3257
        }
3258
3259 1
        return static::create($array, $this->iteratorClass, false);
3260
    }
3261
3262
    /**
3263
     * Count the values from the current array.
3264
     *
3265
     * alias: for "Arrayy->count()"
3266
     *
3267
     * @param int $mode
3268
     *
3269
     * @return int
3270
     */
3271 20
    public function size(int $mode = \COUNT_NORMAL): int
3272
    {
3273 20
        return $this->count($mode);
3274
    }
3275
3276
    /**
3277
     * Counts all elements in an array, or something in an object.
3278
     *
3279
     * <p>
3280
     * For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3281
     * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3282
     * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3283
     * implemented and used in PHP.
3284
     * </p>
3285
     *
3286
     * @return int
3287
     *             <p>
3288
     *             The number of elements in var, which is
3289
     *             typically an array, since anything else will have one
3290
     *             element.
3291
     *             </p>
3292
     *             <p>
3293
     *             If var is not an array or an object with
3294
     *             implemented Countable interface,
3295
     *             1 will be returned.
3296
     *             There is one exception, if var is &null;,
3297
     *             0 will be returned.
3298
     *             </p>
3299
     *             <p>
3300
     *             Caution: count may return 0 for a variable that isn't set,
3301
     *             but it may also return 0 for a variable that has been initialized with an
3302
     *             empty array. Use isset to test if a variable is set.
3303
     *             </p>
3304
     */
3305 10
    public function sizeRecursive(): int
3306
    {
3307 10
        return \count($this->array, \COUNT_RECURSIVE);
3308
    }
3309
3310
    /**
3311
     * Extract a slice of the array.
3312
     *
3313
     * @param int      $offset       <p>Slice begin index.</p>
3314
     * @param int|null $length       <p>Length of the slice.</p>
3315
     * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3316
     *
3317
     * @return static
3318
     *                <p>A slice of the original array with length $length.</p>
3319
     */
3320 4
    public function slice(int $offset, int $length = null, bool $preserveKeys = false): self
3321
    {
3322 4
        return static::create(
3323 4
            \array_slice($this->array, $offset, $length, $preserveKeys),
3324 4
            $this->iteratorClass,
3325 4
            false
3326
        );
3327
    }
3328
3329
    /**
3330
     * Sort the current array and optional you can keep the keys.
3331
     *
3332
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3333
     * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3334
     *                              <strong>SORT_NATURAL</strong></p>
3335
     * @param bool       $keepKeys
3336
     *
3337
     * @return static
3338
     *                <p>(Mutable) Return this Arrayy object.</p>
3339
     */
3340 20
    public function sort($direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
3341
    {
3342 20
        return $this->sorting($this->array, $direction, $strategy, $keepKeys);
3343
    }
3344
3345
    /**
3346
     * Sort the current array by key.
3347
     *
3348
     * @see http://php.net/manual/en/function.ksort.php
3349
     * @see http://php.net/manual/en/function.krsort.php
3350
     *
3351
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3352
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3353
     *                              <strong>SORT_NATURAL</strong></p>
3354
     *
3355
     * @return static
3356
     *                <p>(Mutable) Return this Arrayy object.</p>
3357
     */
3358 18
    public function sortKeys($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3359
    {
3360
        /** @noinspection UnusedFunctionResultInspection */
3361 18
        $this->sorterKeys($this->array, $direction, $strategy);
3362
3363 18
        return $this;
3364
    }
3365
3366
    /**
3367
     * Sort the current array by value.
3368
     *
3369
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3370
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3371
     *                              <strong>SORT_NATURAL</strong></p>
3372
     *
3373
     * @return static
3374
     *                <p>(Mutable)</p>
3375
     */
3376 1
    public function sortValueKeepIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3377
    {
3378 1
        return $this->sort($direction, $strategy, true);
3379
    }
3380
3381
    /**
3382
     * Sort the current array by value.
3383
     *
3384
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3385
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3386
     *                              <strong>SORT_NATURAL</strong></p>
3387
     *
3388
     * @return static
3389
     *                <p>(Mutable)</p>
3390
     */
3391 1
    public function sortValueNewIndex($direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3392
    {
3393 1
        return $this->sort($direction, $strategy, false);
3394
    }
3395
3396
    /**
3397
     * Sort a array by value, by a closure or by a property.
3398
     *
3399
     * - If the sorter is null, the array is sorted naturally.
3400
     * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3401
     *
3402
     * @param \callable|null $sorter
3403
     * @param int|string     $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3404
     * @param int            $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3405
     *                                  <strong>SORT_NATURAL</strong></p>
3406
     *
3407
     * @return static
3408
     *                <p>(Immutable)</p>
3409
     */
3410 1
    public function sorter($sorter = null, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
3411
    {
3412 1
        $array = (array) $this->array;
3413 1
        $direction = $this->getDirection($direction);
3414
3415
        // Transform all values into their results.
3416 1
        if ($sorter) {
3417 1
            $arrayy = static::create($array, $this->iteratorClass, false);
3418
3419 1
            $that = $this;
3420 1
            $results = $arrayy->each(
3421 1
                static function ($value) use ($sorter, $that) {
3422 1
                    return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3423 1
                }
3424
            );
3425
3426 1
            $results = $results->getArray();
3427
        } else {
3428 1
            $results = $array;
3429
        }
3430
3431
        // Sort by the results and replace by original values
3432 1
        \array_multisort($results, $direction, $strategy, $array);
3433
3434 1
        return static::create($array, $this->iteratorClass, false);
3435
    }
3436
3437
    /**
3438
     * Split an array in the given amount of pieces.
3439
     *
3440
     * @param int  $numberOfPieces
3441
     * @param bool $keepKeys
3442
     *
3443
     * @return static
3444
     *                <p>(Immutable)</p>
3445
     */
3446 1 View Code Duplication
    public function split(int $numberOfPieces = 2, bool $keepKeys = 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...
3447
    {
3448 1
        $arrayCount = \count($this->array, \COUNT_NORMAL);
3449
3450 1
        if ($arrayCount === 0) {
3451 1
            $result = [];
3452
        } else {
3453 1
            $splitSize = (int) \ceil($arrayCount / $numberOfPieces);
3454 1
            $result = \array_chunk($this->array, $splitSize, $keepKeys);
3455
        }
3456
3457 1
        return static::create($result, $this->iteratorClass, false);
3458
    }
3459
3460
    /**
3461
     * Stripe all empty items.
3462
     *
3463
     * @return static
3464
     *                <p>(Immutable)</p>
3465
     */
3466 1
    public function stripEmpty(): self
3467
    {
3468 1
        return $this->filter(
3469 1
            static function ($item) {
3470 1
                if ($item === null) {
3471 1
                    return false;
3472
                }
3473
3474 1
                return (bool) \trim((string) $item);
3475 1
            }
3476
        );
3477
    }
3478
3479
    /**
3480
     * Swap two values between positions by key.
3481
     *
3482
     * @param int|string $swapA <p>a key in the array</p>
3483
     * @param int|string $swapB <p>a key in the array</p>
3484
     *
3485
     * @return static
3486
     *                <p>(Immutable)</p>
3487
     */
3488 1
    public function swap($swapA, $swapB): self
3489
    {
3490 1
        $array = $this->array;
3491
3492 1
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3493
3494 1
        return static::create($array, $this->iteratorClass, false);
3495
    }
3496
3497
    /**
3498
     * alias: for "Arrayy->getArray()"
3499
     *
3500
     * @see Arrayy::getArray()
3501
     */
3502 192
    public function toArray()
3503
    {
3504 192
        return $this->getArray();
3505
    }
3506
3507
    /**
3508
     * Convert the current array to JSON.
3509
     *
3510
     * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3511
     * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3512
     *
3513
     * @return string
3514
     */
3515 6
    public function toJson(int $options = 0, int $depth = 512): string
3516
    {
3517
        /** @noinspection PhpComposerExtensionStubsInspection */
3518 6
        return \json_encode($this->array, $options, $depth);
3519
    }
3520
3521
    /**
3522
     * Implodes array to a string with specified separator.
3523
     *
3524
     * @param string $separator [optional] <p>The element's separator.</p>
3525
     *
3526
     * @return string
3527
     *                <p>The string representation of array, separated by ",".</p>
3528
     */
3529 19
    public function toString(string $separator = ','): string
3530
    {
3531 19
        return $this->implode($separator);
3532
    }
3533
3534
    /**
3535
     * Return a duplicate free copy of the current array.
3536
     *
3537
     * @return static
3538
     *                <p>(Mutable)</p>
3539
     */
3540 10
    public function unique(): self
3541
    {
3542
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3543
3544 10
        $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce($this->arr...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...
3545 10
            $this->array,
3546 10
            static function ($resultArray, $value) {
3547 9
                if (!\in_array($value, $resultArray, true)) {
3548 9
                    $resultArray[] = $value;
3549
                }
3550
3551 9
                return $resultArray;
3552 10
            },
3553 10
            []
3554
        );
3555
3556 10 View Code Duplication
        if ($this->array === 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...
3557
            $this->array = [];
3558
        } else {
3559 10
            $this->array = (array) $this->array;
3560
        }
3561
3562 10
        return $this;
3563
    }
3564
3565
    /**
3566
     * Return a duplicate free copy of the current array. (with the old keys)
3567
     *
3568
     * @return static
3569
     *                <p>(Mutable)</p>
3570
     */
3571 11
    public function uniqueKeepIndex(): self
3572
    {
3573
        // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3574
3575
        // init
3576 11
        $array = $this->array;
3577
3578 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...
3579 11
            \array_keys($array),
3580 11
            static function ($resultArray, $key) use ($array) {
3581 10
                if (!\in_array($array[$key], $resultArray, true)) {
3582 10
                    $resultArray[$key] = $array[$key];
3583
                }
3584
3585 10
                return $resultArray;
3586 11
            },
3587 11
            []
3588
        );
3589
3590 11 View Code Duplication
        if ($this->array === 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...
3591
            $this->array = [];
3592
        } else {
3593 11
            $this->array = (array) $this->array;
3594
        }
3595
3596 11
        return $this;
3597
    }
3598
3599
    /**
3600
     * alias: for "Arrayy->unique()"
3601
     *
3602
     * @return static
3603
     *                <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3604
     *
3605
     * @see Arrayy::unique()
3606
     */
3607 10
    public function uniqueNewIndex(): self
3608
    {
3609 10
        return $this->unique();
3610
    }
3611
3612
    /**
3613
     * Prepends one or more values to the beginning of array at once.
3614
     *
3615
     * @return static
3616
     *                <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3617
     */
3618 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...
3619
    {
3620 4
        if (\func_num_args()) {
3621 4
            $args = \array_merge([&$this->array], \func_get_args());
3622 4
            \array_unshift(...$args);
3623
        }
3624
3625 4
        return $this;
3626
    }
3627
3628
    /**
3629
     * Get all values from a array.
3630
     *
3631
     * @return static
3632
     *                <p>(Immutable)</p>
3633
     */
3634 2
    public function values(): self
3635
    {
3636 2
        return static::create(
3637 2
            \array_values((array) $this->array),
3638 2
            $this->iteratorClass,
3639 2
            false
3640
        );
3641
    }
3642
3643
    /**
3644
     * Apply the given function to every element in the array, discarding the results.
3645
     *
3646
     * @param \callable $callable
3647
     * @param bool      $recursive <p>Whether array will be walked recursively or no</p>
3648
     *
3649
     * @return static
3650
     *                <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3651
     */
3652 37
    public function walk($callable, bool $recursive = false): self
3653
    {
3654 37
        if ($recursive === true) {
3655 32
            \array_walk_recursive($this->array, $callable);
3656
        } else {
3657 18
            \array_walk($this->array, $callable);
3658
        }
3659
3660 37
        return $this;
3661
    }
3662
3663
    /**
3664
     * Convert an array into a object.
3665
     *
3666
     * @param array $array PHP array
3667
     *
3668
     * @return \stdClass
3669
     */
3670 4
    protected static function arrayToObject(array $array = []): \stdClass
3671
    {
3672
        // init
3673 4
        $object = new \stdClass();
3674
3675 4
        if (\count($array, \COUNT_NORMAL) <= 0) {
3676 1
            return $object;
3677
        }
3678
3679 3
        foreach ($array as $name => $value) {
3680 3
            if (\is_array($value)) {
3681 1
                $object->{$name} = self::arrayToObject($value);
3682
            } else {
3683 3
                $object->{$name} = $value;
3684
            }
3685
        }
3686
3687 3
        return $object;
3688
    }
3689
3690
    /**
3691
     * @param array|\Generator|null $input        <p>
3692
     *                                            An array containing keys to return.
3693
     *                                            </p>
3694
     * @param mixed                 $search_value [optional] <p>
3695
     *                                            If specified, then only keys containing these values are returned.
3696
     *                                            </p>
3697
     * @param bool                  $strict       [optional] <p>
3698
     *                                            Determines if strict comparison (===) should be used during the
3699
     *                                            search.
3700
     *                                            </p>
3701
     *
3702
     * @return array
3703
     *               <p>an array of all the keys in input</p>
3704
     */
3705 10
    protected function array_keys_recursive($input = null, $search_value = null, bool $strict = true): array
3706
    {
3707
        // init
3708 10
        $keys = [];
3709 10
        $keysTmp = [[]]; // the inner empty array covers cases when no loops were made
3710
3711 10
        if ($input === null) {
3712
            $input = $this->getGenerator();
3713
        }
3714
3715 10
        foreach ($input as $key => $value) {
3716
            if (
3717 10
                $search_value === null
3718
                ||
3719
                (
3720
                    \is_array($search_value) === true
3721
                    &&
3722 10
                    \in_array($key, $search_value, $strict)
3723
                )
3724
            ) {
3725 10
                $keys[] = $key;
3726
            }
3727
3728
            // check if recursive is needed
3729 10
            if (\is_array($value) === true) {
3730 10
                $keysTmp[] = $this->array_keys_recursive($value);
3731
            }
3732
        }
3733
3734 10
        return \array_merge($keys, ...$keysTmp);
3735
    }
3736
3737
    /**
3738
     * @param mixed      $path
3739
     * @param \callable  $callable
3740
     * @param array|null $currentOffset
3741
     */
3742 4
    protected function callAtPath($path, $callable, &$currentOffset = null)
3743
    {
3744 4
        if ($currentOffset === null) {
3745 4
            $currentOffset = &$this->array;
3746
        }
3747
3748 4
        $explodedPath = \explode($this->pathSeparator, $path);
3749 4
        $nextPath = \array_shift($explodedPath);
3750
3751 4
        if (!isset($currentOffset[$nextPath])) {
3752
            return;
3753
        }
3754
3755 4
        if (!empty($explodedPath)) {
3756 1
            $this->callAtPath(
3757 1
                \implode($this->pathSeparator, $explodedPath),
3758 1
                $callable,
3759 1
                $currentOffset[$nextPath]
3760
            );
3761
        } else {
3762 4
            $callable($currentOffset[$nextPath]);
3763
        }
3764 4
    }
3765
3766
    /**
3767
     * create a fallback for array
3768
     *
3769
     * 1. use the current array, if it's a array
3770
     * 2. fallback to empty array, if there is nothing
3771
     * 3. call "getArray()" on object, if there is a "Arrayy"-object
3772
     * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
3773
     * 5. call "__toArray()" on object, if the method exists
3774
     * 6. cast a string or object with "__toString()" into an array
3775
     * 7. throw a "InvalidArgumentException"-Exception
3776
     *
3777
     * @param mixed $array
3778
     *
3779
     * @throws \InvalidArgumentException
3780
     *
3781
     * @return array
3782
     */
3783 891
    protected function fallbackForArray(&$array): array
3784
    {
3785 891
        if (\is_array($array)) {
3786 888
            return $array;
3787
        }
3788
3789 11
        if (!$array) {
3790 6
            return [];
3791
        }
3792
3793 10
        $isObject = \is_object($array);
3794
3795 10
        if ($isObject && $array instanceof self) {
3796 1
            return $array->getArray();
3797
        }
3798
3799 9
        if ($isObject && $array instanceof \ArrayAccess) {
3800
            return static::createFromObject($array)->getArray();
3801
        }
3802
3803 9
        if ($isObject && $array instanceof \ArrayObject) {
3804
            return $array->getArrayCopy();
3805
        }
3806
3807 9
        if ($isObject && \method_exists($array, '__toArray')) {
3808
            return (array) $array->__toArray();
3809
        }
3810
3811
        if (
3812 9
            \is_string($array)
3813
            ||
3814 9
            ($isObject && \method_exists($array, '__toString'))
3815
        ) {
3816 7
            return [(string) $array];
3817
        }
3818
3819 2
        throw new \InvalidArgumentException(
3820 2
            'Passed value should be a array'
3821
        );
3822
    }
3823
3824
    /**
3825
     * Get correct PHP constant for direction.
3826
     *
3827
     * @param int|string $direction
3828
     *
3829
     * @return int
3830
     */
3831 39
    protected function getDirection($direction): int
3832
    {
3833 39
        if (\is_string($direction)) {
3834 10
            $direction = \strtolower($direction);
3835
3836 10
            if ($direction === 'desc') {
3837 2
                $direction = \SORT_DESC;
3838
            } else {
3839 8
                $direction = \SORT_ASC;
3840
            }
3841
        }
3842
3843
        if (
3844 39
            $direction !== \SORT_DESC
3845
            &&
3846 39
            $direction !== \SORT_ASC
3847
        ) {
3848
            $direction = \SORT_ASC;
3849
        }
3850
3851 39
        return $direction;
3852
    }
3853
3854
    /**
3855
     * @return array|Property[]
3856
     */
3857 10
    protected function getPublicProperties(): array
3858
    {
3859 10
        static $PROPERTY_CACHE = [];
3860 10
        $cacheKey = 'Class::' . static::class;
3861
3862 10
        if (isset($PROPERTY_CACHE[$cacheKey])) {
3863 9
            return $PROPERTY_CACHE[$cacheKey];
3864
        }
3865
3866
        // init
3867 2
        $properties = [];
3868
3869 2
        $reflector = new \ReflectionClass($this);
3870 2
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
3871 2
        $docblock = $factory->create($reflector->getDocComment());
3872 2
        foreach ($docblock->getTagsByName('property') as $tag) {
3873
            /* @var $tag \phpDocumentor\Reflection\DocBlock\Tags\Property */
3874 2
            $properties[$tag->getVariableName()] = Property::fromPhpDocumentorProperty($tag);
3875
        }
3876
3877 2
        return $PROPERTY_CACHE[$cacheKey] = $properties;
3878
    }
3879
3880
    /**
3881
     * @param mixed               $glue
3882
     * @param array|static|string $pieces
3883
     * @param bool                $useKeys
3884
     *
3885
     * @return string
3886
     */
3887 35
    protected function implode_recursive($glue = '', $pieces = [], bool $useKeys = false): string
3888
    {
3889 35
        if ($pieces instanceof self) {
3890 1
            $pieces = $pieces->getArray();
3891
        }
3892
3893 35
        if (\is_array($pieces)) {
3894 35
            $pieces_count = \count($pieces, \COUNT_NORMAL);
3895 35
            $pieces_count_not_zero = $pieces_count > 0;
3896
3897 35
            return \implode(
3898 35
                $glue,
3899 35
                \array_map(
3900 35
                    [$this, 'implode_recursive'],
3901 35
                    \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
3902 35
                    ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
3903
                )
3904
            );
3905
        }
3906
3907 35
        return (string) $pieces;
3908
    }
3909
3910
    /**
3911
     * @param mixed                 $needle   <p>
3912
     *                                        The searched value.
3913
     *                                        </p>
3914
     *                                        <p>
3915
     *                                        If needle is a string, the comparison is done
3916
     *                                        in a case-sensitive manner.
3917
     *                                        </p>
3918
     * @param array|\Generator|null $haystack <p>
3919
     *                                        The array.
3920
     *                                        </p>
3921
     * @param bool                  $strict   [optional] <p>
3922
     *                                        If the third parameter strict is set to true
3923
     *                                        then the in_array function will also check the
3924
     *                                        types of the
3925
     *                                        needle in the haystack.
3926
     *                                        </p>
3927
     *
3928
     * @return bool
3929
     *              <p>true if needle is found in the array, false otherwise</p>
3930
     */
3931 44
    protected function in_array_recursive($needle, $haystack = null, $strict = true): bool
3932
    {
3933 44
        if ($haystack === null) {
3934
            $haystack = $this->getGenerator();
3935
        }
3936
3937 44
        foreach ($haystack as $item) {
3938 36
            if (\is_array($item) === true) {
3939 8
                $returnTmp = $this->in_array_recursive($needle, $item, $strict);
3940
            } else {
3941 36
                $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
3942
            }
3943
3944 36
            if ($returnTmp === true) {
3945 36
                return true;
3946
            }
3947
        }
3948
3949 18
        return false;
3950
    }
3951
3952
    /**
3953
     * @param mixed $value
3954
     */
3955
    protected function internalGetArray(&$value)
3956
    {
3957
        if ($value instanceof self) {
3958
            $valueTmp = $value->getArray();
3959
            if (\count($valueTmp, \COUNT_NORMAL) === 0) {
3960
                $value = [];
3961
            } else {
3962
                /** @noinspection PhpUnusedLocalVariableInspection */
3963
                $value = &$valueTmp;
3964
            }
3965
        }
3966
3967
        /** @noinspection PhpComposerExtensionStubsInspection */
3968
        /** @noinspection NotOptimalIfConditionsInspection */
3969
        if (
3970
            \class_exists('JsonSerializable')
3971
            &&
3972
            $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...
3973
        ) {
3974
3975
            /** @noinspection PhpUnusedLocalVariableInspection */
3976
            $value = &$value->jsonSerialize();
3977
        }
3978
    }
3979
3980
    /**
3981
     * Internal mechanics of remove method.
3982
     *
3983
     * @param mixed $key
3984
     *
3985
     * @return bool
3986
     */
3987 18
    protected function internalRemove($key): bool
3988
    {
3989 18
        $path = \explode($this->pathSeparator, (string) $key);
3990
3991
        // Crawl though the keys
3992 18
        while (\count($path, \COUNT_NORMAL) > 1) {
3993
            $key = \array_shift($path);
3994
3995
            if (!$this->has($key)) {
3996
                return false;
3997
            }
3998
3999
            $this->array = &$this->array[$key];
4000
        }
4001
4002 18
        $key = \array_shift($path);
4003
4004 18
        unset($this->array[$key]);
4005
4006 18
        return true;
4007
    }
4008
4009
    /**
4010
     * Internal mechanic of set method.
4011
     *
4012
     * @param string|null $key
4013
     * @param mixed       $value
4014
     *
4015
     * @return bool
4016
     */
4017 780
    protected function internalSet($key, $value): bool
4018
    {
4019 780
        if ($this->checkPropertyTypes === true) {
4020 8
            if (isset($this->properties[$key]) === false) {
4021
                throw new \InvalidArgumentException('The key ' . $key . ' does not exists as @property in the class (' . \get_class($this) . ').');
4022
            }
4023
4024 8
            $this->properties[$key]->checkType($value);
4025
        }
4026
4027 779
        if ($key === null) {
4028
            return false;
4029
        }
4030
4031
        // init
4032 779
        $array = &$this->array;
4033 779
        $path = \explode($this->pathSeparator, (string) $key);
4034
4035
        // Crawl through the keys
4036 779
        while (\count($path, \COUNT_NORMAL) > 1) {
4037 3
            $key = \array_shift($path);
4038
4039 3
            $array = &$array[$key];
4040
        }
4041
4042 779
        $array[\array_shift($path)] = $value;
4043
4044 779
        return true;
4045
    }
4046
4047
    /**
4048
     * Convert a object into an array.
4049
     *
4050
     * @param object $object
4051
     *
4052
     * @return mixed
4053
     */
4054 5
    protected static function objectToArray($object)
4055
    {
4056 5
        if (!\is_object($object)) {
4057 4
            return $object;
4058
        }
4059
4060 5
        if (\is_object($object)) {
4061 5
            $object = \get_object_vars($object);
4062
        }
4063
4064 5
        return \array_map(['self', 'objectToArray'], $object);
4065
    }
4066
4067
    /**
4068
     * sorting keys
4069
     *
4070
     * @param array      $elements
4071
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4072
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4073
     *                              <strong>SORT_NATURAL</strong></p>
4074
     *
4075
     * @return static
4076
     *                <p>(Mutable) Return this Arrayy object.</p>
4077
     */
4078 18
    protected function sorterKeys(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR): self
4079
    {
4080 18
        $direction = $this->getDirection($direction);
4081
4082
        switch ($direction) {
4083 18
            case 'desc':
4084 18
            case \SORT_DESC:
4085 6
                \krsort($elements, $strategy);
4086
4087 6
                break;
4088 13
            case 'asc':
4089 13
            case \SORT_ASC:
4090
            default:
4091 13
                \ksort($elements, $strategy);
4092
        }
4093
4094 18
        return $this;
4095
    }
4096
4097
    /**
4098
     * @param array      $elements  <p>Warning: used as reference</p>
4099
     * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
4100
     * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
4101
     *                              <strong>SORT_NATURAL</strong></p>
4102
     * @param bool       $keepKeys
4103
     *
4104
     * @return static
4105
     *                <p>(Mutable) Return this Arrayy object.</p>
4106
     */
4107 20
    protected function sorting(array &$elements, $direction = \SORT_ASC, int $strategy = \SORT_REGULAR, bool $keepKeys = false): self
4108
    {
4109 20
        $direction = $this->getDirection($direction);
4110
4111 20
        if (!$strategy) {
4112 20
            $strategy = \SORT_REGULAR;
4113
        }
4114
4115
        switch ($direction) {
4116 20
            case 'desc':
4117 20
            case \SORT_DESC:
4118 9
                if ($keepKeys) {
4119 5
                    \arsort($elements, $strategy);
4120
                } else {
4121 4
                    \rsort($elements, $strategy);
4122
                }
4123
4124 9
                break;
4125 11
            case 'asc':
4126 11
            case \SORT_ASC:
4127
            default:
4128 11
                if ($keepKeys) {
4129 4
                    \asort($elements, $strategy);
4130
                } else {
4131 7
                    \sort($elements, $strategy);
4132
                }
4133
        }
4134
4135 20
        return $this;
4136
    }
4137
}
4138