Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 150 | Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Support;
4
 
5
use ArrayAccess;
6
use ArrayIterator;
7
use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
8
use Illuminate\Support\Traits\EnumeratesValues;
9
use Illuminate\Support\Traits\Macroable;
10
use stdClass;
11
use Traversable;
12
 
13
/**
14
 * @template TKey of array-key
15
 * @template TValue
16
 *
17
 * @implements \ArrayAccess<TKey, TValue>
18
 * @implements \Illuminate\Support\Enumerable<TKey, TValue>
19
 */
20
class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerable
21
{
22
    /**
23
     * @use \Illuminate\Support\Traits\EnumeratesValues<TKey, TValue>
24
     */
25
    use EnumeratesValues, Macroable;
26
 
27
    /**
28
     * The items contained in the collection.
29
     *
30
     * @var array<TKey, TValue>
31
     */
32
    protected $items = [];
33
 
34
    /**
35
     * Create a new collection.
36
     *
37
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>|null  $items
38
     * @return void
39
     */
40
    public function __construct($items = [])
41
    {
42
        $this->items = $this->getArrayableItems($items);
43
    }
44
 
45
    /**
46
     * Create a collection with the given range.
47
     *
48
     * @param  int  $from
49
     * @param  int  $to
50
     * @return static<int, int>
51
     */
52
    public static function range($from, $to)
53
    {
54
        return new static(range($from, $to));
55
    }
56
 
57
    /**
58
     * Get all of the items in the collection.
59
     *
60
     * @return array<TKey, TValue>
61
     */
62
    public function all()
63
    {
64
        return $this->items;
65
    }
66
 
67
    /**
68
     * Get a lazy collection for the items in this collection.
69
     *
70
     * @return \Illuminate\Support\LazyCollection<TKey, TValue>
71
     */
72
    public function lazy()
73
    {
74
        return new LazyCollection($this->items);
75
    }
76
 
77
    /**
78
     * Get the average value of a given key.
79
     *
80
     * @param  (callable(TValue): float|int)|string|null  $callback
81
     * @return float|int|null
82
     */
83
    public function avg($callback = null)
84
    {
85
        $callback = $this->valueRetriever($callback);
86
 
87
        $items = $this->map(function ($value) use ($callback) {
88
            return $callback($value);
89
        })->filter(function ($value) {
90
            return ! is_null($value);
91
        });
92
 
93
        if ($count = $items->count()) {
94
            return $items->sum() / $count;
95
        }
96
    }
97
 
98
    /**
99
     * Get the median of a given key.
100
     *
101
     * @param  string|array<array-key, string>|null  $key
102
     * @return float|int|null
103
     */
104
    public function median($key = null)
105
    {
106
        $values = (isset($key) ? $this->pluck($key) : $this)
107
            ->filter(fn ($item) => ! is_null($item))
108
            ->sort()->values();
109
 
110
        $count = $values->count();
111
 
112
        if ($count === 0) {
113
            return;
114
        }
115
 
116
        $middle = (int) ($count / 2);
117
 
118
        if ($count % 2) {
119
            return $values->get($middle);
120
        }
121
 
122
        return (new static([
123
            $values->get($middle - 1), $values->get($middle),
124
        ]))->average();
125
    }
126
 
127
    /**
128
     * Get the mode of a given key.
129
     *
130
     * @param  string|array<array-key, string>|null  $key
131
     * @return array<int, float|int>|null
132
     */
133
    public function mode($key = null)
134
    {
135
        if ($this->count() === 0) {
136
            return;
137
        }
138
 
139
        $collection = isset($key) ? $this->pluck($key) : $this;
140
 
141
        $counts = new static;
142
 
143
        $collection->each(fn ($value) => $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1);
144
 
145
        $sorted = $counts->sort();
146
 
147
        $highestValue = $sorted->last();
148
 
149
        return $sorted->filter(fn ($value) => $value == $highestValue)
150
            ->sort()->keys()->all();
151
    }
152
 
153
    /**
154
     * Collapse the collection of items into a single array.
155
     *
156
     * @return static<int, mixed>
157
     */
158
    public function collapse()
159
    {
160
        return new static(Arr::collapse($this->items));
161
    }
162
 
163
    /**
164
     * Determine if an item exists in the collection.
165
     *
166
     * @param  (callable(TValue, TKey): bool)|TValue|string  $key
167
     * @param  mixed  $operator
168
     * @param  mixed  $value
169
     * @return bool
170
     */
171
    public function contains($key, $operator = null, $value = null)
172
    {
173
        if (func_num_args() === 1) {
174
            if ($this->useAsCallable($key)) {
175
                $placeholder = new stdClass;
176
 
177
                return $this->first($key, $placeholder) !== $placeholder;
178
            }
179
 
180
            return in_array($key, $this->items);
181
        }
182
 
183
        return $this->contains($this->operatorForWhere(...func_get_args()));
184
    }
185
 
186
    /**
187
     * Determine if an item exists, using strict comparison.
188
     *
189
     * @param  (callable(TValue): bool)|TValue|array-key  $key
190
     * @param  TValue|null  $value
191
     * @return bool
192
     */
193
    public function containsStrict($key, $value = null)
194
    {
195
        if (func_num_args() === 2) {
196
            return $this->contains(fn ($item) => data_get($item, $key) === $value);
197
        }
198
 
199
        if ($this->useAsCallable($key)) {
200
            return ! is_null($this->first($key));
201
        }
202
 
203
        return in_array($key, $this->items, true);
204
    }
205
 
206
    /**
207
     * Determine if an item is not contained in the collection.
208
     *
209
     * @param  mixed  $key
210
     * @param  mixed  $operator
211
     * @param  mixed  $value
212
     * @return bool
213
     */
214
    public function doesntContain($key, $operator = null, $value = null)
215
    {
216
        return ! $this->contains(...func_get_args());
217
    }
218
 
219
    /**
220
     * Cross join with the given lists, returning all possible permutations.
221
     *
222
     * @template TCrossJoinKey
223
     * @template TCrossJoinValue
224
     *
225
     * @param  \Illuminate\Contracts\Support\Arrayable<TCrossJoinKey, TCrossJoinValue>|iterable<TCrossJoinKey, TCrossJoinValue>  ...$lists
226
     * @return static<int, array<int, TValue|TCrossJoinValue>>
227
     */
228
    public function crossJoin(...$lists)
229
    {
230
        return new static(Arr::crossJoin(
231
            $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
232
        ));
233
    }
234
 
235
    /**
236
     * Get the items in the collection that are not present in the given items.
237
     *
238
     * @param  \Illuminate\Contracts\Support\Arrayable<array-key, TValue>|iterable<array-key, TValue>  $items
239
     * @return static
240
     */
241
    public function diff($items)
242
    {
243
        return new static(array_diff($this->items, $this->getArrayableItems($items)));
244
    }
245
 
246
    /**
247
     * Get the items in the collection that are not present in the given items, using the callback.
248
     *
249
     * @param  \Illuminate\Contracts\Support\Arrayable<array-key, TValue>|iterable<array-key, TValue>  $items
250
     * @param  callable(TValue, TValue): int  $callback
251
     * @return static
252
     */
253
    public function diffUsing($items, callable $callback)
254
    {
255
        return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback));
