Completed
Push — master ( f1d05d...05a20f )
by Lars
02:30
created

Arrayy::lastsImmutable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2
Metric Value
dl 0
loc 12
ccs 8
cts 8
cp 1
rs 9.4285
cc 2
eloc 8
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Arrayy;
4
5
use ArrayAccess;
6
use Closure;
7
use voku\helper\UTF8;
8
9
/**
10
 * Methods to manage arrays.
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
class Arrayy extends \ArrayObject
16
{
17
  /**
18
   * @var array
19
   */
20
  protected $array = array();
21
22
  /** @noinspection MagicMethodsValidityInspection */
23
  /**
24
   * Initializes
25
   *
26
   * @param array $array
27
   */
28 698
  public function __construct($array = array())
29
  {
30 698
    $array = $this->fallbackForArray($array);
31
32 696
    $this->array = $array;
0 ignored issues
show
Documentation Bug introduced by
It seems like $array can also be of type object<Arrayy\Arrayy>. However, the property $array is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
33 696
  }
34
35
  /**
36
   * Get a value by key.
37
   *
38
   * @param $key
39
   *
40
   * @return mixed Get a Value from the current array.
41
   */
42
  public function &__get($key)
43
  {
44
    return $this->array[$key];
45
  }
46
47
  /**
48
   * Call object as function.
49
   *
50
   * @param mixed $key
51
   *
52
   * @return mixed
53
   */
54
  public function __invoke($key = null)
55
  {
56
    if ($key !== null) {
57
      if (isset($this->array[$key])) {
58
        return $this->array[$key];
59
      } else {
60
        return false;
61
      }
62
    }
63
64
    return (array)$this->array;
65
  }
66
67
  /**
68
   * Whether or not an element exists by key.
69
   *
70
   * @param mixed $key
71
   *
72
   * @return bool True is the key/index exists, otherwise false.
73
   */
74
  public function __isset($key)
75
  {
76
    return isset($this->array[$key]);
77
  }
78
79
  /**
80
   * Assigns a value to the specified element.
81
   *
82
   * @param mixed $key
83
   * @param mixed $value
84
   */
85
  public function __set($key, $value)
86
  {
87
    $this->array[$key] = $value;
88
  }
89
90
  /**
91
   * magic to string
92
   *
93
   * @return string
94
   */
95 15
  public function __toString()
96
  {
97 15
    return $this->toString();
98
  }
99
100
  /**
101
   * Unset element by key.
102
   *
103
   * @param mixed $key
104
   */
105
  public function __unset($key)
106
  {
107
    unset($this->array[$key]);
108
  }
109
110
  /**
111
   * alias: for "Arrayy->append()"
112
   *
113
   * @param mixed $value
114
   *
115
   * @return self (Mutable) Return this Arrayy object, with the appended values.
116
   */
117 1
  public function add($value)
118
  {
119 1
    return $this->append($value);
120
  }
121
122
  /**
123
   * Append a value to the current array.
124
   *
125
   * @param mixed $value
126
   *
127
   * @return self (Mutable) Return this Arrayy object, with the appended values.
128
   */
129 9
  public function append($value)
130
  {
131 9
    $this->array[] = $value;
132
133 9
    return $this;
134
  }
135
136
  /**
137
   * Count the values from the current array.
138
   *
139
   * INFO: only a alias for "$arrayy->size()"
140
   *
141
   * @return int
142
   */
143 109
  public function count()
144
  {
145 109
    return $this->size();
146
  }
147
148
  /**
149
   * Returns a new ArrayIterator, thus implementing the IteratorAggregate interface.
150
   *
151
   * @return \ArrayIterator An iterator for the values in the array.
152
   */
153 16
  public function getIterator()
154
  {
155 16
    return new \ArrayIterator($this->array);
156
  }
157
158
  /**
159
   * Whether or not an offset exists.
160
   *
161
   * @param mixed $offset
162
   *
163
   * @return bool
164
   */
165 31
  public function offsetExists($offset)
166
  {
167 31
    return isset($this->array[$offset]);
168
  }
169
170
  /**
171
   * Returns the value at specified offset.
172
   *
173
   * @param mixed $offset
174
   *
175
   * @return mixed return null if the offset did not exists
176
   */
177 22
  public function offsetGet($offset)
178
  {
179 22
    return $this->offsetExists($offset) ? $this->array[$offset] : null;
180
  }
181
182
  /**
183
   * Assigns a value to the specified offset.
184
   *
185
   * @param mixed $offset
186
   * @param mixed $value
187
   */
188 13
  public function offsetSet($offset, $value)
189
  {
190 13
    if (null === $offset) {
191 4
      $this->array[] = $value;
192 4
    } else {
193 9
      $this->array[$offset] = $value;
194
    }
195 13
  }
196
197
  /**
198
   * Unset an offset.
199
   *
200
   * @param mixed $offset
201
   */
202 5
  public function offsetUnset($offset)
203
  {
204 5
    if ($this->offsetExists($offset)) {
205 3
      unset($this->array[$offset]);
206 3
    }
207 5
  }
208
209
  /**
210
   * Serialize the current array.
211
   *
212
   * @return string
213
   */
214 2
  public function serialize()
215
  {
216 2
    return serialize($this->array);
217
  }
218
219
  /**
220
   * Unserialize an string and return this object.
221
   *
222
   * @param string $string
223
   *
224
   * @return self (Mutable)
225
   */
226 1
  public function unserialize($string)
227
  {
228 1
    $this->array = unserialize($string);
229
230 1
    return $this;
231
  }
232
233
  /**
234
   * Iterate over the current array and execute a callback for each loop.
235
   *
236
   * @param \Closure $closure
237
   *
238
   * @return Arrayy (Immutable)
239
   */
240 2 View Code Duplication
  public function at(\Closure $closure)
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...
241
  {
242 2
    $array = $this->array;
243
244 2
    foreach ($array as $key => $value) {
245 2
      $closure($value, $key);
246 2
    }
247
248 2
    return static::create($array);
249
  }
250
251
  /**
252
   * Returns the average value of the current array.
253
   *
254
   * @param int $decimals The number of decimals to return
255
   *
256
   * @return int|double The average value
257
   */
258 10
  public function average($decimals = null)
259
  {
260 10
    $count = $this->count();
261
262 10
    if (!$count) {
263 2
      return 0;
264
    }
265
266 8
    if (!is_int($decimals)) {
267 3
      $decimals = null;
268 3
    }
269
270 8
    return round(array_sum($this->array) / $count, $decimals);
271
  }
272
273
  /**
274
   * Create a chunked version of the current array.
275
   *
276
   * @param int  $size         Size of each chunk
277
   * @param bool $preserveKeys Whether array keys are preserved or no
278
   *
279
   * @return Arrayy (Immutable) A new array of chunks from the original array.
280
   */
281 4
  public function chunk($size, $preserveKeys = false)
282
  {
283 4
    $result = array_chunk($this->array, $size, $preserveKeys);
284
285 4
    return static::create($result);
286
  }
287
288
  /**
289
   * Clean all falsy values from the current array.
290
   *
291
   * @return Arrayy (Immutable)
292
   */
293 8
  public function clean()
294
  {
295 8
    return $this->filter(
296
        function ($value) {
297 7
          return (bool)$value;
298
        }
299 8
    );
300
  }
301
302
  /**
303
   * WARNING!!! -> Clear the current array.
304
   *
305
   * @return self (Mutable) Return this Arrayy object, with an empty array.
306
   */
307 4
  public function clear()
308
  {
309 4
    $this->array = array();
310
311 4
    return $this;
312
  }
313
314
  /**
315
   * Check if an item is in the current array.
316
   *
317
   * @param mixed $value
318
   *
319
   * @return bool
320
   */
321 13
  public function contains($value)
322
  {
323 13
    return in_array($value, $this->array, true);
324
  }
325
326
  /**
327
   * Check if the given key/index exists in the array.
328
   *
329
   * @param mixed $key Key/index to search for
330
   *
331
   * @return bool Returns true if the given key/index exists in the array, false otherwise
332
   */
