Completed
Branch master (9bd847)
by Lars
03:32 queued 01:22
created

Arrayy::rest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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