256
    }
257
 
258
    /**
259
     * Get the items in the collection whose keys and values are not present in the given items.
260
     *
261
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
262
     * @return static
263
     */
264
    public function diffAssoc($items)
265
    {
266
        return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));
267
    }
268
 
269
    /**
270
     * Get the items in the collection whose keys and values are not present in the given items, using the callback.
271
     *
272
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
273
     * @param  callable(TKey, TKey): int  $callback
274
     * @return static
275
     */
276
    public function diffAssocUsing($items, callable $callback)
277
    {
278
        return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback));
279
    }
280
 
281
    /**
282
     * Get the items in the collection whose keys are not present in the given items.
283
     *
284
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
285
     * @return static
286
     */
287
    public function diffKeys($items)
288
    {
289
        return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
290
    }
291
 
292
    /**
293
     * Get the items in the collection whose keys are not present in the given items, using the callback.
294
     *
295
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
296
     * @param  callable(TKey, TKey): int  $callback
297
     * @return static
298
     */
299
    public function diffKeysUsing($items, callable $callback)
300
    {
301
        return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));
302
    }
303
 
304
    /**
305
     * Retrieve duplicate items from the collection.
306
     *
307
     * @param  (callable(TValue): bool)|string|null  $callback
308
     * @param  bool  $strict
309
     * @return static
310
     */
311
    public function duplicates($callback = null, $strict = false)
312
    {
313
        $items = $this->map($this->valueRetriever($callback));
314
 
315
        $uniqueItems = $items->unique(null, $strict);
316
 
317
        $compare = $this->duplicateComparator($strict);
318
 
319
        $duplicates = new static;
320
 
321
        foreach ($items as $key => $value) {
322
            if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) {
323
                $uniqueItems->shift();
324
            } else {
325
                $duplicates[$key] = $value;
326
            }
327
        }
328
 
329
        return $duplicates;
330
    }
331
 
332
    /**
333
     * Retrieve duplicate items from the collection using strict comparison.
334
     *
335
     * @param  (callable(TValue): bool)|string|null  $callback
336
     * @return static
337
     */
338
    public function duplicatesStrict($callback = null)
339
    {
340
        return $this->duplicates($callback, true);
341
    }
342
 
343
    /**
344
     * Get the comparison function to detect duplicates.
345
     *
346
     * @param  bool  $strict
347
     * @return callable(TValue, TValue): bool
348
     */
349
    protected function duplicateComparator($strict)
350
    {
351
        if ($strict) {
352
            return function ($a, $b) {
353
                return $a === $b;
354
            };
355
        }
356
 
357
        return function ($a, $b) {
358
            return $a == $b;
359
        };
360
    }
361
 
362
    /**
363
     * Get all items except for those with the specified keys.
364
     *
365
     * @param  \Illuminate\Support\Enumerable<array-key, TKey>|array<array-key, TKey>  $keys
366
     * @return static
367
     */
368
    public function except($keys)
369
    {
370
        if ($keys instanceof Enumerable) {
371
            $keys = $keys->all();
372
        } elseif (! is_array($keys)) {
373
            $keys = func_get_args();
374
        }
375
 
376
        return new static(Arr::except($this->items, $keys));
377
    }
378
 
379
    /**
380
     * Run a filter over each of the items.
381
     *
382
     * @param (callable(TValue, TKey): bool)|null  $callback
383
     * @return static
384
     */
385
    public function filter(callable $callback = null)
386
    {
387
        if ($callback) {
388
            return new static(Arr::where($this->items, $callback));
389
        }
390
 
391
        return new static(array_filter($this->items));
392
    }
393
 
394
    /**
395
     * Get the first item from the collection passing the given truth test.
396
     *
397
     * @template TFirstDefault
398
     *
399
     * @param  (callable(TValue, TKey): bool)|null  $callback
400
     * @param  TFirstDefault|(\Closure(): TFirstDefault)  $default
401
     * @return TValue|TFirstDefault
402
     */
403
    public function first(callable $callback = null, $default = null)
404
    {
405
        return Arr::first($this->items, $callback, $default);
406
    }
407
 
408
    /**
409
     * Get a flattened array of the items in the collection.
410
     *
411
     * @param  int  $depth
412
     * @return static<int, mixed>
413
     */
414
    public function flatten($depth = INF)
415
    {
416
        return new static(Arr::flatten($this->items, $depth));
417
    }
418
 
419
    /**
420
     * Flip the items in the collection.
421
     *
422
     * @return static<TValue, TKey>
423
     */
424
    public function flip()
425
    {
426
        return new static(array_flip($this->items));
427
    }
428
 
429
    /**
430
     * Remove an item from the collection by key.
431
     *
432
     * @param  TKey|array<array-key, TKey>  $keys
433
     * @return $this
434
     */
435
    public function forget($keys)
436
    {
437
        foreach ((array) $keys as $key) {
438
            $this->offsetUnset($key);
439
        }
440
 
441
        return $this;
442
    }
443
 