333 4
  public function containsKey($key)
334
  {
335 4
    return array_key_exists($key, $this->array);
336
  }
337
338
  /** @noinspection ArrayTypeOfParameterByDefaultValueInspection */
339
  /**
340
   * Creates an Arrayy object.
341
   *
342
   * @param array $array
343
   *
344
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
345
   */
346 438
  public static function create($array = array())
347
  {
348 438
    return new static($array);
349
  }
350
351
  /** @noinspection ArrayTypeOfParameterByDefaultValueInspection */
352
  /**
353
   * WARNING: Creates an Arrayy object by reference.
354
   *
355
   * @param array $array
356
   *
357
   * @return self (Mutable) Return this Arrayy object.
358
   */
359
  public function createByReference(&$array = array())
360
  {
361
    $array = $this->fallbackForArray($array);
362
363
    $this->array = &$array;
364
365
    return $this;
366
  }
367
368
  /**
369
   * Create an new Arrayy object via JSON.
370
   *
371
   * @param string $json
372
   *
373
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
374
   */
375 5
  public static function createFromJson($json)
376
  {
377 5
    $array = UTF8::json_decode($json, true);
378
379 5
    return static::create($array);
380
  }
381
382
  /**
383
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
384
   *
385
   * @param ArrayAccess $object Object that implements ArrayAccess
386
   *
387
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
388
   */
389 4
  public static function createFromObject(ArrayAccess $object)
390
  {
391 4
    $array = new static();
392 4
    foreach ($object as $key => $value) {
393
      /** @noinspection OffsetOperationsInspection */
394 3
      $array[$key] = $value;
395 4
    }
396
397 4
    return $array;
398
  }
399
400
  /**
401
   * Create an new instance containing a range of elements.
402
   *
403
   * @param mixed $low  First value of the sequence
404
   * @param mixed $high The sequence is ended upon reaching the end value
405
   * @param int   $step Used as the increment between elements in the sequence
406
   *
407
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
408
   */
409 1
  public static function createWithRange($low, $high, $step = 1)
410
  {
411 1
    return static::create(range($low, $high, $step));
412
  }
413
414
  /**
415
   * Create an new Arrayy object via string.
416
   *
417
   * @param string      $str       The input string.
418
   * @param string|null $delimiter The boundary string.
419
   * @param string|null $regEx     Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be used.
420
   *
421
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
422
   */
423 8
  public static function createFromString($str, $delimiter, $regEx = null)
424
  {
425 8
    if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type string|null 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...
426 1
      preg_match_all($regEx, $str, $array);
427
428 1
      if (count($array) > 0) {
429 1
        $array = $array[0];
430 1
      }
431
432 1
    } else {
433 7
      $array = explode($delimiter, $str);
434
    }
435
436
    // trim all string in the array
437 8
    array_walk(
438 8
        $array,
439
        function (&$val) {
440
          /** @noinspection ReferenceMismatchInspection */
441 8
          if (is_string($val)) {
442 8
            $val = trim($val);
443 8
          }
444 8
        }
445 8
    );
446
447 8
    return static::create($array);
448
  }
449
450
  /**
451
   * Custom sort by index via "uksort".
452
   *
453
   * @link http://php.net/manual/en/function.uksort.php
454
   *
455
   * @param callable $function
456
   *
457
   * @return self (Mutable) Return this Arrayy object.
458
   */
459 5
  public function customSortKeys($function)
460
  {
461 5
    uksort($this->array, $function);
462
463 5
    return $this;
464
  }
465
466
  /**
467
   * Custom sort by value via "usort".
468
   *
469
   * @link http://php.net/manual/en/function.usort.php
470
   *
471
   * @param callable $function
472
   *
473
   * @return self (Mutable) Return this Arrayy object.
474
   */
475 4
  public function customSortValues($function)
476
  {
477 4
    usort($this->array, $function);
478
479 4
    return $this;
480
  }
481
482
  /**
483
   * Return values that are only in the current array.
484
   *
485
   * @param array $array
486
   *
487
   * @return Arrayy (Immutable)
488
   */
489 12
  public function diff(array $array = array())
490
  {
491 12
    $result = array_diff($this->array, $array);
492
493 12
    return static::create($result);
494
  }
495
496
  /**
497
   * Return values that are only in the new $array.
498
   *
499
   * @param array $array
500
   *
501
   * @return Arrayy (Immutable)
502
   */
503 8
  public function diffReverse(array $array = array())
504
  {
505 8
    $result = array_diff($array, $this->array);
506
507 8
    return static::create($result);
508
  }
509
510
  /**
511
   * Iterate over the current array and modify the array's value.
512
   *
513
   * @param \Closure $closure
514
   *
515
   * @return Arrayy (Immutable)
516
   */
517 22 View Code Duplication
  public function each(\Closure $closure)
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...
518
  {
519 22
    $array = $this->array;
520
521 22
    foreach ($array as $key => &$value) {
522 18
      $value = $closure($value, $key);
523 22
    }
524
525 22
    return static::create($array);
526
  }
527
528
  /**
529
   * Check if a value is in the current array using a closure.
530
   *
531
   * @param \Closure $closure
532
   *
533
   * @return bool Returns true if the given value is found, false otherwise
534
   */
535 4
  public function exists(\Closure $closure)
536
  {
537 4
    $isExists = false;
538 4
    foreach ($this->array as $key => $value) {
539 3
      if ($closure($value, $key)) {
540 1
        $isExists = true;
541 1
        break;
542
      }
543 4
    }
544
545 4
    return $isExists;
546
  }
547
548
  /**
549
   * create a fallback for array
550
   *
551
   * 1. use the current array, if it's a array
552
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
553
   * 3. fallback to empty array, if there is nothing
554
   * 4. call "createFromObject()" on object, if there is a "ArrayAccess"-object
555
   * 5. call "__toArray()" on object, if the method exists
556
   * 6. cast a string or object with "__toString()" into an array
557
   * 7. throw a "InvalidArgumentException"-Exception
558
   *
559
   * @param $array
560
   *
561
   * @return array
562
   *
563
   * @throws \InvalidArgumentException
564
   */
565 698
  protected function fallbackForArray(&$array)
566
  {
567 698
    if (is_array($array)) {
568 695
      return $array;
569
    }
570
571 4
    if ($array instanceof self) {
572
      return $array->getArray();
573
    }
574
575 4
    if (!$array) {
576 1
      return array();
577
    }
578
    
579 3
    if ($array instanceof ArrayAccess) {
580
      /** @noinspection ReferenceMismatchInspection */
581
      return self::createFromObject($array);
582
    }
583
584 3
    if (is_object($array) && method_exists($array, '__toArray')) {
585
      return (array)$array->__toArray();
586
    }
587
588
    /** @noinspection ReferenceMismatchInspection */
589
    if (
590 3
        is_string($array)
591
        ||
592 2
        (is_object($array) && method_exists($array, '__toString'))
593 3
    ) {
594 1
      return (array)$array;
595
    }
596
597 2
    throw new \InvalidArgumentException(
598
        'Passed value should be a array'
599 2
    );
600
  }
601
602
  /**
603
   * Find all items in an array that pass the truth test.
604
   *
605
   * @param \Closure|null $closure
606
   *
607
   * @return Arrayy (Immutable)
608
   */
609 8
  public function filter($closure = null)
610
  {
611 8
    if (!$closure) {
612 1
      return $this->clean();
613
    }
614
615 8
    $array = array_filter($this->array, $closure);
616
617 8
    return static::create($array);
618
  }
619
620
  /**
621
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
622
   * within that.
623
   *
624
   * @param        $property
625
   * @param        $value
626
   * @param string $comparisonOp
627
   *                            'eq' (equals),<br />
628
   *                            'gt' (greater),<br />
629
   *                            'gte' || 'ge' (greater or equals),<br />
630
   *                            'lt' (less),<br />
631
   *                            'lte' || 'le' (less or equals),<br />
632
   *                            'ne' (not equals),<br />
633
   *                            'contains',<br />
634
   *                            'notContains',<br />
635
   *                            'newer' (via strtotime),<br />
636
   *                            'older' (via strtotime),<br />
637
   *
638
   * @return Arrayy (Immutable)
639
   */
