Completed
Push — master ( f37ac0...f4b286 )
by Ivan
09:19
created

Collection::offsetGet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace vakata\collection;
4
5
class Collection implements \Iterator, \ArrayAccess, \Serializable, \Countable
6
{
7
    protected $array = null;
8
    protected $stack = [];
9
    protected $iterator = null;
10
    protected $key = null;
11
    protected $val = null;
12
13 4
    protected static function rangeGenerator($low, $high, $step = 1)
14
    {
15 4
        $k = -1;
16 4
        for ($i = $low; $i <= $high; $i += $step) {
17 4
            yield ++$k => $i;
18
        }
19 4
    }
20
    /**
21
     * Create a collection based on a range generator
22
     * @param  int|float  $low  start value
23
     * @param  int|float  $high end value
24
     * @param  int|float  $step increment
25
     * @return Collection
26
     */
27 4
    public static function range($low, $high, $step = 1) : Collection
28
    {
29 4
        return new static(static::rangeGenerator($low, $high, $step));
30
    }
31
    /**
32
     * A static alias of the __constructor
33
     * @param  mixed  $input  Anything iterable
34
     * @return Collection
35
     */
36 51
    public static function from($input) : Collection
37
    {
38 51
        return new static($input);
39
    }
40
    /**
41
     * Create an instance
42
     * @param  mixed  $input  Anything iterable
43
     */
44 55
    public function __construct($input = [])
45
    {
46 55
        if (is_object($input)) {
47 28
            if ($input instanceof \Iterator) {
48 5
                $this->array = $input;
49 5
                $this->iterator = $input;
50 23
            } else if ($input instanceof self) {
51
                $this->array = $input->toArray();
52
            } else {
53 23
                $input = get_object_vars($input);
54
            }
55
        }
56 55
        if (is_array($input)) {
57 51
            $this->array = new \ArrayObject($input);
58 51
            $this->iterator = $this->array->getIterator();
59
        }
60 55
    }
61
    public function __clone()
62
    {
63
        $this->array = new \ArrayObject(iterator_to_array($this));
64
        $this->stack = [];
65
        $this->iterator = $this->array->getIterator();
66
    }
67 1
    public function __toString()
68
    {
69 1
        return implode(', ', $this->toArray());
70
    }
71 1
    public function serialize() {
72 1
        return serialize($this->toArray());
73
    }
74 1
    public function unserialize($array) {
75 1
        $this->array = new \ArrayObject(unserialize($array));
76 1
        $this->stack = [];
77 1
        $this->iterator = $this->array->getIterator();
78 1
    }
79
80
    /**
81
     * Applies all pending operations
82
     * @return $this
83
     */
84 45
    public function squash() : Collection
85
    {
86 45
        if (count($this->stack) || !($this->array instanceof \ArrayObject)) {
87 16
            $this->array = new \ArrayObject(iterator_to_array($this));
88 16
            $this->stack = [];
89 16
            $this->iterator = $this->array->getIterator();
90
        }
91 45
        return $this;
92
    }
93
    /**
94
     * Get an actual array from the collection
95
     * @return array
96
     */
97 44
    public function toArray() : array
98
    {
99 44
        return $this->squash()->array->getArrayCopy();
0 ignored issues
show
Bug introduced by
The method getArrayCopy does only exist in ArrayObject, but not in Iterator.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
100
    }
101
    /**
102
     * Gets the first value in the collection or null if empty
103
     * @return mixed
104
     */
105 3
    public function value()
106
    {
107 3
        foreach ($this as $v) {
108 3
            return $v;
109
        }
110 1
        return null;
111
    }
112
113
    // iterator
114 25
    public function key()
115
    {
116 25
        return $this->key;
117
    }
118 30
    public function current()
119
    {
120 30
        return $this->val;
121
    }
122 30
    public function rewind()
123
    {
124 30
        return $this->iterator->rewind();
125
    }
126 27
    public function next()
127
    {
128 27
        return $this->iterator->next();
129
    }
130 30
    public function valid()
131
    {
132 30
        while ($this->iterator->valid()) {
133 30
            $this->val = $this->iterator->current();
134 30
            $this->key = $this->iterator->key();
135 30
            $con = false;
136 30
            foreach ($this->stack as $action) {
137 12
                if ($action[0] === 'filter') {
138 8
                    if (!call_user_func($action[1], $this->val, $this->key, $this)) {
139 8
                        $con = true;
140 8
                        break;
141
                    }
142
                }
143 12
                if ($action[0] === 'map') {
144 5
                    $this->val = call_user_func($action[1], $this->val, $this->key, $this);
145
                }
146 12
                if ($action[0] === 'mapKey') {
147 12
                    $this->key = call_user_func($action[1], $this->val, $this->key, $this);
148
                }
149
            }
150 30
            if ($con) {
151 8
                $this->iterator->next();
152 8
                continue;
153
            }
154 30
            return true;
155
        }
156 27
        return false;
157
    }
158
159
    // array access
160 1
    public function offsetGet($offset)
161
    {
162 1
        return $this->squash()->array->offsetGet($offset);
0 ignored issues
show
Bug introduced by
The method offsetGet does only exist in ArrayObject, but not in Iterator.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
163
    }
164 1
    public function offsetExists($offset)
165
    {
166 1
        return $this->squash()->array->offsetExists($offset);
0 ignored issues
show
Bug introduced by
The method offsetExists does only exist in ArrayObject, but not in Iterator.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
167
    }
168 1
    public function offsetUnset($offset)
169
    {
170 1
        return $this->squash()->array->offsetUnset($offset);
0 ignored issues
show
Bug introduced by
The method offsetUnset does only exist in ArrayObject, but not in Iterator.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
171
    }
172 1
    public function offsetSet($offset, $value)
173
    {
174 1
        return $this->squash()->array->offsetSet($offset, $value);
0 ignored issues
show
Bug introduced by
The method offsetSet does only exist in ArrayObject, but not in Iterator.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
175
    }
176
    public function add($value)
177
    {
178
        $this->squash()->array->append($value);
0 ignored issues
show
Bug introduced by
The method append does only exist in ArrayObject, but not in Iterator.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
179
        return $this;
180
    }
181
    public function append($value)
182
    {
183
        return $this->add($value);
184
    }
185
    public function remove($value)
186
    {
187
        return $this->filter(function ($v) use ($value) { return $v !== $value; })->squash();
188
    }
189
    /**
190
     * Get the collection length
191
     * @return int
192
     */
193 1
    public function count()
194
    {
195 1
        if (count($this->stack) || !($this->array instanceof \Countable)) {
196
            $this->squash();
197
        }
198 1
        return $this->array->count();
199
    }
200
201
    // mutators
202
    /**
203
     * Filter values from the collection based on a predicate. The callback will receive the value, key and collection
204
     * @param  callable $iterator the predicate
205
     * @return $this
206
     */
207 8
    public function filter(callable $iterator) : Collection
208
    {
209 8
        $this->stack[] = [ 'filter', $iterator ];
210 8
        return $this;
211
    }
212
    /**
213
     * Pass all values of the collection through a mutator callable, which will receive the value, key and collection
214
     * @param  callable $iterator the mutator
215
     * @return $this
216
     */
217 5
    public function map(callable $iterator) : Collection
218
    {
219 5
        $this->stack[] = [ 'map', $iterator ];
220 5
        return $this;
221
    }
222
    /**
223
     * Pass all values of the collection through a key mutator callable, which will receive the value, key and collection
224
     * @param  callable $iterator the mutator
225
     * @return $this
226
     */
227 1
    public function mapKey(callable $iterator) : Collection
228
    {
229 1
        $this->stack[] = [ 'mapKey', $iterator ];
230 1
        return $this;
231
    }
232
    /**
233
     * Clone the current collection and return it.
234
     * @return Collection
235
     */
236
    public function clone() : Collection
237
    {
238 1
        return new static($this->toArray());
239
    }
240
    /**
241
     * Remove all falsy values from the collection (uses filter internally).
242
     * @return $this
243
     */
244 1
    public function compact() : Collection
245
    {
246
        return $this->filter(function ($v) {
247 1
            return !!$v;
248 1
        });
249
    }
250
    /**
251
     * Exclude all listed values from the collection (uses filter internally).
252
     * @param  iterable $values the values to exclude
253
     * @return $this
254
     */
255 3
    public function difference($values) : Collection
256
    {
257 3
        if (!is_array($values)) {
258 1
            $values = iterator_to_array($values);
259
        }
260 3
        $keys = array_keys($values);
261 3
        $isAssoc = $keys !== array_keys($keys);
262
        return $this->filter(function ($v, $k) use ($values, $isAssoc) {
263 3
            return $isAssoc ? 
264 1
                ($index = array_search($v, $values)) === false || $index !== $k :
265 3
                !in_array($v, $values, true);
266 3
        });
267
    }
268
    /**
269
     * Append more values to the collection
270
     * @param  iterable $source the values to add
271
     * @return Collection
272
     */
273 2
    public function extend($source) : Collection
274
    {
275 2
        if (!is_array($source)) {
276 1
            $source = iterator_to_array($source);
277
        }
278 2
        return new static(array_merge($this->toArray(), $source));
279
    }
280
    /**
281
     * Append more values to the collection
282
     * @param  iterable $source the values to add
283
     * @return Collection
284
     */
285 1
    public function merge($source) : Collection
286
    {
287 1
        return $this->extend($source);
288
    }
289
    /**
290
     * Perform a shallow flatten of the collection
291
     * @return Collection
292
     */
293 1
    public function flatten() : Collection
294
    {
295 1
        $rslt = [];
296 1
        $temp = $this->toArray();
297 1
        foreach ($temp as $v) {
298 1
            $rslt = array_merge($rslt, is_array($v) ? $v : [$v]);
299
        }
300 1
        return new static($rslt);
301
    }
302
    /**
303
     * Group by a key (if a callable is used - return the value to group by)
304
     * @param  string|callable $iterator the key to group by
305
     * @return Collection
306
     */
307 1
    public function groupBy($iterator) : Collection
308
    {
309 1
        $rslt = [];
310 1
        $temp = $this->toArray();
311 1
        foreach ($temp as $k => $v) {
312 1
            $rslt[is_string($iterator) ? (is_object($v) ? $v->{$iterator} : $v[$iterator]) : call_user_func($iterator, $v, $k)][] = $v;
313
        }
314 1
        return new static($rslt);
315
    }
316
    /**
317
     * Get the first X items from the collection
318
     * @param  int $count the number of items to include (defaults to 1)
319
     * @return Collection
320
     */
321 1
    public function first(int $count = 1) : Collection
322
    {
323 1
        $i = 0;
324 1
        $new = [];
325 1
        foreach ($this as $k => $v) {
326 1
            if (++$i > $count) {
327 1
                break;
328
            }
329 1
            $new[$k] = $v;
330
        }
331 1
        return new static($new);
332
    }
333
    /**
334
     * Get the first X items from the collection
335
     * @param  int $count the number of items to include (defaults to 1)
336
     * @return Collection
337
     */
338 1
    public function head(int $count = 1) : Collection
339
    {
340 1
        return $this->first($count);
341
    }
342
    /**
343
     * Get the last X items from the collection
344
     * @param  int $count the number of items to include (defaults to 1)
345
     * @return Collection
346
     */
347 2
    public function last(int $count = 1) : Collection
348
    {
349 2
        $new = $this->toArray();
350 2
        return new static(array_slice($new, $count * -1));
351
    }
352
    /**
353
     * Get the first X items from the collection
354
     * @param  int $count the number of items to include (defaults to 1)
355
     * @return Collection
356
     */
357 1
    public function tail(int $count = 1) : Collection
358
    {
359 1
        return $this->last($count);
360
    }
361
    /**
362
     * Get all but the last X items from the collection
363
     * @param  int $count the number of items to exclude (defaults to 1)
364
     * @return Collection
365
     */
366 1
    public function initial(int $count = 1) : Collection
367
    {
368 1
        $new = $this->toArray();
369 1
        return new static(array_slice($new, 0, $count * -1));
370
    }
371
    /**
372
     * Get all but the first X items from the collection
373
     * @param  int $count the number of items to exclude (defaults to 1)
374
     * @return Collection
375
     */
376 1
    public function rest(int $count = 1) : Collection
377
    {
378 1
        $new = $this->toArray();
379 1
        return new static(array_slice($new, $count));
380
    }
381
    /**
382
     * Execute a callable for each item in the collection (does not modify the collection)
383
     * @param  callable $iterator the callable to execute
384
     * @return $this
385
     */
386 1
    public function each(callable $iterator) : Collection
387
    {
388 1
        foreach ($this as $k => $v) {
389 1
            call_user_func($iterator, $v, $k, $this);
390
        }
391 1
        return $this;
392
    }
393
    /**
394
     * Execute a callable for each item in the collection (does not modify the collection)
395
     * @param  callable $iterator the callable to execute
396
     * @return $this
397
     */
398 1
    public function invoke(callable $iterator) : Collection
399
    {
400 1
        return $this->each($iterator);
401
    }
402
    /**
403
     * Get all the collection keys
404
     * @return $this
405
     */
406
    public function keys() : Collection
407
    {
408
        return $this->map(function ($v, $k) { return $k; })->values();
409
    }
410
    /**
411
     * Pluck a value from each object (uses map internally)
412
     * @param  string|int $key the key to extract
413
     * @return $this
414
     */
415 2
    public function pluck($key) : Collection
416
    {
417
        return $this->map(function ($v) use ($key) {
418 2
            return is_object($v) ?
419 1
                (isset($v->{$key}) ? $v->{$key} : null) :
420 2
                (isset($v[$key]) ? $v[$key] : null);
421 2
        });
422
    }
423
    /**
424
     * Intersect the collection with another iterable (uses filter internally)
425
     * @param  interable $values the data to intersect with
426
     * @return $this
427
     */
428 1
    public function intersection($values) : Collection
429
    {
430 1
        if (!is_array($values)) {
431 1
            $values = iterator_to_array($values);
432
        }
433 1
        $keys = array_keys($values);
434 1
        $isAssoc = $keys !== array_keys($keys);
435
        return $this->filter(function ($v, $k) use ($values, $isAssoc) {
436 1
            return $isAssoc ? 
437 1
                array_search($v, $values) === $k :
438 1
                in_array($v, $values, true);
439 1
        });
440
    }
441
    /**
442
     * Reject values on a given predicate (opposite of filter)
443
     * @param  callable $iterator the predicate
444
     * @return $this
445
     */
446 1
    public function reject(callable $iterator) : Collection
447
    {
448
        return $this->filter(function ($v, $k, $array) use ($iterator) {
449 1
            return !call_user_func($iterator, $v, $k, $array);
450 1
        });
451
    }
452
    /**
453
     * Shuffle the values in the collection
454
     * @return Collection
455
     */
456 1
    public function shuffle() : Collection
457
    {
458 1
        $temp = $this->toArray();
459 1
        $keys = array_keys($temp);
460 1
        shuffle($keys);
461 1
        $rslt = [];
462 1
        foreach ($keys as $key) {
463 1
            $rslt[$key] = $temp[$key];
464
        }
465 1
        return new static($rslt);
466
    }
467
    /**
468
     * Sort the collection using a standard sorting function
469
     * @param  callable $iterator the sort function (must return -1, 0 or 1)
470
     * @return Collection
471
     */
472 1
    public function sortBy(callable $iterator) : Collection
473
    {
474 1
        $this->squash();
475 1
        $this->array->uasort($iterator);
476 1
        return $this;
477
    }
478
    /**
479
     * Inspect the whole collection (as an array) mid-chain
480
     * @param  callable $iterator the callable to execute
481
     * @return $this
482
     */
483 1
    public function tap(callable $iterator) : Collection
484
    {
485 1
        call_user_func($iterator, $this->toArray());
486 1
        return $this;
487
    }
488
    /**
489
     * Modify the whole collection (as an array) mid-chain
490
     * @param  callable $iterator the callable to execute
491
     * @return Collection
492
     */
493 1
    public function thru(callable $iterator) : Collection
494
    {
495 1
        $temp = $this->toArray();
496 1
        $rslt = call_user_func($iterator, $temp);
497 1
        return new static($rslt);
498
    }
499
    /**
500
     * Leave only unique items in the collection
501
     * @return Collection
502
     */
503 3
    public function unique() : Collection
504
    {
505 3
        $temp = $this->toArray();
506 3
        $rslt = [];
507 3
        foreach ($temp as $k => $v) {
508 3
            if (!in_array($v, $rslt, true)) {
509 3
                $rslt[$k] = $v;
510
            }
511
        }
512 3
        return new static($rslt);
513
    }
514
    /**
515
     * Get only the values of the collection
516
     * @return Collection
517
     */
518 3
    public function values() : Collection
519
    {
520 3
        return new static(array_values($this->toArray()));
521
    }
522
    /**
523
     * Filter items from the collection using key => value pairs
524
     * @param  array   $properties the key => value to check for in each item
525
     * @param  boolean $strict     should the comparison be strict
526
     * @return $this
527
     */
528
    public function where(array $properties, $strict = true) : Collection
529
    {
530 1
        return $this->filter(function ($v) use ($properties, $strict) {
531 1
            foreach ($properties as $key => $value) {
532 1
                $vv = is_object($v) ? (isset($v->{$key}) ? $v->{$key} : null) : (isset($v[$key]) ? $v[$key] : null);
533 1
                if (!$vv || ($strict && $vv !== $value) || (!$strict && $vv != $value)) {
534 1
                    return false;
535
                }
536
            }
537 1
            return true;
538 1
        });
539
    }
540
    /**
541
     * Exclude all listed values from the collection (uses filter internally).
542
     * @param  iterable $values the values to exclude
543
     * @return $this
544
     */
545 2
    public function without($values) : Collection
546
    {
547 2
        return $this->difference($values);
548
    }
549
    /**
550
     * Combine all the values from the collection with a key
551
     * @param  iterable $keys the keys to use
552
     * @return Collection
553
     */
554 2
    public function zip($keys) : Collection
555
    {
556 2
        if (!is_array($keys)) {
557 1
            $keys = iterator_to_array($keys);
558
        }
559 2
        return new static(array_combine($keys, $this->toArray()));
560
    }
561
    /**
562
     * Reverse the collection order
563
     * @return Collection
564
     */
565 1
    public function reverse() : Collection
566
    {
567 1
        return new static(array_reverse($this->toArray()));
568
    }
569
570
    // accessors
571
    /**
572
     * Do all of the items in the collection match a given criteria
573
     * @param  callable $iterator the criteria - should return true / false
574
     * @return bool
575
     */
576 1
    public function all(callable $iterator) : bool
577
    {
578 1
        foreach ($this as $k => $v) {
579 1
            if (!call_user_func($iterator, $v, $k, $this)) {
580 1
                return false;
581
            }
582
        }
583 1
        return true;
584
    }
585
    /**
586
     * Do any of the items in the collection match a given criteria
587
     * @param  callable $iterator the criteria - should return true / false
588
     * @return bool
589
     */
590 1
    public function any(callable $iterator) : bool
591
    {
592 1
        foreach ($this as $k => $v) {
593 1
            if (call_user_func($iterator, $v, $k, $this)) {
594 1
                return true;
595
            }
596
        }
597 1
        return false;
598
    }
599
    /**
600
     * Does the collection contain a given value
601
     * @param  mixed $needle the value to check for
602
     * @return bool
603
     */
604 1
    public function contains($needle) : bool
605
    {
606 1
        foreach ($this as $k => $v) {
607 1
            if ($v === $needle) {
608 1
                return true;
609
            }
610
        }
611 1
        return false;
612
    }
613
    /**
614
     * Get the first element matching a given criteria (or null)
615
     * @param  callable $iterator the filter criteria
616
     * @return mixed
617
     */
618 1
    public function find(callable $iterator)
619
    {
620 1
        foreach ($this as $k => $v) {
621 1
            if (call_user_func($iterator, $v, $k, $this)) {
622 1
                return $v;
623
            }
624
        }
625 1
        return null;
626
    }
627
    /**
628
     * Get all the elements matching a given criteria (with the option to limit the number of results)
629
     * @param  callable $iterator the search criteria
630
     * @param  int|null $limit    optional limit to the number of results (default to null - no limit)
631
     * @return Collection
632
     */
633 1
    public function findAll(callable $iterator, int $limit = null) : Collection
634
    {
635 1
        $res = [];
636 1
        foreach ($this as $k => $v) {
637 1
            if (call_user_func($iterator, $v, $k, $this)) {
638 1
                $res[] = $v;
639
            }
640 1
            if ((int)$limit > 0 && count($res) >= $limit) {
641 1
                break;
642
            }
643
        }
644 1
        return new static($res);
645
    }
646
    /**
647
     * Get the key corresponding to a value (or false)
648
     * @param  mixed  $needle the value to search for
649
     * @return mixed
650
     */
651 1
    public function indexOf($needle)
652
    {
653 1
        return array_search($needle, $this->toArray(), true);
654
    }
655
    /**
656
     * Get the last key corresponding to a value (or false)
657
     * @param  mixed  $needle the value to search for
658
     * @return mixed
659
     */
660 1
    public function lastIndexOf($needle)
661
    {
662 1
        $res = null;
663 1
        foreach ($this as $k => $v) {
664 1
            if ($v === $needle) {
665 1
                $res = $k;
666
            }
667
        }
668 1
        return $res;
669
    }
670
    /**
671
     * Get the number of elements in the collection
672
     * @return int
673
     */
674 1
    public function size() : int
675
    {
676 1
        return $this->count();
677
    }
678
    /**
679
     * Get the minimal item in the collection
680
     * @return mixed
681
     */
682 1
    public function min()
683
    {
684 1
        $min = null;
685 1
        $first = false;
686 1
        foreach ($this as $v) {
687 1
            if (!$first || $v < $min) {
688 1
                $min = $v;
689 1
                $first = true;
690
            }
691
        }
692 1
        return $min;
693
    }
694
    /**
695
     * Get the maximum item in the collection
696
     * @return mixed
697
     */
698 1
    public function max()
699
    {
700 1
        $max = null;
701 1
        $first = false;
702 1
        foreach ($this as $v) {
703 1
            if (!$first || $v > $max) {
704 1
                $max = $v;
705 1
                $first = true;
706
            }
707
        }
708 1
        return $max;
709
    }
710
    /**
711
     * Does the collection contain a given key
712
     * @param  string|int  $key the key to check
713
     * @return bool
714
     */
715 1
    public function has($key) : bool
716
    {
717 1
        return $this->offsetExists($key);
718
    }
719
    /**
720
     * Reduce the collection to a single value
721
     * @param  callable $iterator the reducer
722
     * @param  mixed    $initial  the initial value
723
     * @return mixed the final value
724
     */
725 1
    public function reduce(callable $iterator, $initial = null)
726
    {
727 1
        return array_reduce($this->toArray(), $iterator, $initial);
728
    }
729
    /**
730
     * Reduce the collection to a single value, starting from the last element
731
     * @param  callable $iterator the reducer
732
     * @param  mixed    $initial  the initial value
733
     * @return mixed the final value
734
     */
735 1
    public function reduceRight(callable $iterator, $initial = null)
736
    {
737 1
        return array_reduce(array_reverse($this->toArray()), $iterator, $initial);
738
    }
739
}
740