444
    /**
445
     * Get an item from the collection by key.
446
     *
447
     * @template TGetDefault
448
     *
449
     * @param  TKey  $key
450
     * @param  TGetDefault|(\Closure(): TGetDefault)  $default
451
     * @return TValue|TGetDefault
452
     */
453
    public function get($key, $default = null)
454
    {
455
        if (array_key_exists($key, $this->items)) {
456
            return $this->items[$key];
457
        }
458
 
459
        return value($default);
460
    }
461
 
462
    /**
463
     * Get an item from the collection by key or add it to collection if it does not exist.
464
     *
465
     * @param  mixed  $key
466
     * @param  mixed  $value
467
     * @return mixed
468
     */
469
    public function getOrPut($key, $value)
470
    {
471
        if (array_key_exists($key, $this->items)) {
472
            return $this->items[$key];
473
        }
474
 
475
        $this->offsetSet($key, $value = value($value));
476
 
477
        return $value;
478
    }
479
 
480
    /**
481
     * Group an associative array by a field or using a callback.
482
     *
483
     * @param  (callable(TValue, TKey): array-key)|array|string  $groupBy
484
     * @param  bool  $preserveKeys
485
     * @return static<array-key, static<array-key, TValue>>
486
     */
487
    public function groupBy($groupBy, $preserveKeys = false)
488
    {
489
        if (! $this->useAsCallable($groupBy) && is_array($groupBy)) {
490
            $nextGroups = $groupBy;
491
 
492
            $groupBy = array_shift($nextGroups);
493
        }
494
 
495
        $groupBy = $this->valueRetriever($groupBy);
496
 
497
        $results = [];
498
 
499
        foreach ($this->items as $key => $value) {
500
            $groupKeys = $groupBy($value, $key);
501
 
502
            if (! is_array($groupKeys)) {
503
                $groupKeys = [$groupKeys];
504
            }
505
 
506
            foreach ($groupKeys as $groupKey) {
507
                $groupKey = match (true) {
508
                    is_bool($groupKey) => (int) $groupKey,
509
                    $groupKey instanceof \Stringable => (string) $groupKey,
510
                    default => $groupKey,
511
                };
512
 
513
                if (! array_key_exists($groupKey, $results)) {
514
                    $results[$groupKey] = new static;
515
                }
516
 
517
                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
518
            }
519
        }
520
 
521
        $result = new static($results);
522
 
523
        if (! empty($nextGroups)) {
524
            return $result->map->groupBy($nextGroups, $preserveKeys);
525
        }
526
 
527
        return $result;
528
    }
529
 
530
    /**
531
     * Key an associative array by a field or using a callback.
532
     *
533
     * @param  (callable(TValue, TKey): array-key)|array|string  $keyBy
534
     * @return static<array-key, TValue>
535
     */
536
    public function keyBy($keyBy)
537
    {
538
        $keyBy = $this->valueRetriever($keyBy);
539
 
540
        $results = [];
541
 
542
        foreach ($this->items as $key => $item) {
543
            $resolvedKey = $keyBy($item, $key);
544
 
545
            if (is_object($resolvedKey)) {
546
                $resolvedKey = (string) $resolvedKey;
547
            }
548
 
549
            $results[$resolvedKey] = $item;
550
        }
551
 
552
        return new static($results);
553
    }
554
 
555
    /**
556
     * Determine if an item exists in the collection by key.
557
     *
558
     * @param  TKey|array<array-key, TKey>  $key
559
     * @return bool
560
     */
561
    public function has($key)
562
    {
563
        $keys = is_array($key) ? $key : func_get_args();
564
 
565
        foreach ($keys as $value) {
566
            if (! array_key_exists($value, $this->items)) {
567
                return false;
568
            }
569
        }
570
 
571
        return true;
572
    }
573
 
574
    /**
575
     * Determine if any of the keys exist in the collection.
576
     *
577
     * @param  mixed  $key
578
     * @return bool
579
     */
580
    public function hasAny($key)
581
    {
582
        if ($this->isEmpty()) {
583
            return false;
584
        }
585
 
586
        $keys = is_array($key) ? $key : func_get_args();
587
 
588
        foreach ($keys as $value) {
589
            if ($this->has($value)) {
590
                return true;
591
            }
592
        }
593
 
594
        return false;
595
    }
596
 
597
    /**
598
     * Concatenate values of a given key as a string.
599
     *
600
     * @param  callable|string  $value
601
     * @param  string|null  $glue
602
     * @return string
603
     */
604
    public function implode($value, $glue = null)
605
    {
606
        if ($this->useAsCallable($value)) {
607
            return implode($glue ?? '', $this->map($value)->all());
608
        }
609
 
610
        $first = $this->first();
611
 
612
        if (is_array($first) || (is_object($first) && ! $first instanceof Stringable)) {
613
            return implode($glue ?? '', $this->pluck($value)->all());
614
        }
615
 
616
        return implode($value ?? '', $this->items);
617
    }
618
 
619
    /**
620
     * Intersect the collection with the given items.
621
     *
622
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
623
     * @return static
624
     */
625
    public function intersect($items)
626
    {
627
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
628
    }
629
 
630
    /**
631
     * Intersect the collection with the given items by key.
632
     *
633
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
634
     * @return static
635
     */
636
    public function intersectByKeys($items)
637
    {
638
        return new static(array_intersect_key(
639
            $this->items, $this->getArrayableItems($items)
640
        ));
641
    }
642
 
643
    /**
644
     * Determine if the collection is empty or not.
645
     *
646
     * @return bool
647
     */
648
    public function isEmpty()
649
    {
650
        return empty($this->items);
651
    }
652
 
653
    /**
654
     * Determine if the collection contains a single item.
655
     *
656
     * @return bool
657
     */
658
    public function containsOneItem()
659
    {
660
        return $this->count() === 1;
661
    }
662
 
663
    /**
664
     * Join all items from the collection using a string. The final items can use a separate glue string.
665
     *
666
     * @param  string  $glue
667
     * @param  string  $finalGlue
668
     * @return string
669
     */
670
    public function join($glue, $finalGlue = '')