640 1
  public function filterBy($property, $value, $comparisonOp = null)
641
  {
642 1
    if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type string|null 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...
643 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
644 1
    }
645
646
    $ops = array(
647
        'eq'          => function ($item, $prop, $value) {
648 1
          return $item[$prop] === $value;
649 1
        },
650
        'gt'          => function ($item, $prop, $value) {
651
          return $item[$prop] > $value;
652 1
        },
653
        'ge'         => function ($item, $prop, $value) {
654
          return $item[$prop] >= $value;
655 1
        },
656
        'gte'         => function ($item, $prop, $value) {
657
          return $item[$prop] >= $value;
658 1
        },
659
        'lt'          => function ($item, $prop, $value) {
660 1
          return $item[$prop] < $value;
661 1
        },
662
        'le'         => function ($item, $prop, $value) {
663
          return $item[$prop] <= $value;
664 1
        },
665
        'lte'         => function ($item, $prop, $value) {
666
          return $item[$prop] <= $value;
667 1
        },
668
        'ne'          => function ($item, $prop, $value) {
669
          return $item[$prop] !== $value;
670 1
        },
671
        'contains'    => function ($item, $prop, $value) {
672 1
          return in_array($item[$prop], (array)$value, true);
673 1
        },
674
        'notContains' => function ($item, $prop, $value) {
675
          return !in_array($item[$prop], (array)$value, true);
676 1
        },
677
        'newer'       => function ($item, $prop, $value) {
678
          return strtotime($item[$prop]) > strtotime($value);
679 1
        },
680
        'older'       => function ($item, $prop, $value) {
681
          return strtotime($item[$prop]) < strtotime($value);
682 1
        },
683 1
    );
684
685 1
    $result = array_values(
686 1
        array_filter(
687 1
            (array)$this->array,
688
            function ($item) use (
689 1
                $property,
690 1
                $value,
691 1
                $ops,
692 1
                $comparisonOp
693
            ) {
694 1
              $item = (array)$item;
695 1
              $itemArrayy = new Arrayy($item);
696 1
              $item[$property] = $itemArrayy->get($property, array());
697
698 1
              return $ops[$comparisonOp]($item, $property, $value);
699
            }
700 1
        )
701 1
    );
702
703 1
    return static::create($result);
704
  }
705
706
  /**
707
   * Find the first item in an array that passes the truth test,
708
   *  otherwise return false
709
   *
710
   * @param \Closure $closure
711
   *
712
   * @return mixed|false false if we did not find the value
713
   */
714 8
  public function find(\Closure $closure)
715
  {
716 8
    foreach ($this->array as $key => $value) {
717 6
      if ($closure($value, $key)) {
718 5
        return $value;
719
      }
720 5
    }
721
722 3
    return false;
723
  }
724
725
  /**
726
   * find by ...
727
   *
728
   * @param        $property
729
   * @param        $value
730
   * @param string $comparisonOp
731
   *
732
   * @return Arrayy (Immutable)
733
   */
734
  public function findBy($property, $value, $comparisonOp = 'eq')
735
  {
736
    return $this->filterBy($property, $value, $comparisonOp);
737
  }
738
739
  /**
740
   * Get the first value from the current array.
741
   *
742
   * @return mixed Return null if there wasn't a element.
743
   */
744 13
  public function first()
745
  {
746 13
    $result = array_shift($this->array);
747
748 13
    if (null === $result) {
749 3
      return null;
750
    } else {
751 10
      return $result;
752
    }
753
  }
754
755
  /**
756
   * Get the first value(s) from the current array.
757
   *
758
   * @param int|null $number how many values you will take?
759
   *
760
   * @return self (Mutable)
761
   */
762 26
  public function firstsMutable($number = null)
763
  {
764 26
    if ($number === null) {
765 11
      $this->array = (array)array_shift($this->array);
766 11
    } else {
767 15
      $number = (int)$number;
768 15
      $this->array = array_splice($this->array, 0, $number, true);
769
    }
770
771 26
    return $this;
772
  }
773
774
  /**
775
   * Get the first value(s) from the current array.
776
   *
777
   * @param int|null $number how many values you will take?
778
   *
779
   * @return Arrayy (Immutable)
780
   */
781 28
  public function firstsImmutable($number = null)
782
  {
783 28
    if ($number === null) {
784 7
      $array = (array)array_shift($this->array);
785 7
    } else {
786 21
      $number = (int)$number;
787 21
      $array = array_splice($this->array, 0, $number, true);
788
    }
789
790 28
    return static::create($array);
791
  }
792
793
  /**
794
   * Exchanges all keys with their associated values in an array.
795
   *
796
   * @return Arrayy (Immutable)
797
   */
798 1
  public function flip()
799
  {
800 1
    $result = array_flip($this->array);
801
802 1
    return static::create($result);
803
  }
804
805
  /**
806
   * Get a value from an array (optional using dot-notation).
807
   *
808
   * @param string $key     The key to look for.
809
   * @param mixed  $default Default value to fallback to.
810
   * @param array  $array   The array to get from, if it's set to "null" we use the current array from the class.
811
   *
812
   * @return mixed
813
   */
814 34
  public function get($key, $default = null, $array = null)
815
  {
816 34
    if (is_array($array) === true) {
817 3
      $usedArray = $array;
818 3
    } else {
819 32
      $usedArray = $this->array;
820
    }
821
822 34
    if (null === $key) {
823 1
      return $usedArray;
824
    }
825
826 34
    if (isset($usedArray[$key])) {
827 23
      return $usedArray[$key];
828
    }
829
830
    // Crawl through array, get key according to object or not
831 19
    foreach (explode('.', $key) as $segment) {
832 19
      if (!isset($usedArray[$segment])) {
833 17
        return $default instanceof Closure ? $default() : $default;
834
      }
835
836 2
      $usedArray = $usedArray[$segment];
837 2
    }
838
839 2
    return $usedArray;
840
  }
841
842
  /**
843
   * Get the current array from the "Arrayy"-object.
844
   *
845
   * @return array
846
   */
847 474
  public function getArray()
848
  {
849 474
    return $this->array;
850
  }
851
852
  /**
853
   * Returns the values from a single column of the input array, identified by
854
   * the $columnKey, can be used to extract data-columns from multi-arrays.
855
   *
856
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
857
   * array by the values from the $indexKey column in the input array.
858
   *
859
   * @param mixed $columnKey
860
   * @param mixed $indexKey
861
   *
862
   * @return Arrayy (Immutable)
863
   */
864 1
  public function getColumn($columnKey = null, $indexKey = null)
865
  {
866 1
    $result = array_column($this->array, $columnKey, $indexKey);
867
868 1
    return static::create($result);
869
  }
870
871
  /**
872
   * Get correct PHP constant for direction.
873
   *
874
   * @param int|string $direction
875
   *
876
   * @return int
877
   */
878 38
  protected function getDirection($direction)
879
  {
880 38
    if (is_string($direction)) {
881 10
      $direction = strtolower($direction);
882
883 10
      if ($direction === 'desc') {
884 2
        $direction = SORT_DESC;
885 2
      } else {
886 8
        $direction = SORT_ASC;
887
      }
888 10
    }
889
890
    if (
891
        $direction !== SORT_DESC
892 38
        &&
893
        $direction !== SORT_ASC
894 38
    ) {
895
      $direction = SORT_ASC;
896
    }
897
898 38
    return $direction;
899
  }
900
901
  /**
902
   * alias: for "Arrayy->keys()"
903
   *
904
   * @return Arrayy (Immutable)
905
   */
906
  public function getKeys()
907
  {
908
    return $this->keys();
909
  }
910
911
  /**
912
   * alias: for "Arrayy->random()"
913
   *
914
   * @return Arrayy (Immutable)
915
   */
916 3
  public function getRandom()
917
  {
918 3
    return $this->randomImmutable();
919
  }
920
921
  /**
922
   * alias: for "Arrayy->randomKey()"
923
   *
924
   * @return mixed get a key/index or null if there wasn't a key/index
925
   */
926 3
  public function getRandomKey()
927
  {
928 3
    return $this->randomKey();
929
  }
930
931
  /**
932
   * alias: for "Arrayy->randomKeys()"
933
   *
934
   * @param int $number
935
   *
936
   * @return Arrayy (Immutable)
937
   */
938 9
  public function getRandomKeys($number)
939
  {
940 9
    return $this->randomKeys($number);
941
  }
942
943
  /**
944
   * alias: for "Arrayy->randomValue()"
945
   *
946
   * @return mixed get a random value or null if there wasn't a value
947
   */
948 3
  public function getRandomValue()
949
  {
950 3
    return $this->randomValue();
951
  }
952
953
  /**
954
   * alias: for "Arrayy->randomValues()"
955
   *
956
   * @param int $number
957
   *
958
   * @return Arrayy (Immutable)
959
   */
960 6
  public function getRandomValues($number)
961
  {
962 6
    return $this->randomValues($number);
963
  }
964
965
  /**
966
   * Group values from a array according to the results of a closure.
967
   *
968
   * @param string $grouper a callable function name
969
   * @param bool   $saveKeys
970
   *
971
   * @return Arrayy (Immutable)
972
   */
973 3
  public function group($grouper, $saveKeys = false)
974
  {
975 3
    $array = (array)$this->array;
976 3
    $result = array();
977
978
    // Iterate over values, group by property/results from closure
979 3
    foreach ($array as $key => $value) {
980 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
981 3
      $newValue = $this->get($groupKey, null, $result);
982
983
      // Add to results
984 3
      if ($groupKey !== null) {
985 2
        if ($saveKeys) {
986 1
          $result[$groupKey] = $newValue;
987 1
          $result[$groupKey][$key] = $value;
988 1
        } else {
989 1
          $result[$groupKey] = $newValue;
990 1
          $result[$groupKey][] = $value;
991
        }
992 2
      }
993
994 3
    }
995
996 3
    return static::create($result);
997
  }
998
999
  /**
1000
   * Check if an array has a given key.
1001
   *
1002
   * @param mixed $key
1003
   *
1004
   * @return bool
1005
   */
1006 19
  public function has($key)
1007
  {
1008
    // Generate unique string to use as marker.
1009 19
    $unFound = (string)uniqid('arrayy', true);
1010
1011 19
    return $this->get($key, $unFound) !== $unFound;
1012
  }
1013
1014
  /**
1015
   * Implodes an array.
1016
   *
1017
   * @param string $with What to implode it with
1018
   *
1019
   * @return string
1020
   */
1021 23
  public function implode($with = '')
1022
  {
1023 23
    return implode($with, $this->array);
1024
  }
1025
1026
  /**
1027
   * Given a list and an iterate-function that returns
1028
   * a key for each element in the list (or a property name),
1029
   * returns an object with an index of each item.
1030
   *
1031
   * Just like groupBy, but for when you know your keys are unique.
1032
   *
1033
   * @param mixed $key
1034
   *
1035
   * @return Arrayy (Immutable)
1036
   */
1037 3
  public function indexBy($key)
1038
  {
1039 3
    $results = array();
1040
1041 3
    foreach ($this->array as $a) {
1042 3
      if (isset($a[$key])) {
1043 2
        $results[$a[$key]] = $a;
1044 2
      }
1045 3
    }
1046
1047 3
    return static::create($results);
1048
  }
1049
1050
  /**
1051
   * alias: for "Arrayy->searchIndex()"
1052
   *
1053
   * @param mixed $value Value to search for
1054
   *
1055
   * @return mixed
1056
   */
1057 4
  public function indexOf($value)
1058
  {
1059 4
    return $this->searchIndex($value);
1060
  }
1061
1062
  /**
1063
   * Get everything but the last..$to items.
1064
   *
1065
   * @param int $to
1066
   *
1067
   * @return Arrayy (Immutable)
1068
   */
1069 12
  public function initial($to = 1)
1070
  {
1071 12
    $slice = count($this->array) - $to;
1072
1073 12
    return $this->firstsImmutable($slice);
1074
  }
1075
1076
  /**
1077
   * Internal mechanics of remove method.
1078
   *
1079
   * @param $key
1080
   *
1081
   * @return boolean
1082
   */
1083 18
  protected function internalRemove($key)
1084
  {
1085
    // Explode keys
1086 18
    $keys = explode('.', $key);
1087
1088
    // Crawl though the keys
1089 18
    while (count($keys) > 1) {
1090
      $key = array_shift($keys);
1091
1092
      if (!$this->has($key)) {
1093
        return false;
1094
      }
1095
1096
      $this->array = &$this->array[$key];
1097
    }
1098
1099 18
    $key = array_shift($keys);
1100
1101 18
    unset($this->array[$key]);
1102
1103 18
    return true;
1104
  }
1105
1106
  /**
1107
   * Internal mechanic of set method.
1108
   *
1109
   * @param string $key
1110
   * @param mixed $value
1111
   *
1112
   * @return bool
1113
   */
1114 17
  protected function internalSet($key, $value)
1115
  {
1116 17
    if (null === $key) {
1117
      return false;
1118
    }
1119
1120
    // init
1121 17
    $array = &$this->array;
1122
1123
    // Explode the keys
1124 17
    $keys = explode('.', $key);
1125
1126
    // Crawl through the keys
1127 17
    while (count($keys) > 1) {
1128 1
      $key = array_shift($keys);
1129
      // If the key doesn't exist at this depth, we will just create an empty array
1130
      // to hold the next value, allowing us to create the arrays to hold final
1131
      // values at the correct depth. Then we'll keep digging into the array.
1132 1
      if (! isset($array[$key]) || ! is_array($array[$key])) {
1133
        $array[$key] = array();
1134
      }
1135 1
      $array = &$array[$key];
1136 1
    }
1137
1138 17
    $array[array_shift($keys)] = $value;
1139
1140 17
    return true;
1141
  }
1142
1143
  /**
1144
   * Return an array with all elements found in input array.
1145
   *
1146
   * @param array $search
1147
   *
1148
   * @return Arrayy (Immutable)
1149
   */
1150 2
  public function intersection(array $search)
1151
  {
1152 2
    $result = array_values(array_intersect($this->array, $search));
1153
1154 2
    return static::create($result);
1155
  }
1156
1157
  /**
1158
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1159
   *
1160
   * @param array $search
1161
   *
1162
   * @return bool
1163
   */
1164 1
  public function intersects(array $search)
1165
  {
1166 1
    return count($this->intersection($search)->array) > 0;
1167
  }
1168
1169
  /** @noinspection ArrayTypeOfParameterByDefaultValueInspection */
1170
  /**
1171
   * Invoke a function on all of an array's values.
1172
   *
1173
   * @param mixed $callable
1174
   * @param mixed $arguments
1175
   *
1176
   * @return Arrayy (Immutable)
1177
   */
1178 1
  public function invoke($callable, $arguments = array())
1179
  {
1180
    // If one argument given for each iteration, create an array for it.
1181 1
    if (!is_array($arguments)) {
1182 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1183 1
    }
1184
1185
    // If the callable has arguments, pass them.
1186 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...
1187 1
      $array = array_map($callable, $this->array, $arguments);
1188 1
    } else {
1189 1
      $array = array_map($callable, $this->array);
1190
    }
1191
1192 1
    return static::create($array);
1193
  }
1194
1195
  /**
1196
   * Check whether array is associative or not.
1197
   *
1198
   * @return bool Returns true if associative, false otherwise
1199
   */
1200 14
  public function isAssoc()
1201
  {
1202 14
    if ($this->isEmpty()) {
1203 2
      return false;
1204
    }
1205
1206 12
    foreach ($this->keys()->getArray() as $key) {
1207 12
      if (!is_string($key)) {
1208 10
        return false;
1209
      }
1210 2
    }
1211
1212 2
    return true;
1213
  }
1214
1215
  /**
1216
   * Check whether the array is empty or not.
1217
   *
1218
   * @return bool Returns true if empty, false otherwise
1219
   */