671
    {
672
        if ($finalGlue === '') {
673
            return $this->implode($glue);
674
        }
675
 
676
        $count = $this->count();
677
 
678
        if ($count === 0) {
679
            return '';
680
        }
681
 
682
        if ($count === 1) {
683
            return $this->last();
684
        }
685
 
686
        $collection = new static($this->items);
687
 
688
        $finalItem = $collection->pop();
689
 
690
        return $collection->implode($glue).$finalGlue.$finalItem;
691
    }
692
 
693
    /**
694
     * Get the keys of the collection items.
695
     *
696
     * @return static<int, TKey>
697
     */
698
    public function keys()
699
    {
700
        return new static(array_keys($this->items));
701
    }
702
 
703
    /**
704
     * Get the last item from the collection.
705
     *
706
     * @template TLastDefault
707
     *
708
     * @param  (callable(TValue, TKey): bool)|null  $callback
709
     * @param  TLastDefault|(\Closure(): TLastDefault)  $default
710
     * @return TValue|TLastDefault
711
     */
712
    public function last(callable $callback = null, $default = null)
713
    {
714
        return Arr::last($this->items, $callback, $default);
715
    }
716
 
717
    /**
718
     * Get the values of a given key.
719
     *
720
     * @param  string|int|array<array-key, string>  $value
721
     * @param  string|null  $key
722
     * @return static<array-key, mixed>
723
     */
724
    public function pluck($value, $key = null)
725
    {
726
        return new static(Arr::pluck($this->items, $value, $key));
727
    }
728
 
729
    /**
730
     * Run a map over each of the items.
731
     *
732
     * @template TMapValue
733
     *
734
     * @param  callable(TValue, TKey): TMapValue  $callback
735
     * @return static<TKey, TMapValue>
736
     */
737
    public function map(callable $callback)
738
    {
739
        return new static(Arr::map($this->items, $callback));
740
    }
741
 
742
    /**
743
     * Run a dictionary map over the items.
744
     *
745
     * The callback should return an associative array with a single key/value pair.
746
     *
747
     * @template TMapToDictionaryKey of array-key
748
     * @template TMapToDictionaryValue
749
     *
750
     * @param  callable(TValue, TKey): array<TMapToDictionaryKey, TMapToDictionaryValue>  $callback
751
     * @return static<TMapToDictionaryKey, array<int, TMapToDictionaryValue>>
752
     */
753
    public function mapToDictionary(callable $callback)
754
    {
755
        $dictionary = [];
756
 
757
        foreach ($this->items as $key => $item) {
758
            $pair = $callback($item, $key);
759
 
760
            $key = key($pair);
761
 
762
            $value = reset($pair);
763
 
764
            if (! isset($dictionary[$key])) {
765
                $dictionary[$key] = [];
766
            }
767
 
768
            $dictionary[$key][] = $value;
769
        }
770
 
771
        return new static($dictionary);
772
    }
773
 
774
    /**
775
     * Run an associative map over each of the items.
776
     *
777
     * The callback should return an associative array with a single key/value pair.
778
     *
779
     * @template TMapWithKeysKey of array-key
780
     * @template TMapWithKeysValue
781
     *
782
     * @param  callable(TValue, TKey): array<TMapWithKeysKey, TMapWithKeysValue>  $callback
783
     * @return static<TMapWithKeysKey, TMapWithKeysValue>
784
     */
785
    public function mapWithKeys(callable $callback)
786
    {
787
        $result = [];
788
 
789
        foreach ($this->items as $key => $value) {
790
            $assoc = $callback($value, $key);
791
 
792
            foreach ($assoc as $mapKey => $mapValue) {
793
                $result[$mapKey] = $mapValue;
794
            }
795
        }
796
 
797
        return new static($result);
798
    }
799
 
800
    /**
801
     * Merge the collection with the given items.
802
     *
803
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
804
     * @return static
805
     */
806
    public function merge($items)
807
    {
808
        return new static(array_merge($this->items, $this->getArrayableItems($items)));
809
    }
810
 
811
    /**
812
     * Recursively merge the collection with the given items.
813
     *
814
     * @template TMergeRecursiveValue
815
     *
816
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TMergeRecursiveValue>|iterable<TKey, TMergeRecursiveValue>  $items
817
     * @return static<TKey, TValue|TMergeRecursiveValue>
818
     */
819
    public function mergeRecursive($items)
820
    {
821
        return new static(array_merge_recursive($this->items, $this->getArrayableItems($items)));
822
    }
823
 
824
    /**
825
     * Create a collection by using this collection for keys and another for its values.
826
     *
827
     * @template TCombineValue
828
     *
829
     * @param  \Illuminate\Contracts\Support\Arrayable<array-key, TCombineValue>|iterable<array-key, TCombineValue>  $values
830
     * @return static<TValue, TCombineValue>
831
     */
832
    public function combine($values)
833
    {
834
        return new static(array_combine($this->all(), $this->getArrayableItems($values)));
835
    }
836
 
837
    /**
838
     * Union the collection with the given items.
839
     *
840
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
841
     * @return static
842
     */
843
    public function union($items)
844
    {
845
        return new static($this->items + $this->getArrayableItems($items));
846
    }
847
 
848
    /**
849
     * Create a new collection consisting of every n-th element.
850
     *
851
     * @param  int  $step
852
     * @param  int  $offset
853
     * @return static
854
     */
855
    public function nth($step, $offset = 0)
856
    {
857
        $new = [];
858
 
859
        $position = 0;
860
 
861
        foreach ($this->slice($offset)->items as $item) {
862
            if ($position % $step === 0) {
863
                $new[] = $item;
864
            }
865
 
866
            $position++;
867
        }
868
 
869
        return new static($new);
870
    }
871
 
872
    /**
873
     * Get the items with the specified keys.
874
     *
875
     * @param  \Illuminate\Support\Enumerable<array-key, TKey>|array<array-key, TKey>|string  $keys
876
     * @return static
877
     */
878
    public function only($keys)
879
    {
880
        if (is_null($keys)) {
881
            return new static($this->items);
882
        }
883
 
884
        if ($keys instanceof Enumerable) {
885
            $keys = $keys->all();
886
        }
887
 
888
        $keys = is_array($keys) ? $keys : func_get_args();
889
 
890
        return new static(Arr::only($this->items, $keys));
891
    }