1220 22
  public function isEmpty()
1221
  {
1222 22
    return !$this->array;
1223
  }
1224
1225
  /**
1226
   * Check if the current array is a multi-array.
1227
   *
1228
   * @return bool
1229
   */
1230 13
  public function isMultiArray()
1231
  {
1232 13
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1233
  }
1234
1235
  /**
1236
   * Check whether array is numeric or not.
1237
   *
1238
   * @return bool Returns true if numeric, false otherwise
1239
   */
1240 4
  public function isNumeric()
1241
  {
1242 4
    if ($this->isEmpty()) {
1243 1
      return false;
1244
    }
1245
1246 3
    foreach ($this->keys() as $key) {
1247 3
      if (!is_int($key)) {
1248 2
        return false;
1249
      }
1250 2
    }
1251
1252 1
    return true;
1253
  }
1254
1255
  /**
1256
   * Get all keys from the current array.
1257
   *
1258
   * @return Arrayy (Immutable)
1259
   */
1260 20
  public function keys()
1261
  {
1262 20
    $array = array_keys((array)$this->array);
1263
1264 20
    return static::create($array);
1265
  }
1266
1267
  /**
1268
   * Get the last value from the current array.
1269
   *
1270
   * @return mixed Return null if there wasn't a element.
1271
   */
1272 4
  public function last()
1273
  {
1274 4
    $result = $this->pop();
1275
1276 4
    if (null === $result) {
1277 1
      return null;
1278
    } else {
1279 3
      return $result;
1280
    }
1281
  }
1282
1283
  /**
1284
   * Get the last value(s) from the current array.
1285
   *
1286
   * @param int|null $number
1287
   *
1288
   * @return Arrayy (Immutable)
1289
   */
1290 12
  public function lastsImmutable($number = null)
1291
  {
1292 12
    if ($number === null) {
1293 8
      $poppedValue = (array)$this->pop();
1294 8
      $arrayy = static::create($poppedValue);
1295 8
    } else {
1296 4
      $number = (int)$number;
1297 4
      $arrayy = $this->rest(-$number);
1298
    }
1299
1300 12
    return $arrayy;
1301
  }
1302
1303
  /**
1304
   * Get the last value(s) from the current array.
1305
   *
1306
   * @param int|null $number
1307
   *
1308
   * @return self (Mutable)
1309
   */
1310 12
  public function lastsMutable($number = null)
1311
  {
1312 12
    if ($number === null) {
1313 8
      $poppedValue = (array)$this->pop();
1314 8
      $this->array = static::create($poppedValue)->array;
1315 8
    } else {
1316 4
      $number = (int)$number;
1317 4
      $this->array = $this->rest(-$number)->array;
1318
    }
1319
1320 12
    return $this;
1321
  }
1322
1323
  /**
1324
   * Count the values from the current array.
1325
   *
1326
   * INFO: only a alias for "$arrayy->size()"
1327
   *
1328
   * @return int
1329
   */
1330 10
  public function length()
1331
  {
1332 10
    return $this->size();
1333
  }
1334
1335
  /**
1336
   * Apply the given function to the every element of the array,
1337
   * collecting the results.
1338
   *
1339
   * @param callable $callable
1340
   *
1341
   * @return Arrayy (Immutable) Arrayy object with modified elements
1342
   */
1343 4
  public function map($callable)
1344
  {
1345 4
    $result = array_map($callable, $this->array);
1346
1347 4
    return static::create($result);
1348
  }
1349
1350
  /**
1351
   * Check if all items in current array match a truth test.
1352
   *
1353
   * @param \Closure $closure
1354
   *
1355
   * @return bool
1356
   */
1357 9 View Code Duplication
  public function matches(\Closure $closure)
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...
1358
  {
1359
    // Reduce the array to only booleans
1360 9
    $array = $this->each($closure);
1361
1362
    // Check the results
1363 9
    if (count($array) === 0) {
1364 2
      return true;
1365
    }
1366
1367 7
    $array = array_search(false, $array->toArray(), false);
1368
1369 7
    return is_bool($array);
1370
  }
1371
1372
  /**
1373
   * Check if any item in the current array matches a truth test.
1374
   *
1375
   * @param \Closure $closure
1376
   *
1377
   * @return bool
1378
   */
1379 9 View Code Duplication
  public function matchesAny(\Closure $closure)
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...
1380
  {
1381
    // Reduce the array to only booleans
1382 9
    $array = $this->each($closure);
1383
1384
    // Check the results
1385 9
    if (count($array) === 0) {
1386 2
      return true;
1387
    }
1388
1389 7
    $array = array_search(true, $array->toArray(), false);
1390
1391 7
    return is_int($array);
1392
  }
1393
1394
  /**
1395
   * Get the max value from an array.
1396
   *
1397
   * @return mixed
1398
   */
1399 10
  public function max()
1400
  {
1401 10
    if ($this->count() === 0) {
1402 1
      return false;
1403
    }
1404
1405 9
    return max($this->array);
1406
  }
1407
1408
  /**
1409
   * Merge the new $array into the current array.
1410
   *
1411
   * - keep key,value from the current array, also if the index is in the new $array
1412
   *
1413
   * @param array $array
1414
   * @param bool  $recursive
1415
   *
1416
   * @return Arrayy (Immutable)
1417
   */
1418 25 View Code Duplication
  public function mergeAppendKeepIndex(array $array = array(), $recursive = false)
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...
1419
  {
1420 25
    if (true === $recursive) {
1421 4
      $result = array_replace_recursive($this->array, $array);
1422 4
    } else {
1423 21
      $result = array_replace($this->array, $array);
1424
    }
1425
1426 25
    return static::create($result);
1427
  }
1428
1429
  /**
1430
   * Merge the new $array into the current array.
1431
   *
1432
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1433
   * - create new indexes
1434
   *
1435
   * @param array $array
1436
   * @param bool  $recursive
1437
   *
1438
   * @return Arrayy (Immutable)
1439
   */
1440 16 View Code Duplication
  public function mergeAppendNewIndex(array $array = array(), $recursive = false)
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...
1441
  {
1442 16
    if (true === $recursive) {
1443 4
      $result = array_merge_recursive($this->array, $array);
1444 4
    } else {
1445 12
      $result = array_merge($this->array, $array);
1446
    }
1447
1448 16
    return static::create($result);
1449
  }
1450
1451
  /**
1452
   * Merge the the current array into the $array.
1453
   *
1454
   * - use key,value from the new $array, also if the index is in the current array
1455
   *
1456
   * @param array $array
1457
   * @param bool  $recursive
1458
   *
1459
   * @return Arrayy (Immutable)
1460
   */
1461 16 View Code Duplication
  public function mergePrependKeepIndex(array $array = array(), $recursive = false)
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...
1462
  {
1463 16
    if (true === $recursive) {
1464 4
      $result = array_replace_recursive($array, $this->array);
1465 4
    } else {
1466 12
      $result = array_replace($array, $this->array);
1467
    }
1468
1469 16
    return static::create($result);
1470
  }
1471
1472
  /**
1473
   * Merge the current array into the new $array.
1474
   *
1475
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1476
   * - create new indexes
1477
   *
1478
   * @param array $array
1479
   * @param bool  $recursive
1480
   *
1481
   * @return Arrayy (Immutable)
1482
   */
1483 16 View Code Duplication
  public function mergePrependNewIndex(array $array = array(), $recursive = false)
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...
1484
  {
1485 16
    if (true === $recursive) {
1486 4
      $result = array_merge_recursive($array, $this->array);
1487 4
    } else {
1488 12
      $result = array_merge($array, $this->array);
1489
    }
1490
1491 16
    return static::create($result);
1492
  }
1493
1494
  /**
1495
   * Get the min value from an array.
1496
   *
1497
   * @return mixed
1498
   */
1499 10
  public function min()
1500
  {
1501 10
    if ($this->count() === 0) {
1502 1
      return false;
1503
    }
1504
1505 9
    return min($this->array);
1506
  }
1507
1508
  /**
1509
   * Pad array to the specified size with a given value.
1510
   *
1511
   * @param int   $size  Size of the result array
1512
   * @param mixed $value Empty value by default
1513
   *
1514
   * @return Arrayy (Immutable) Arrayy object padded to $size with $value
1515
   */
1516 4
  public function pad($size, $value)
1517
  {
1518 4
    $result = array_pad($this->array, $size, $value);
1519
1520 4
    return static::create($result);
1521
  }
1522
1523
  /**
1524
   * Pop a specified value off the end of the current array.
1525
   *
1526
   * @return mixed The popped element from the current array.
1527
   */
1528 16
  public function pop()
1529
  {
1530 16
    return array_pop($this->array);
1531
  }
1532
1533
  /**
1534
   * Prepend a value to the current array.
1535
   *
1536
   * @param mixed $value
1537
   *
1538
   * @return self (Mutable) Return this Arrayy object, with the prepended value.
1539
   */
1540 7
  public function prepend($value)
1541
  {
1542 7
    array_unshift($this->array, $value);
1543
1544 7
    return $this;
1545
  }
1546
1547
  /**
1548
   * Push one or more values onto the end of array at once.
1549
   *
1550
   * @return self (Mutable) Return this Arrayy object, with pushed elements to the end of array.
1551
   */
1552 4 View Code Duplication
  public function push(/* variadic arguments allowed */)
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...
1553
  {
1554 4
    if (func_num_args()) {
1555 4
      $args = array_merge(array(&$this->array), func_get_args());
1556 4
      call_user_func_array('array_push', $args);
1557 4
    }
1558
1559 4
    return $this;
1560
  }
1561
1562
  /**
1563
   * Get a random value from the current array.
1564
   *
1565
   * @param null|int $number how many values you will take?
1566
   *
1567
   * @return Arrayy (Mutable)
1568
   */
1569 16
  public function randomMutable($number = null)
1570
  {
1571 16
    if ($this->count() === 0) {
1572
      return static::create();
1573
    }
1574
1575 16 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...
1576 6
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1577 6
      $this->array = $arrayRandValue;
1578
1579 6
      return $this;
1580
    }
1581
1582 11
    shuffle($this->array);
1583
1584 11
    return $this->firstsMutable($number);
1585
  }
1586
1587
  /**
1588
   * Get a random value from the current array.
1589
   *
1590
   * @param null|int $number how many values you will take?
1591
   *
1592
   * @return Arrayy (Immutable)
1593
   */
1594 17
  public function randomImmutable($number = null)
1595
  {
1596 17
    if ($this->count() === 0) {
1597
      return static::create();
1598
    }
1599
1600 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...
1601 14
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1602
1603 14
      return static::create($arrayRandValue);
1604
    }
1605
1606 5
    $arrayTmp = $this->array;
1607 5
    shuffle($arrayTmp);
1608
1609 5
    return self::create($arrayTmp)->firstsImmutable($number);
1610
  }
1611
1612
  /**
1613
   * Pick a random key/index from the keys of this array.
1614
   *
1615
   *
1616
   * @return mixed get a key/index or null if there wasn't a key/index
1617
   *
1618
   * @throws \RangeException If array is empty
1619
   */
1620 4
  public function randomKey()
1621
  {
1622 4
    $result = $this->randomKeys(1);
1623
1624 4
    if (!isset($result[0])) {
1625
      $result[0] = null;
1626
    }
1627
1628 4
    return $result[0];
1629
  }
1630
1631
  /**
1632
   * Pick a given number of random keys/indexes out of this array.
1633
   *
1634
   * @param int $number The number of keys/indexes (should be <= $this->count())
1635
   *
1636
   * @return Arrayy (Immutable)
1637
   *
1638
   * @throws \RangeException If array is empty
1639
   */
1640 14
  public function randomKeys($number)
1641
  {
1642 14
    $number = (int)$number;
1643 14
    $count = $this->count();
1644
1645 14
    if ($number === 0 || $number > $count) {
1646 3
      throw new \RangeException(
1647 3
          sprintf(
1648 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1649 3
              $number,
1650
              $count
1651 3
          )
1652 3
      );
1653
    }
1654
1655 11
    $result = (array)array_rand($this->array, $number);
1656
1657 11
    return static::create($result);
1658
  }
1659
1660
  /**
1661
   * Pick a random value from the values of this array.
1662
   *
1663
   * @return mixed get a random value or null if there wasn't a value
1664
   */
1665 4
  public function randomValue()
1666
  {
1667 4
    $result = $this->randomImmutable();
1668
1669 4
    if (!isset($result[0])) {
1670
      $result[0] = null;
1671
    }
1672
1673 4
    return $result[0];
1674
  }
1675
1676
  /**
1677
   * Pick a given number of random values out of this array.
1678
   *
1679
   * @param int $number
1680
   *
1681
   * @return Arrayy (Mutable)
1682
   */
1683 7
  public function randomValues($number)
1684
  {
1685 7
    $number = (int)$number;
1686
1687 7
    return $this->randomMutable($number);
1688
  }
1689
1690
  /**
1691
   * Get a random value from an array, with the ability to skew the results.
1692
   *
1693
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
1694
   *
1695
   * @param array    $array
1696
   * @param null|int $number how many values you will take?
1697
   *
1698
   * @return Arrayy (Immutable)
1699
   */
1700 9
  public function randomWeighted(array $array, $number = null)
1701
  {
1702 9
    $options = array();
1703 9
    foreach ($array as $option => $weight) {
1704 9
      if ($this->searchIndex($option) !== false) {
1705 2
        for ($i = 0; $i < $weight; ++$i) {
1706 1
          $options[] = $option;
1707 1
        }
1708 2
      }
1709 9
    }
1710
1711 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
1712
  }
1713
1714
  /**
1715
   * Reduce the current array via callable e.g. anonymous-function.
1716
   *
1717
   * @param mixed $callable
1718
   * @param array $init
1719
   *
1720
   * @return Arrayy (Immutable)
1721
   */
1722 3
  public function reduce($callable, array $init = array())
1723
  {
1724 3
    $result = array_reduce($this->array, $callable, $init);
1725
1726 3
    if ($result === null) {
1727
      $this->array = array();
1728
    } else {
1729 3
      $this->array = (array)$result;
1730
    }
1731
1732 3
    return static::create($this->array);
1733
  }
1734
1735
  /**
1736
   * Create a numerically re-indexed Arrayy object.
1737
   *
1738
   * @return self (Mutable) Return this Arrayy object, with re-indexed array-elements.
1739
   */
1740 9
  public function reindex()
1741
  {
1742 9
    $this->array = array_values($this->array);
1743
1744 9
    return $this;
1745
  }
1746
1747
  /**
1748
   * Return all items that fail the truth test.
1749
   *
1750
   * @param \Closure $closure
1751
   *
1752
   * @return Arrayy (Immutable)
1753
   */
1754 1 View Code Duplication
  public function reject(\Closure $closure)
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...
1755
  {
1756 1
    $filtered = array();
1757
1758 1
    foreach ($this->array as $key => $value) {
1759 1
      if (!$closure($value, $key)) {
1760 1
        $filtered[$key] = $value;
1761 1
      }
1762 1
    }
1763
1764 1
    return static::create($filtered);
1765
  }
1766
1767
  /**
1768
   * Remove a value from the current array (optional using dot-notation).
1769
   *
1770
   * @param mixed $key
1771
   *
1772
   * @return Arrayy (Immutable)
1773
   */
1774 18
  public function remove($key)
1775
  {
1776
    // Recursive call
1777 18
    if (is_array($key)) {
1778
      foreach ($key as $k) {
1779
        $this->internalRemove($k);
1780
      }
1781
1782
      return static::create($this->array);
1783
    }
1784
1785 18
    $this->internalRemove($key);
1786
1787 18
    return static::create($this->array);
1788
  }
1789
1790
  /**
1791
   * Remove the first value from the current array.
1792
   *
1793
   * @return Arrayy (Immutable)
1794
   */
1795 7
  public function removeFirst()