892
 
893
    /**
894
     * Get and remove the last N items from the collection.
895
     *
896
     * @param  int  $count
897
     * @return static<int, TValue>|TValue|null
898
     */
899
    public function pop($count = 1)
900
    {
901
        if ($count === 1) {
902
            return array_pop($this->items);
903
        }
904
 
905
        if ($this->isEmpty()) {
906
            return new static;
907
        }
908
 
909
        $results = [];
910
 
911
        $collectionCount = $this->count();
912
 
913
        foreach (range(1, min($count, $collectionCount)) as $item) {
914
            array_push($results, array_pop($this->items));
915
        }
916
 
917
        return new static($results);
918
    }
919
 
920
    /**
921
     * Push an item onto the beginning of the collection.
922
     *
923
     * @param  TValue  $value
924
     * @param  TKey  $key
925
     * @return $this
926
     */
927
    public function prepend($value, $key = null)
928
    {
929
        $this->items = Arr::prepend($this->items, ...func_get_args());
930
 
931
        return $this;
932
    }
933
 
934
    /**
935
     * Push one or more items onto the end of the collection.
936
     *
937
     * @param  TValue  ...$values
938
     * @return $this
939
     */
940
    public function push(...$values)
941
    {
942
        foreach ($values as $value) {
943
            $this->items[] = $value;
944
        }
945
 
946
        return $this;
947
    }
948
 
949
    /**
950
     * Push all of the given items onto the collection.
951
     *
952
     * @param  iterable<array-key, TValue>  $source
953
     * @return static
954
     */
955
    public function concat($source)
956
    {
957
        $result = new static($this);
958
 
959
        foreach ($source as $item) {
960
            $result->push($item);
961
        }
962
 
963
        return $result;
964
    }
965
 
966
    /**
967
     * Get and remove an item from the collection.
968
     *
969
     * @template TPullDefault
970
     *
971
     * @param  TKey  $key
972
     * @param  TPullDefault|(\Closure(): TPullDefault)  $default
973
     * @return TValue|TPullDefault
974
     */
975
    public function pull($key, $default = null)
976
    {
977
        return Arr::pull($this->items, $key, $default);
978
    }
979
 
980
    /**
981
     * Put an item in the collection by key.
982
     *
983
     * @param  TKey  $key
984
     * @param  TValue  $value
985
     * @return $this
986
     */
987
    public function put($key, $value)
988
    {
989
        $this->offsetSet($key, $value);
990
 
991
        return $this;
992
    }
993
 
994
    /**
995
     * Get one or a specified number of items randomly from the collection.
996
     *
997
     * @param  (callable(self<TKey, TValue>): int)|int|null  $number
998
     * @return static<int, TValue>|TValue
999
     *
1000
     * @throws \InvalidArgumentException
1001
     */
1002
    public function random($number = null)
1003
    {
1004
        if (is_null($number)) {
1005
            return Arr::random($this->items);
1006
        }
1007
 
1008
        if (is_callable($number)) {
1009
            return new static(Arr::random($this->items, $number($this)));
1010
        }
1011
 
1012
        return new static(Arr::random($this->items, $number));
1013
    }
1014
 
1015
    /**
1016
     * Replace the collection items with the given items.
1017
     *
1018
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
1019
     * @return static
1020
     */
1021
    public function replace($items)
1022
    {
1023
        return new static(array_replace($this->items, $this->getArrayableItems($items)));
1024
    }
1025
 
1026
    /**
1027
     * Recursively replace the collection items with the given items.
1028
     *
1029
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
1030
     * @return static
1031
     */
1032
    public function replaceRecursive($items)
1033
    {
1034
        return new static(array_replace_recursive($this->items, $this->getArrayableItems($items)));
1035
    }
1036
 
1037
    /**
1038
     * Reverse items order.
1039
     *
1040
     * @return static
1041
     */
1042
    public function reverse()
1043
    {
1044
        return new static(array_reverse($this->items, true));
1045
    }
1046
 
1047
    /**
1048
     * Search the collection for a given value and return the corresponding key if successful.
1049
     *
1050
     * @param  TValue|(callable(TValue,TKey): bool)  $value
1051
     * @param  bool  $strict
1052
     * @return TKey|bool
1053
     */
1054
    public function search($value, $strict = false)
1055
    {
1056
        if (! $this->useAsCallable($value)) {
1057
            return array_search($value, $this->items, $strict);
1058
        }
1059
 
1060
        foreach ($this->items as $key => $item) {
1061
            if ($value($item, $key)) {
1062
                return $key;
1063
            }
1064
        }
1065
 
1066
        return false;
1067
    }
1068
 
1069
    /**
1070
     * Get and remove the first N items from the collection.
1071
     *
1072
     * @param  int  $count
1073
     * @return static<int, TValue>|TValue|null
1074
     */
1075
    public function shift($count = 1)
1076
    {
1077
        if ($count === 1) {
1078
            return array_shift($this->items);
1079
        }
1080
 
1081
        if ($this->isEmpty()) {
1082
            return new static;
1083
        }
1084
 
1085
        $results = [];
1086
 
1087
        $collectionCount = $this->count();
1088
 
1089
        foreach (range(1, min($count, $collectionCount)) as $item) {
1090
            array_push($results, array_shift($this->items));
1091
        }
1092
 
1093
        return new static($results);
1094
    }
1095
 
1096
    /**
1097
     * Shuffle the items in the collection.
1098
     *
1099
     * @param  int|null  $seed
1100
     * @return static
1101
     */
1102
    public function shuffle($seed = null)
1103
    {
1104
        return new static(Arr::shuffle($this->items, $seed));
1105
    }
1106
 
1107
    /**
1108
     * Create chunks representing a "sliding window" view of the items in the collection.
1109
     *
1110
     * @param  int  $size
1111
     * @param  int  $step
1112
     * @return static<int, static>
1113
     */
1114
    public function sliding($size = 2, $step = 1)