1796
  {
1797 7
    array_shift($this->array);
1798
1799 7
    return static::create($this->array);
1800
  }
1801
1802
  /**
1803
   * Remove the last value from the current array.
1804
   *
1805
   * @return Arrayy (Immutable)
1806
   */
1807 7
  public function removeLast()
1808
  {
1809 7
    array_pop($this->array);
1810
1811 7
    return static::create($this->array);
1812
  }
1813
1814
  /**
1815
   * Removes a particular value from an array (numeric or associative).
1816
   *
1817
   * @param mixed $value
1818
   *
1819
   * @return Arrayy (Immutable)
1820
   */
1821 7
  public function removeValue($value)
1822
  {
1823 7
    $isNumericArray = true;
1824 7
    foreach ($this->array as $key => $item) {
1825 6
      if ($item === $value) {
1826 6
        if (!is_int($key)) {
1827
          $isNumericArray = false;
1828
        }
1829 6
        unset($this->array[$key]);
1830 6
      }
1831 7
    }
1832
1833 7
    if ($isNumericArray) {
1834 7
      $this->array = array_values($this->array);
1835 7
    }
1836
1837 7
    return static::create($this->array);
1838
  }
1839
1840
  /**
1841
   * Replace a key with a new key/value pair.
1842
   *
1843
   * @param $replace
1844
   * @param $key
1845
   * @param $value
1846
   *
1847
   * @return Arrayy (Immutable)
1848
   */
1849 2
  public function replace($replace, $key, $value)
1850
  {
1851 2
    $this->remove($replace);
1852
1853 2
    return $this->set($key, $value);
1854
  }
1855
1856
  /**
1857
   * Create an array using the current array as values and the other array as keys.
1858
   *
1859
   * @param array $keys Keys array
1860
   *
1861
   * @return Arrayy (Immutable) Arrayy object with keys from the other array.
1862
   */
1863 2
  public function replaceAllKeys(array $keys)
1864
  {
1865 2
    $result = array_combine($keys, $this->array);
1866
1867 2
    return static::create($result);
1868
  }
1869
1870
  /**
1871
   * Create an array using the current array as keys and the other array as values.
1872
   *
1873
   * @param array $array Values array
1874
   *
1875
   * @return Arrayy (Immutable) Arrayy object with values from the other array.
1876
   */
1877 2
  public function replaceAllValues(array $array)
1878
  {
1879 2
    $result = array_combine($this->array, $array);
1880
1881 2
    return static::create($result);
1882
  }
1883
1884
  /**
1885
   * Replace the keys in an array with another set.
1886
   *
1887
   * @param array $keys An array of keys matching the array's size
1888
   *
1889
   * @return Arrayy (Immutable)
1890
   */
1891 1
  public function replaceKeys(array $keys)
1892
  {
1893 1
    $values = array_values($this->array);
1894 1
    $result = array_combine($keys, $values);
1895
1896 1
    return static::create($result);
1897
  }
1898
1899
  /**
1900
   * Replace the first matched value in an array.
1901
   *
1902
   * @param mixed $search
1903
   * @param mixed $replacement
1904
   *
1905
   * @return Arrayy (Immutable)
1906
   */
1907 3
  public function replaceOneValue($search, $replacement = '')
1908
  {
1909 3
    $array = $this->array;
1910 3
    $key = array_search($search, $array, true);
1911
1912 3
    if ($key !== false) {
1913 3
      $array[$key] = $replacement;
1914 3
    }
1915
1916 3
    return static::create($array);
1917
  }
1918
1919
  /**
1920
   * Replace values in the current array.
1921
   *
1922
   * @param string $search      The string to replace.
1923
   * @param string $replacement What to replace it with.
1924
   *
1925
   * @return Arrayy (Immutable)
1926
   */
1927 1
  public function replaceValues($search, $replacement = '')
1928
  {
1929 1
    $array = $this->each(
1930
        function ($value) use ($search, $replacement) {
1931 1
          return UTF8::str_replace($search, $replacement, $value);
1932
        }
1933 1
    );
1934
1935 1
    return $array;
1936
  }
1937
1938
  /**
1939
   * Get the last elements from index $from until the end of this array.
1940
   *
1941
   * @param int $from
1942
   *
1943
   * @return Arrayy (Immutable)
1944
   */
1945 16
  public function rest($from = 1)
1946
  {
1947 16
    $result = array_splice($this->array, $from);
1948
1949 16
    return static::create($result);
1950
  }
1951
1952
  /**
1953
   * Return the array in the reverse order.
1954
   *
1955
   * @return self (Mutable) Return this Arrayy object.
1956
   */
1957 7
  public function reverse()
1958
  {
1959 7
    $this->array = array_reverse($this->array);
1960
1961 7
    return $this;
1962
  }
1963
1964
  /**
1965
   * Search for the first index of the current array via $value.
1966
   *
1967
   * @param mixed $value
1968
   *
1969
   * @return mixed
1970
   */
1971 20
  public function searchIndex($value)
1972
  {
1973 20
    return array_search($value, $this->array, true);
1974
  }
1975
1976
  /**
1977
   * Search for the value of the current array via $index.
1978
   *
1979
   * @param mixed $index
1980
   *
1981
   * @return Arrayy (Immutable) will return a empty Arrayy if the value wasn't found
1982
   */
1983 7
  public function searchValue($index)
1984
  {
1985
    // init
1986 7
    $return = array();
1987
1988 7
    if (null !== $index) {
1989 7
      $keyExists = isset($this->array[$index]);
1990
1991 7
      if ($keyExists !== false) {
1992 5
        $return = array($this->array[$index]);
1993 5
      }
1994 7
    }
1995
1996 7
    return static::create($return);
1997
  }
1998
1999
  /**
2000
   * Set a value for the current array (optional using dot-notation).
2001
   *
2002
   * @param string $key   The key to set
2003
   * @param mixed  $value Its value
2004
   *
2005
   * @return Arrayy (Immutable)
2006
   */
2007 17
  public function set($key, $value)
2008
  {
2009 17
    $this->internalSet($key, $value);
2010
2011 17
    return static::create($this->array);
2012
  }
2013
2014
  /**
2015
   * Get a value from a array and set it if it was not.
2016
   *
2017
   * WARNING: this method only set the value, if the $key is not already set
2018
   *
2019
   * @param string $key      The key
2020
   * @param mixed  $fallback The default value to set if it isn't
2021
   *
2022
   * @return mixed (Mutable)
2023
   */
2024 10
  public function setAndGet($key, $fallback = null)
2025
  {
2026
    // If the key doesn't exist, set it
2027 10
    if (!$this->has($key)) {
2028 5
      $this->array = $this->set($key, $fallback)->getArray();
2029 5
    }
2030
2031 10
    return $this->get($key);
2032
  }
2033
2034
  /**
2035
   * Shifts a specified value off the beginning of array.
2036
   *
2037
   * @return mixed A shifted element from the current array.
2038
   */
2039 4
  public function shift()
2040
  {
2041 4
    return array_shift($this->array);
2042
  }
2043
2044
  /**
2045
   * Shuffle the current array.
2046
   *
2047
   * @return Arrayy (Immutable)
2048
   */
2049 1
  public function shuffle()
2050
  {
2051 1
    $array = $this->array;
2052
2053 1
    shuffle($array);
2054
2055 1
    return static::create($array);
2056
  }
2057
2058
  /**
2059
   * Get the size of an array.
2060
   *
2061
   * @return int
2062
   */
2063 109
  public function size()
2064
  {
2065 109
    return count($this->array);
2066
  }
2067
2068
  /**
2069
   * Extract a slice of the array.
2070
   *
2071
   * @param int      $offset       Slice begin index
2072
   * @param int|null $length       Length of the slice
2073
   * @param bool     $preserveKeys Whether array keys are preserved or no
2074
   *
2075
   * @return static A slice of the original array with length $length
2076
   */
2077 4
  public function slice($offset, $length = null, $preserveKeys = false)
2078
  {
2079 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
2080
2081 4
    return static::create($result);
2082
  }
2083
2084
  /**
2085
   * Sort the current array and optional you can keep the keys.
2086
   *
2087
   * @param integer $direction use SORT_ASC or SORT_DESC
2088
   * @param integer $strategy
2089
   * @param bool       $keepKeys
2090
   *
2091
   * @return self (Mutable) Return this Arrayy object.
2092
   */
2093 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2094
  {
2095 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2096
2097 19
    return $this;
2098
  }
2099
2100
  /**
2101
   * Sort the current array by key.
2102
   *
2103
   * @link http://php.net/manual/en/function.ksort.php
2104
   * @link http://php.net/manual/en/function.krsort.php
2105
   *
2106
   * @param int|string $direction use SORT_ASC or SORT_DESC
2107
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2108
   *
2109
   * @return self (Mutable) Return this Arrayy object.
2110
   */
2111 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2112
  {
2113 18
    $this->sorterKeys($this->array, $direction, $strategy);
2114
2115 18
    return $this;
2116
  }
2117
2118
  /**
2119
   * Sort the current array by value.
2120
   *
2121
   * @param int $direction use SORT_ASC or SORT_DESC
2122
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2123
   *
2124
   * @return Arrayy (Immutable)
2125
   */
2126 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2127
  {
2128 1
    return $this->sort($direction, $strategy, true);
2129
  }
2130
2131
  /**
2132
   * Sort the current array by value.
2133
   *
2134
   * @param int $direction use SORT_ASC or SORT_DESC
2135
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2136
   *
2137
   * @return Arrayy (Immutable)
2138
   */
2139 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2140
  {
2141 1
    return $this->sort($direction, $strategy, false);
2142
  }
2143
2144
  /**
2145
   * Sort a array by value, by a closure or by a property.
2146
   *
2147
   * - If the sorter is null, the array is sorted naturally.
2148
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2149
   *
2150
   * @param null       $sorter
2151
   * @param string|int $direction
2152
   * @param int        $strategy
2153
   *
2154
   * @return Arrayy (Immutable)
2155
   */
2156 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2157
  {
2158 1
    $array = (array)$this->array;
2159 1
    $direction = $this->getDirection($direction);
2160
2161
    // Transform all values into their results.
2162 1
    if ($sorter) {
2163 1
      $arrayy = new self($array);
2164
2165 1
      $that = $this;
2166 1
      $results = $arrayy->each(
2167
          function ($value) use ($sorter, $that) {
2168 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2169
          }
2170 1
      );
2171
2172 1
      $results = $results->getArray();
2173 1
    } else {
2174 1
      $results = $array;
2175
    }
2176
2177
    // Sort by the results and replace by original values
2178 1
    array_multisort($results, $direction, $strategy, $array);
2179
2180 1
    return static::create($array);
2181
  }
2182
2183
  /**
2184
   * sorting keys
2185
   *
2186
   * @param array $elements
2187
   * @param int   $direction
2188
   * @param int   $strategy
2189
   */
2190 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2191
  {
2192 18
    $direction = $this->getDirection($direction);
2193
2194
    switch ($direction) {
2195 18
      case 'desc':
2196 18
      case SORT_DESC:
2197 6
        krsort($elements, $strategy);
2198 6
        break;
2199 13
      case 'asc':
2200 13
      case SORT_ASC:
2201 13
      default:
2202 13
        ksort($elements, $strategy);
2203 13
    }
2204 18
  }
2205
2206
  /**
2207
   * @param array      &$elements
2208
   * @param int|string $direction
2209
   * @param int        $strategy
2210
   * @param bool       $keepKeys
2211
   */
2212 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2213
  {
2214 19
    $direction = $this->getDirection($direction);
2215
2216 19
    if (!$strategy) {
2217 19
      $strategy = SORT_REGULAR;
2218 19
    }
2219
2220
    switch ($direction) {
2221 19
      case 'desc':
2222 19
      case SORT_DESC:
2223 9
        if ($keepKeys) {
2224 5
          arsort($elements, $strategy);
2225 5
        } else {
2226 4
          rsort($elements, $strategy);
2227
        }
2228 9
        break;
2229 10
      case 'asc':
2230 10
      case SORT_ASC:
2231 10
      default:
2232 10
        if ($keepKeys) {
2233 4
          asort($elements, $strategy);
2234 4
        } else {
2235 6
          sort($elements, $strategy);
2236
        }
2237 10
    }
2238 19
  }
2239
2240
  /**
2241
   * Split an array in the given amount of pieces.
2242
   *
2243
   * @param int  $numberOfPieces
2244
   * @param bool $keepKeys
2245
   *
2246
   * @return Arrayy (Immutable)
2247
   */
2248 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2249
  {
2250 1
    if (count($this->array) === 0) {
2251 1
      $result = array();
2252 1
    } else {
2253 1
      $numberOfPieces = (int)$numberOfPieces;
2254 1
      $splitSize = ceil(count($this->array) / $numberOfPieces);
2255 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
2256
    }
2257
2258 1
    return static::create($result);
2259
  }
2260
2261
  /**
2262
   * alias: for "Arrayy->getArray()"
2263
   */
2264 153
  public function toArray()
2265
  {
2266 153
    return $this->getArray();
2267
  }
2268
2269
  /**
2270
   * Convert the current array to JSON.
2271
   *
2272
   * @param null $options e.g. JSON_PRETTY_PRINT
2273
   *
2274
   * @return string
2275
   */
2276 5
  public function toJson($options = null)
2277
  {
2278 5
    return UTF8::json_encode($this->array, $options);
2279
  }
2280
2281
  /**
2282
   * Implodes array to a string with specified separator.
2283
   *
2284
   * @param string $separator The element's separator
2285
   *
2286
   * @return string The string representation of array, separated by ","
2287
   */
2288 15
  public function toString($separator = ',')
2289
  {
2290 15
    return $this->implode($separator);
2291
  }
2292
2293
  /**
2294
   * Return a duplicate free copy of the current array.
2295
   *
2296
   * @return Arrayy (Mutable)
2297
   */
2298 7
  public function unique()
2299
  {
2300 7
    $this->array = array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce($this->arra...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...
2301 7
        $this->array,
2302 7
        function ($resultArray, $value) {
2303 6
          if (in_array($value, $resultArray, true) === false) {
2304 6
            $resultArray[] = $value;
2305 6
          }
2306
2307 6
          return $resultArray;
2308 7
        },
2309 7
        array()
2310 7
    );
2311
2312 7
    if ($this->array === null) {
2313
      $this->array = array();
2314
    } else {
2315 7
      $this->array = (array)$this->array;
2316
    }
2317
2318 7
    return $this;
2319
  }
2320
2321
  /**
2322
   * Prepends one or more values to the beginning of array at once.
2323
   *
2324
   * @return self (Mutable) Return this Arrayy object, with prepended elements to the beginning of array.
2325
   */
2326 4 View Code Duplication
  public function unshift(/* variadic arguments allowed */)
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...
2327
  {
2328 4
    if (func_num_args()) {
2329 4
      $args = array_merge(array(&$this->array), func_get_args());
2330 4
      call_user_func_array('array_unshift', $args);
2331 4
    }
2332
2333 4
    return $this;
2334
  }
2335
2336
  /**
2337
   * Get all values from a array.
2338
   *
2339
   * @return Arrayy (Immutable)
2340
   */
2341 1
  public function values()
2342
  {
2343 1
    $array = array_values((array)$this->array);
2344
2345 1
    return static::create($array);
2346
  }
2347
2348
  /**
2349
   * Apply the given function to every element in the array, discarding the results.
2350
   *
2351
   * @param callable $callable
2352
   * @param bool     $recursive Whether array will be walked recursively or no
2353
   *
2354
   * @return self (Mutable) Return this Arrayy object, with modified elements
2355
   */
2356 9
  public function walk($callable, $recursive = false)
2357
  {
2358 9
    if (true === $recursive) {
2359 4
      array_walk_recursive($this->array, $callable);
2360 4
    } else {
2361 5
      array_walk($this->array, $callable);
2362
    }
2363
2364 9
    return $this;
2365
  }
2366
2367
2368
}
2369