1115
    {
1116
        $chunks = floor(($this->count() - $size) / $step) + 1;
1117
 
1118
        return static::times($chunks, function ($number) use ($size, $step) {
1119
            return $this->slice(($number - 1) * $step, $size);
1120
        });
1121
    }
1122
 
1123
    /**
1124
     * Skip the first {$count} items.
1125
     *
1126
     * @param  int  $count
1127
     * @return static
1128
     */
1129
    public function skip($count)
1130
    {
1131
        return $this->slice($count);
1132
    }
1133
 
1134
    /**
1135
     * Skip items in the collection until the given condition is met.
1136
     *
1137
     * @param  TValue|callable(TValue,TKey): bool  $value
1138
     * @return static
1139
     */
1140
    public function skipUntil($value)
1141
    {
1142
        return new static($this->lazy()->skipUntil($value)->all());
1143
    }
1144
 
1145
    /**
1146
     * Skip items in the collection while the given condition is met.
1147
     *
1148
     * @param  TValue|callable(TValue,TKey): bool  $value
1149
     * @return static
1150
     */
1151
    public function skipWhile($value)
1152
    {
1153
        return new static($this->lazy()->skipWhile($value)->all());
1154
    }
1155
 
1156
    /**
1157
     * Slice the underlying collection array.
1158
     *
1159
     * @param  int  $offset
1160
     * @param  int|null  $length
1161
     * @return static
1162
     */
1163
    public function slice($offset, $length = null)
1164
    {
1165
        return new static(array_slice($this->items, $offset, $length, true));
1166
    }
1167
 
1168
    /**
1169
     * Split a collection into a certain number of groups.
1170
     *
1171
     * @param  int  $numberOfGroups
1172
     * @return static<int, static>
1173
     */
1174
    public function split($numberOfGroups)
1175
    {
1176
        if ($this->isEmpty()) {
1177
            return new static;
1178
        }
1179
 
1180
        $groups = new static;
1181
 
1182
        $groupSize = floor($this->count() / $numberOfGroups);
1183
 
1184
        $remain = $this->count() % $numberOfGroups;
1185
 
1186
        $start = 0;
1187
 
1188
        for ($i = 0; $i < $numberOfGroups; $i++) {
1189
            $size = $groupSize;
1190
 
1191
            if ($i < $remain) {
1192
                $size++;
1193
            }
1194
 
1195
            if ($size) {
1196
                $groups->push(new static(array_slice($this->items, $start, $size)));
1197
 
1198
                $start += $size;
1199
            }
1200
        }
1201
 
1202
        return $groups;
1203
    }
1204
 
1205
    /**
1206
     * Split a collection into a certain number of groups, and fill the first groups completely.
1207
     *
1208
     * @param  int  $numberOfGroups
1209
     * @return static<int, static>
1210
     */
1211
    public function splitIn($numberOfGroups)
1212
    {
1213
        return $this->chunk(ceil($this->count() / $numberOfGroups));
1214
    }
1215
 
1216
    /**
1217
     * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception.
1218
     *
1219
     * @param  (callable(TValue, TKey): bool)|string  $key
1220
     * @param  mixed  $operator
1221
     * @param  mixed  $value
1222
     * @return TValue
1223
     *
1224
     * @throws \Illuminate\Support\ItemNotFoundException
1225
     * @throws \Illuminate\Support\MultipleItemsFoundException
1226
     */
1227
    public function sole($key = null, $operator = null, $value = null)
1228
    {
1229
        $filter = func_num_args() > 1
1230
            ? $this->operatorForWhere(...func_get_args())
1231
            : $key;
1232
 
1233
        $items = $this->unless($filter == null)->filter($filter);
1234
 
1235
        $count = $items->count();
1236
 
1237
        if ($count === 0) {
1238
            throw new ItemNotFoundException;
1239
        }
1240
 
1241
        if ($count > 1) {
1242
            throw new MultipleItemsFoundException($count);
1243
        }
1244
 
1245
        return $items->first();
1246
    }
1247
 
1248
    /**
1249
     * Get the first item in the collection but throw an exception if no matching items exist.
1250
     *
1251
     * @param  (callable(TValue, TKey): bool)|string  $key
1252
     * @param  mixed  $operator
1253
     * @param  mixed  $value
1254
     * @return TValue
1255
     *
1256
     * @throws \Illuminate\Support\ItemNotFoundException
1257
     */
1258
    public function firstOrFail($key = null, $operator = null, $value = null)
1259
    {
1260
        $filter = func_num_args() > 1
1261
            ? $this->operatorForWhere(...func_get_args())
1262
            : $key;
1263
 
1264
        $placeholder = new stdClass();
1265
 
1266
        $item = $this->first($filter, $placeholder);
1267
 
1268
        if ($item === $placeholder) {
1269
            throw new ItemNotFoundException;
1270
        }
1271
 
1272
        return $item;
1273
    }
1274
 
1275
    /**
1276
     * Chunk the collection into chunks of the given size.
1277
     *
1278
     * @param  int  $size
1279
     * @return static<int, static>
1280
     */
1281
    public function chunk($size)
1282
    {
1283
        if ($size <= 0) {
1284
            return new static;
1285
        }
1286
 
1287
        $chunks = [];
1288
 
1289
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1290
            $chunks[] = new static($chunk);
1291
        }
1292
 
1293
        return new static($chunks);
1294
    }
1295
 
1296
    /**
1297
     * Chunk the collection into chunks with a callback.
1298
     *
1299
     * @param  callable(TValue, TKey, static<int, TValue>): bool  $callback
1300
     * @return static<int, static<int, TValue>>
1301
     */
1302
    public function chunkWhile(callable $callback)
1303
    {
1304
        return new static(
1305
            $this->lazy()->chunkWhile($callback)->mapInto(static::class)
1306
        );
1307
    }
1308
 
1309
    /**
1310
     * Sort through each item with a callback.
1311
     *
1312
     * @param  (callable(TValue, TValue): int)|null|int  $callback
1313
     * @return static
1314
     */
1315
    public function sort($callback = null)
1316
    {
1317
        $items = $this->items;
1318
 
1319
        $callback && is_callable($callback)
1320
            ? uasort($items, $callback)
1321
            : asort($items, $callback ?? SORT_REGULAR);
1322
 
1323
        return new static($items);
1324
    }
1325
 
1326
    /**
1327
     * Sort items in descending order.
1328
     *
1329
     * @param  int  $options
1330
     * @return static
1331
     */
1332
    public function sortDesc($options = SORT_REGULAR)
1333
    {
1334
        $items = $this->items;
1335
 
1336
        arsort($items, $options);
1337
 
1338
        return new static($items);
1339
    }
1340
 
1341
    /**
1342
     * Sort the collection using the given callback.
1343
     *
1344
     * @param  array<array-key, (callable(TValue, TValue): mixed)|(callable(TValue, TKey): mixed)|string|array{string, string}>|(callable(TValue, TKey): mixed)|string  $callback
1345
     * @param  int  $options
1346
     * @param  bool  $descending
1347
     * @return static
1348
     */
1349
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1350
    {
1351
        if (is_array($callback) && ! is_callable($callback)) {
1352
            return $this->sortByMany($callback);
1353
        }
1354
 
1355
        $results = [];
1356
 
1357
        $callback = $this->valueRetriever($callback);
1358
 
1359
        // First we will loop through the items and get the comparator from a callback
1360
        // function which we were given. Then, we will sort the returned values and
1361
        // grab all the corresponding values for the sorted keys from this array.
1362
        foreach ($this->items as $key => $value) {
1363
            $results[$key] = $callback($value, $key);
1364
        }
1365
 
1366
        $descending ? arsort($results, $options)
1367
            : asort($results, $options);
1368
 
1369
        // Once we have sorted all of the keys in the array, we will loop through them
1370
        // and grab the corresponding model so we can set the underlying items list
1371
        // to the sorted version. Then we'll just return the collection instance.
1372
        foreach (array_keys($results) as $key) {
1373
            $results[$key] = $this->items[$key];
1374
        }
1375
 
1376
        return new static($results);
1377
    }
1378
 
1379
    /**
1380
     * Sort the collection using multiple comparisons.
1381
     *
1382
     * @param  array<array-key, (callable(TValue, TValue): mixed)|(callable(TValue, TKey): mixed)|string|array{string, string}>  $comparisons
1383
     * @return static
1384
     */
1385
    protected function sortByMany(array $comparisons = [])
1386
    {
1387
        $items = $this->items;
1388
 
1389
        uasort($items, function ($a, $b) use ($comparisons) {
1390
            foreach ($comparisons as $comparison) {
1391
                $comparison = Arr::wrap($comparison);
1392
 
1393
                $prop = $comparison[0];
1394
 
1395
                $ascending = Arr::get($comparison, 1, true) === true ||
1396
                             Arr::get($comparison, 1, true) === 'asc';
1397
 
1398
                if (! is_string($prop) && is_callable($prop)) {
1399
                    $result = $prop($a, $b);
1400
                } else {
1401
                    $values = [data_get($a, $prop), data_get($b, $prop)];
1402
 
1403
                    if (! $ascending) {
1404
                        $values = array_reverse($values);
1405
                    }
1406
 
1407
                    $result = $values[0] <=> $values[1];
1408
                }
1409
 
1410
                if ($result === 0) {
1411
                    continue;
1412
                }
1413
 
1414
                return $result;
1415
            }
1416
        });
1417
 
1418
        return new static($items);
1419
    }
1420
 
1421
    /**
1422
     * Sort the collection in descending order using the given callback.
1423
     *
1424
     * @param  array<array-key, (callable(TValue, TValue): mixed)|(callable(TValue, TKey): mixed)|string|array{string, string}>|(callable(TValue, TKey): mixed)|string  $callback
1425
     * @param  int  $options
1426
     * @return static
1427
     */
1428
    public function sortByDesc($callback, $options = SORT_REGULAR)
1429
    {
1430
        return $this->sortBy($callback, $options, true);
1431
    }
1432
 
1433
    /**
1434
     * Sort the collection keys.
1435
     *
1436
     * @param  int  $options
1437
     * @param  bool  $descending
1438
     * @return static
1439
     */
1440
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1441
    {
1442
        $items = $this->items;
1443
 
1444
        $descending ? krsort($items, $options) : ksort($items, $options);
1445
 
1446
        return new static($items);
1447
    }
1448
 
1449
    /**
1450
     * Sort the collection keys in descending order.
1451
     *
1452
     * @param  int  $options
1453
     * @return static
1454
     */
1455
    public function sortKeysDesc($options = SORT_REGULAR)
1456
    {
1457
        return $this->sortKeys($options, true);
1458
    }
1459
 
1460
    /**
1461
     * Sort the collection keys using a callback.
1462
     *
1463
     * @param  callable(TKey, TKey): int  $callback
1464
     * @return static
1465
     */
1466
    public function sortKeysUsing(callable $callback)
1467
    {
1468
        $items = $this->items;
1469
 
1470
        uksort($items, $callback);
1471
 
1472
        return new static($items);
1473
    }
1474
 
1475
    /**
1476
     * Splice a portion of the underlying collection array.
1477
     *
1478
     * @param  int  $offset
1479
     * @param  int|null  $length
1480
     * @param  array<array-key, TValue>  $replacement
1481
     * @return static
1482
     */
1483
    public function splice($offset, $length = null, $replacement = [])
1484
    {
1485
        if (func_num_args() === 1) {
1486
            return new static(array_splice($this->items, $offset));
1487
        }
1488
 
1489
        return new static(array_splice($this->items, $offset, $length, $this->getArrayableItems($replacement)));
1490
    }
1491
 
1492
    /**
1493
     * Take the first or last {$limit} items.
1494
     *
1495
     * @param  int  $limit
1496
     * @return static
1497
     */
1498
    public function take($limit)
1499
    {
1500
        if ($limit < 0) {
1501
            return $this->slice($limit, abs($limit));
1502
        }
1503
 
1504
        return $this->slice(0, $limit);
1505
    }
1506
 
1507
    /**
1508
     * Take items in the collection until the given condition is met.
1509
     *
1510
     * @param  TValue|callable(TValue,TKey): bool  $value
1511
     * @return static
1512
     */
1513
    public function takeUntil($value)
1514
    {
1515
        return new static($this->lazy()->takeUntil($value)->all());
1516
    }
1517
 
1518
    /**
1519
     * Take items in the collection while the given condition is met.
1520
     *
1521
     * @param  TValue|callable(TValue,TKey): bool  $value
1522
     * @return static
1523
     */
1524
    public function takeWhile($value)
1525
    {
1526
        return new static($this->lazy()->takeWhile($value)->all());
1527
    }
1528
 
1529
    /**
1530
     * Transform each item in the collection using a callback.
1531
     *
1532
     * @param  callable(TValue, TKey): TValue  $callback
1533
     * @return $this
1534
     */
1535
    public function transform(callable $callback)
1536
    {
1537
        $this->items = $this->map($callback)->all();
1538
 
1539
        return $this;
1540
    }
1541
 
1542
    /**
1543
     * Convert a flatten "dot" notation array into an expanded array.
1544
     *
1545
     * @return static
1546
     */
1547
    public function undot()
1548
    {
1549
        return new static(Arr::undot($this->all()));
1550
    }
1551
 
1552
    /**
1553
     * Return only unique items from the collection array.
1554
     *
1555
     * @param  (callable(TValue, TKey): mixed)|string|null  $key
1556
     * @param  bool  $strict
1557
     * @return static
1558
     */
1559
    public function unique($key = null, $strict = false)
1560
    {
1561
        if (is_null($key) && $strict === false) {
1562
            return new static(array_unique($this->items, SORT_REGULAR));
1563
        }
1564
 
1565
        $callback = $this->valueRetriever($key);
1566
 
1567
        $exists = [];
1568
 
1569
        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
1570
            if (in_array($id = $callback($item, $key), $exists, $strict)) {
1571
                return true;
1572
            }
1573
 
1574
            $exists[] = $id;
1575
        });
1576
    }
1577
 
1578
    /**
1579
     * Reset the keys on the underlying array.
1580
     *
1581
     * @return static<int, TValue>
1582
     */
1583
    public function values()
1584
    {
1585
        return new static(array_values($this->items));
1586
    }
1587
 
1588
    /**
1589
     * Zip the collection together with one or more arrays.
1590
     *
1591
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1592
     *      => [[1, 4], [2, 5], [3, 6]]
1593
     *
1594
     * @template TZipValue
1595
     *
1596
     * @param  \Illuminate\Contracts\Support\Arrayable<array-key, TZipValue>|iterable<array-key, TZipValue>  ...$items
1597
     * @return static<int, static<int, TValue|TZipValue>>
1598
     */
1599
    public function zip($items)
1600
    {
1601
        $arrayableItems = array_map(function ($items) {
1602
            return $this->getArrayableItems($items);
1603
        }, func_get_args());
1604
 
1605
        $params = array_merge([function () {
1606
            return new static(func_get_args());
1607
        }, $this->items], $arrayableItems);
1608
 
1609
        return new static(array_map(...$params));
1610
    }
1611
 
1612
    /**
1613
     * Pad collection to the specified length with a value.
1614
     *
1615
     * @template TPadValue
1616
     *
1617
     * @param  int  $size
1618
     * @param  TPadValue  $value
1619
     * @return static<int, TValue|TPadValue>
1620
     */
1621
    public function pad($size, $value)
1622
    {
1623
        return new static(array_pad($this->items, $size, $value));
1624
    }
1625
 
1626
    /**
1627
     * Get an iterator for the items.
1628
     *
1629
     * @return \ArrayIterator<TKey, TValue>
1630
     */
1631
    public function getIterator(): Traversable
1632
    {
1633
        return new ArrayIterator($this->items);
1634
    }
1635
 
1636
    /**
1637
     * Count the number of items in the collection.
1638
     *
1639
     * @return int
1640
     */
1641
    public function count(): int
1642
    {
1643
        return count($this->items);
1644
    }
1645
 
1646
    /**
1647
     * Count the number of items in the collection by a field or using a callback.
1648
     *
1649
     * @param  (callable(TValue, TKey): mixed)|string|null  $countBy
1650
     * @return static<array-key, int>
1651
     */
1652
    public function countBy($countBy = null)
1653
    {
1654
        return new static($this->lazy()->countBy($countBy)->all());
1655
    }
1656
 
1657
    /**
1658
     * Add an item to the collection.
1659
     *
1660
     * @param  TValue  $item
1661
     * @return $this
1662
     */
1663
    public function add($item)
1664
    {
1665
        $this->items[] = $item;
1666
 
1667
        return $this;
1668
    }
1669
 
1670
    /**
1671
     * Get a base Support collection instance from this collection.
1672
     *
1673
     * @return \Illuminate\Support\Collection<TKey, TValue>
1674
     */
1675
    public function toBase()
1676
    {
1677
        return new self($this);
1678
    }
1679
 
1680
    /**
1681
     * Determine if an item exists at an offset.
1682
     *
1683
     * @param  TKey  $key
1684
     * @return bool
1685
     */
1686
    public function offsetExists($key): bool
1687
    {
1688
        return isset($this->items[$key]);
1689
    }
1690
 
1691
    /**
1692
     * Get an item at a given offset.
1693
     *
1694
     * @param  TKey  $key
1695
     * @return TValue
1696
     */
1697
    public function offsetGet($key): mixed
1698
    {
1699
        return $this->items[$key];
1700
    }
1701
 
1702
    /**
1703
     * Set the item at a given offset.
1704
     *
1705
     * @param  TKey|null  $key
1706
     * @param  TValue  $value
1707
     * @return void
1708
     */
1709
    public function offsetSet($key, $value): void
1710
    {
1711
        if (is_null($key)) {
1712
            $this->items[] = $value;
1713
        } else {
1714
            $this->items[$key] = $value;
1715
        }
1716
    }
1717
 
1718
    /**
1719
     * Unset the item at a given offset.
1720
     *
1721
     * @param  TKey  $key
1722
     * @return void
1723
     */
1724
    public function offsetUnset($key): void
1725
    {
1726
        unset($this->items[$key]);
1727
    }
1728
}