Completed
Push — master ( 138724...f1cce9 )
by Lars
02:40
created

Arrayy::removeLast()   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 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
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
    } 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
    }
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
    }
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
    }
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 8
        }
298
    );
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
    }
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
      }
428
429
    } else {
430 7
      $array = explode($delimiter, $str);
431
    }
432
433
    // trim all string in the array
434 8
    array_walk(
435
        $array,
436
        function (&$val) {
437 8
          if (is_string($val)) {
438 8
            $val = trim($val);
439
          }
440 8
        }
441
    );
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
    }
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 3
        break;
538
      }
539
    }
540
541 4
    return $isExists;
542
  }
543
544
  /**
545
   * create a fallback for array
546
   *
547
   * 1. fallback to empty array, if there is nothing
548
   * 2. cast a String or Object with "__toString" into an array
549
   * 3. call "__toArray" on Object, if the method exists
550
   * 4. throw a "InvalidArgumentException"-Exception
551
   *
552
   * @param $array
553
   *
554
   * @return array
555
   */
556 698
  protected function fallbackForArray(&$array)
557
  {
558 698
    if (is_array($array)) {
559 695
      return $array;
560
    }
561
562 5
    if ($array instanceof self) {
563 1
      return $array->getArray();
564
    }
565
566 4
    if (!$array) {
567 1
      return array();
568
    }
569
570
    if (
571 3
        is_string($array)
572
        ||
573 3
        (is_object($array) && method_exists($array, '__toString'))
574
    ) {
575 1
      return (array)$array;
576
    }
577
578 2
    if ($array instanceof ArrayAccess) {
579
      return self::createFromObject($array);
580
    }
581
582 2
    if (is_object($array) && method_exists($array, '__toArray')) {
583
      return (array)$array->__toArray();
584
    }
585
586 2
    throw new \InvalidArgumentException(
587 2
        'Passed value should be a array'
588
    );
589
  }
590
591
  /**
592
   * Find all items in an array that pass the truth test.
593
   *
594
   * @param \Closure|null $closure
595
   *
596
   * @return Arrayy (Immutable)
597
   */
598 8
  public function filter($closure = null)
599
  {
600 8
    if (!$closure) {
601 1
      return $this->clean();
602
    }
603
604 8
    $array = array_filter($this->array, $closure);
605
606 8
    return static::create($array);
607
  }
608
609
  /**
610
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
611
   * within that.
612
   *
613
   * @param        $property
614
   * @param        $value
615
   * @param string $comparisonOp
616
   *                            'eq' (equals),<br />
617
   *                            'gt' (greater),<br />
618
   *                            'gte' || 'ge' (greater or equals),<br />
619
   *                            'lt' (less),<br />
620
   *                            'lte' || 'le' (less or equals),<br />
621
   *                            'ne' (not equals),<br />
622
   *                            'contains',<br />
623
   *                            'notContains',<br />
624
   *                            'newer' (via strtotime),<br />
625
   *                            'older' (via strtotime),<br />
626
   *
627
   * @return Arrayy (Immutable)
628
   */
629 1
  public function filterBy($property, $value, $comparisonOp = null)
630
  {
631 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...
632 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
633
    }
634
635
    $ops = array(
636
        'eq'          => function ($item, $prop, $value) {
637 1
          return $item[$prop] === $value;
638 1
        },
639
        'gt'          => function ($item, $prop, $value) {
640
          return $item[$prop] > $value;
641 1
        },
642
        'ge'         => function ($item, $prop, $value) {
643
          return $item[$prop] >= $value;
644 1
        },
645
        'gte'         => function ($item, $prop, $value) {
646
          return $item[$prop] >= $value;
647 1
        },
648
        'lt'          => function ($item, $prop, $value) {
649 1
          return $item[$prop] < $value;
650 1
        },
651
        'le'         => function ($item, $prop, $value) {
652
          return $item[$prop] <= $value;
653 1
        },
654
        'lte'         => function ($item, $prop, $value) {
655
          return $item[$prop] <= $value;
656 1
        },
657
        'ne'          => function ($item, $prop, $value) {
658
          return $item[$prop] !== $value;
659 1
        },
660
        'contains'    => function ($item, $prop, $value) {
661 1
          return in_array($item[$prop], (array)$value, true);
662 1
        },
663
        'notContains' => function ($item, $prop, $value) {
664
          return !in_array($item[$prop], (array)$value, true);
665 1
        },
666
        'newer'       => function ($item, $prop, $value) {
667
          return strtotime($item[$prop]) > strtotime($value);
668 1
        },
669
        'older'       => function ($item, $prop, $value) {
670
          return strtotime($item[$prop]) < strtotime($value);
671 1
        },
672
    );
673
674 1
    $result = array_values(
675
        array_filter(
676 1
            (array)$this->array,
677
            function ($item) use (
678 1
                $property,
679 1
                $value,
680 1
                $ops,
681 1
                $comparisonOp
682
            ) {
683 1
              $item = (array)$item;
684 1
              $itemArrayy = new Arrayy($item);
685 1
              $item[$property] = $itemArrayy->get($property, array());
686
687 1
              return $ops[$comparisonOp]($item, $property, $value);
688 1
            }
689
        )
690
    );
691
692 1
    return static::create($result);
693
  }
694
695
  /**
696
   * Find the first item in an array that passes the truth test,
697
   *  otherwise return false
698
   *
699
   * @param \Closure $closure
700
   *
701
   * @return mixed|false false if we did not find the value
702
   */
703 8
  public function find(\Closure $closure)
704
  {
705 8
    foreach ($this->array as $key => $value) {
706 6
      if ($closure($value, $key)) {
707 6
        return $value;
708
      }
709
    }
710
711 3
    return false;
712
  }
713
714
  /**
715
   * find by ...
716
   *
717
   * @param        $property
718
   * @param        $value
719
   * @param string $comparisonOp
720
   *
721
   * @return Arrayy (Immutable)
722
   */
723
  public function findBy($property, $value, $comparisonOp = 'eq')
724
  {
725
    $array = $this->filterBy($property, $value, $comparisonOp);
726
727
    return static::create($array);
0 ignored issues
show
Documentation introduced by
$array is of type object<Arrayy\Arrayy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
728
  }
729
730
  /**
731
   * Get the first value from the current array.
732
   *
733
   * @return mixed Return null if there wasn't a element.
734
   */
735 13
  public function first()
736
  {
737 13
    $result = array_shift($this->array);
738
739 13
    if (null === $result) {
740 3
      return null;
741
    } else {
742 10
      return $result;
743
    }
744
  }
745
746
  /**
747
   * Get the first value(s) from the current array.
748
   *
749
   * @param int|null $number how many values you will take?
750
   *
751
   * @return self (Mutable)
752
   */
753 26
  public function firstsMutable($number = null)
754
  {
755 26
    if ($number === null) {
756 11
      $this->array = (array)array_shift($this->array);
757
    } else {
758 15
      $number = (int)$number;
759 15
      $this->array = array_splice($this->array, 0, $number, true);
760
    }
761
762 26
    return $this;
763
  }
764
765
  /**
766
   * Get the first value(s) from the current array.
767
   *
768
   * @param int|null $number how many values you will take?
769
   *
770
   * @return Arrayy (Immutable)
771
   */
772 28
  public function firstsImmutable($number = null)
773
  {
774 28
    if ($number === null) {
775 7
      $array = (array)array_shift($this->array);
776
    } else {
777 21
      $number = (int)$number;
778 21
      $array = array_splice($this->array, 0, $number, true);
779
    }
780
781 28
    return static::create($array);
782
  }
783
784
  /**
785
   * Exchanges all keys with their associated values in an array.
786
   *
787
   * @return Arrayy (Immutable)
788
   */
789 1
  public function flip()
790
  {
791 1
    $result = array_flip($this->array);
792
793 1
    return static::create($result);
794
  }
795
796
  /**
797
   * Get a value from an array (optional using dot-notation).
798
   *
799
   * @param string $key     The key to look for.
800
   * @param mixed  $default Default value to fallback to.
801
   * @param array  $array   The array to get from, if it's set to "null" we use the current array from the class.
802
   *
803
   * @return mixed
804
   */
805 34
  public function get($key, $default = null, $array = null)
806
  {
807 34
    if (is_array($array) === true) {
808 3
      $usedArray = $array;
809
    } else {
810 32
      $usedArray = $this->array;
811
    }
812
813 34
    if (null === $key) {
814 1
      return $usedArray;
815
    }
816
817 34
    if (isset($usedArray[$key])) {
818 23
      return $usedArray[$key];
819
    }
820
821
    // Crawl through array, get key according to object or not
822 19
    foreach (explode('.', $key) as $segment) {
823 19
      if (!isset($usedArray[$segment])) {
824 17
        return $default instanceof Closure ? $default() : $default;
825
      }
826
827 2
      $usedArray = $usedArray[$segment];
828
    }
829
830 2
    return $usedArray;
831
  }
832
833
  /**
834
   * Get the current array from the "Arrayy"-object.
835
   *
836
   * @return array
837
   */
838 475
  public function getArray()
839
  {
840 475
    return $this->array;
841
  }
842
843
  /**
844
   * Returns the values from a single column of the input array, identified by
845
   * the $columnKey, can be used to extract data-columns from multi-arrays.
846
   *
847
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
848
   * array by the values from the $indexKey column in the input array.
849
   *
850
   * @param mixed $columnKey
851
   * @param mixed $indexKey
852
   *
853
   * @return Arrayy (Immutable)
854
   */
855 1
  public function getColumn($columnKey = null, $indexKey = null)
856
  {
857 1
    $result = array_column($this->array, $columnKey, $indexKey);
858
859 1
    return static::create($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by array_column($this->array, $columnKey, $indexKey) on line 857 can also be of type false or null; however, Arrayy\Arrayy::create() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
860
  }
861
862
  /**
863
   * Get correct PHP constant for direction.
864
   *
865
   * @param int|string $direction
866
   *
867
   * @return int
868
   */
869 38
  protected function getDirection($direction)
870
  {
871 38
    if (is_string($direction)) {
872 10
      $direction = strtolower($direction);
873
874 10
      if ($direction === 'desc') {
875 2
        $direction = SORT_DESC;
876
      } else {
877 8
        $direction = SORT_ASC;
878
      }
879
    }
880
881
    if (
882 38
        $direction !== SORT_DESC
883
        &&
884 38
        $direction !== SORT_ASC
885
    ) {
886
      $direction = SORT_ASC;
887
    }
888
889 38
    return $direction;
890
  }
891
892
  /**
893
   * alias: for "Arrayy->keys()"
894
   *
895
   * @return Arrayy (Immutable)
896
   */
897
  public function getKeys()
898
  {
899
    return $this->keys();
900
  }
901
902
  /**
903
   * alias: for "Arrayy->random()"
904
   *
905
   * @return Arrayy (Immutable)
906
   */
907 3
  public function getRandom()
908
  {
909 3
    return $this->randomImmutable();
910
  }
911
912
  /**
913
   * alias: for "Arrayy->randomKey()"
914
   *
915
   * @return mixed get a key/index or null if there wasn't a key/index
916
   */
917 3
  public function getRandomKey()
918
  {
919 3
    return $this->randomKey();
920
  }
921
922
  /**
923
   * alias: for "Arrayy->randomKeys()"
924
   *
925
   * @param int $number
926
   *
927
   * @return Arrayy (Immutable)
928
   */
929 9
  public function getRandomKeys($number)
930
  {
931 9
    return $this->randomKeys($number);
932
  }
933
934
  /**
935
   * alias: for "Arrayy->randomValue()"
936
   *
937
   * @return mixed get a random value or null if there wasn't a value
938
   */
939 3
  public function getRandomValue()
940
  {
941 3
    return $this->randomValue();
942
  }
943
944
  /**
945
   * alias: for "Arrayy->randomValues()"
946
   *
947
   * @param int $number
948
   *
949
   * @return Arrayy (Immutable)
950
   */
951 6
  public function getRandomValues($number)
952
  {
953 6
    return $this->randomValues($number);
954
  }
955
956
  /**
957
   * Group values from a array according to the results of a closure.
958
   *
959
   * @param string $grouper a callable function name
960
   * @param bool   $saveKeys
961
   *
962
   * @return Arrayy (Immutable)
963
   */
964 3
  public function group($grouper, $saveKeys = false)
965
  {
966 3
    $array = (array)$this->array;
967 3
    $result = array();
968
969
    // Iterate over values, group by property/results from closure
970 3
    foreach ($array as $key => $value) {
971 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
972 3
      $newValue = $this->get($groupKey, null, $result);
973
974
      // Add to results
975 3
      if ($groupKey !== null) {
976 2
        if ($saveKeys) {
977 1
          $result[$groupKey] = $newValue;
978 1
          $result[$groupKey][$key] = $value;
979
        } else {
980 1
          $result[$groupKey] = $newValue;
981 3
          $result[$groupKey][] = $value;
982
        }
983
      }
984
985
    }
986
987 3
    return static::create($result);
988
  }
989
990
  /**
991
   * Check if an array has a given key.
992
   *
993
   * @param mixed $key
994
   *
995
   * @return bool
996
   */
997 19
  public function has($key)
998
  {
999
    // Generate unique string to use as marker.
1000 19
    $unFound = (string)uniqid('arrayy', true);
1001
1002 19
    return $this->get($key, $unFound) !== $unFound;
1003
  }
1004
1005
  /**
1006
   * Implodes an array.
1007
   *
1008
   * @param string $with What to implode it with
1009
   *
1010
   * @return string
1011
   */
1012 23
  public function implode($with = '')
1013
  {
1014 23
    return implode($with, $this->array);
1015
  }
1016
1017
  /**
1018
   * Given a list and an iterate-function that returns
1019
   * a key for each element in the list (or a property name),
1020
   * returns an object with an index of each item.
1021
   *
1022
   * Just like groupBy, but for when you know your keys are unique.
1023
   *
1024
   * @param mixed $key
1025
   *
1026
   * @return Arrayy (Immutable)
1027
   */
1028 3
  public function indexBy($key)
1029
  {
1030 3
    $results = array();
1031
1032 3
    foreach ($this->array as $a) {
1033 3
      if (isset($a[$key])) {
1034 3
        $results[$a[$key]] = $a;
1035
      }
1036
    }
1037
1038 3
    return static::create($results);
1039
  }
1040
1041
  /**
1042
   * alias: for "Arrayy->searchIndex()"
1043
   *
1044
   * @param mixed $value Value to search for
1045
   *
1046
   * @return mixed
1047
   */
1048 4
  public function indexOf($value)
1049
  {
1050 4
    return $this->searchIndex($value);
1051
  }
1052
1053
  /**
1054
   * Get everything but the last..$to items.
1055
   *
1056
   * @param int $to
1057
   *
1058
   * @return Arrayy (Immutable)
1059
   */
1060 12
  public function initial($to = 1)
1061
  {
1062 12
    $slice = count($this->array) - $to;
1063
1064 12
    return $this->firstsImmutable($slice);
1065
  }
1066
1067
  /**
1068
   * Internal mechanics of remove method.
1069
   *
1070
   * @param $key
1071
   *
1072
   * @return boolean
1073
   */
1074 18
  protected function internalRemove($key)
1075
  {
1076
    // Explode keys
1077 18
    $keys = explode('.', $key);
1078
1079
    // Crawl though the keys
1080 18
    while (count($keys) > 1) {
1081
      $key = array_shift($keys);
1082
1083
      if (!$this->has($key)) {
1084
        return false;
1085
      }
1086
1087
      $this->array = &$this->array[$key];
1088
    }
1089
1090 18
    $key = array_shift($keys);
1091
1092 18
    unset($this->array[$key]);
1093
1094 18
    return true;
1095
  }
1096
1097
  /**
1098
   * Internal mechanic of set method.
1099
   *
1100
   * @param string $key
1101
   * @param mixed $value
1102
   *
1103
   * @return bool
1104
   */
1105 17
  protected function internalSet($key, $value)
1106
  {
1107 17
    if (null === $key) {
1108
      return false;
1109
    }
1110
1111
    // init
1112 17
    $array = &$this->array;
1113
1114
    // Explode the keys
1115 17
    $keys = explode('.', $key);
1116
1117
    // Crawl through the keys
1118 17
    while (count($keys) > 1) {
1119 1
      $key = array_shift($keys);
1120
      // If the key doesn't exist at this depth, we will just create an empty array
1121
      // to hold the next value, allowing us to create the arrays to hold final
1122
      // values at the correct depth. Then we'll keep digging into the array.
1123 1
      if (! isset($array[$key]) || ! is_array($array[$key])) {
1124
        $array[$key] = array();
1125
      }
1126 1
      $array = &$array[$key];
1127
    }
1128
1129 17
    $array[array_shift($keys)] = $value;
1130
1131 17
    return true;
1132
  }
1133
1134
  /**
1135
   * Return an array with all elements found in input array.
1136
   *
1137
   * @param array $search
1138
   *
1139
   * @return Arrayy (Immutable)
1140
   */
1141 2
  public function intersection(array $search)
1142
  {
1143 2
    $result = array_values(array_intersect($this->array, $search));
1144
1145 2
    return static::create($result);
1146
  }
1147
1148
  /**
1149
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1150
   *
1151
   * @param array $search
1152
   *
1153
   * @return bool
1154
   */
1155 1
  public function intersects(array $search)
1156
  {
1157 1
    return count($this->intersection($search)->array) > 0;
1158
  }
1159
1160
  /**
1161
   * Invoke a function on all of an array's values.
1162
   *
1163
   * @param mixed $callable
1164
   * @param array $arguments
1165
   *
1166
   * @return Arrayy (Immutable)
1167
   */
1168 1
  public function invoke($callable, $arguments = array())
1169
  {
1170
    // If one argument given for each iteration, create an array for it.
1171 1
    if (!is_array($arguments)) {
1172 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1173
    }
1174
1175
    // If the callable has arguments, pass them.
1176 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...
1177 1
      $array = array_map($callable, $this->array, $arguments);
1178
    } else {
1179 1
      $array = array_map($callable, $this->array);
1180
    }
1181
1182 1
    return static::create($array);
1183
  }
1184
1185
  /**
1186
   * Check whether array is associative or not.
1187
   *
1188
   * @return bool Returns true if associative, false otherwise
1189
   */
1190 14
  public function isAssoc()
1191
  {
1192 14
    if ($this->isEmpty()) {
1193 2
      return false;
1194
    }
1195
1196 12
    foreach ($this->keys()->getArray() as $key) {
1197 12
      if (!is_string($key)) {
1198 12
        return false;
1199
      }
1200
    }
1201
1202 2
    return true;
1203
  }
1204
1205
  /**
1206
   * Check whether the array is empty or not.
1207
   *
1208
   * @return bool Returns true if empty, false otherwise
1209
   */
1210 22
  public function isEmpty()
1211
  {
1212 22
    return !$this->array;
1213
  }
1214
1215
  /**
1216
   * Check if the current array is a multi-array.
1217
   *
1218
   * @return bool
1219
   */
1220 13
  public function isMultiArray()
1221
  {
1222 13
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1223
  }
1224
1225
  /**
1226
   * Check whether array is numeric or not.
1227
   *
1228
   * @return bool Returns true if numeric, false otherwise
1229
   */
1230 4
  public function isNumeric()
1231
  {
1232 4
    if ($this->isEmpty()) {
1233 1
      return false;
1234
    }
1235
1236 3
    foreach ($this->keys() as $key) {
1237 3
      if (!is_int($key)) {
1238 3
        return false;
1239
      }
1240
    }
1241
1242 1
    return true;
1243
  }
1244
1245
  /**
1246
   * Get all keys from the current array.
1247
   *
1248
   * @return Arrayy (Immutable)
1249
   */
1250 20
  public function keys()
1251
  {
1252 20
    $array = array_keys((array)$this->array);
1253
1254 20
    return static::create($array);
1255
  }
1256
1257
  /**
1258
   * Get the last value from the current array.
1259
   *
1260
   * @return mixed Return null if there wasn't a element.
1261
   */
1262 4
  public function last()
1263
  {
1264 4
    $result = $this->pop();
1265
1266 4
    if (null === $result) {
1267 1
      return null;
1268
    } else {
1269 3
      return $result;
1270
    }
1271
  }
1272
1273
  /**
1274
   * Get the last value(s) from the current array.
1275
   *
1276
   * @param int|null $number
1277
   *
1278
   * @return Arrayy (Immutable)
1279
   */
1280 12
  public function lastsImmutable($number = null)
1281
  {
1282 12
    if ($number === null) {
1283 8
      $poppedValue = (array)$this->pop();
1284 8
      $arrayy = static::create($poppedValue);
1285
    } else {
1286 4
      $number = (int)$number;
1287 4
      $arrayy = $this->rest(-$number);
1288
    }
1289
1290 12
    return $arrayy;
1291
  }
1292
1293
  /**
1294
   * Get the last value(s) from the current array.
1295
   *
1296
   * @param int|null $number
1297
   *
1298
   * @return self (Mutable)
1299
   */
1300 12
  public function lastsMutable($number = null)
1301
  {
1302 12
    if ($number === null) {
1303 8
      $poppedValue = (array)$this->pop();
1304 8
      $this->array = static::create($poppedValue)->array;
1305
    } else {
1306 4
      $number = (int)$number;
1307 4
      $this->array = $this->rest(-$number)->array;
1308
    }
1309
1310 12
    return $this;
1311
  }
1312
1313
  /**
1314
   * Count the values from the current array.
1315
   *
1316
   * INFO: only a alias for "$arrayy->size()"
1317
   *
1318
   * @return int
1319
   */
1320 10
  public function length()
1321
  {
1322 10
    return $this->size();
1323
  }
1324
1325
  /**
1326
   * Apply the given function to the every element of the array,
1327
   * collecting the results.
1328
   *
1329
   * @param callable $callable
1330
   *
1331
   * @return Arrayy (Immutable) Arrayy object with modified elements
1332
   */
1333 4
  public function map($callable)
1334
  {
1335 4
    $result = array_map($callable, $this->array);
1336
1337 4
    return static::create($result);
1338
  }
1339
1340
  /**
1341
   * Check if all items in current array match a truth test.
1342
   *
1343
   * @param \Closure $closure
1344
   *
1345
   * @return bool
1346
   */
1347 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...
1348
  {
1349
    // Reduce the array to only booleans
1350 9
    $array = $this->each($closure);
1351
1352
    // Check the results
1353 9
    if (count($array) === 0) {
1354 2
      return true;
1355
    }
1356
1357 7
    $array = array_search(false, $array->toArray(), false);
1358
1359 7
    return is_bool($array);
1360
  }
1361
1362
  /**
1363
   * Check if any item in the current array matches a truth test.
1364
   *
1365
   * @param \Closure $closure
1366
   *
1367
   * @return bool
1368
   */
1369 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...
1370
  {
1371
    // Reduce the array to only booleans
1372 9
    $array = $this->each($closure);
1373
1374
    // Check the results
1375 9
    if (count($array) === 0) {
1376 2
      return true;
1377
    }
1378
1379 7
    $array = array_search(true, $array->toArray(), false);
1380
1381 7
    return is_int($array);
1382
  }
1383
1384
  /**
1385
   * Get the max value from an array.
1386
   *
1387
   * @return mixed
1388
   */
1389 10
  public function max()
1390
  {
1391 10
    if ($this->count() === 0) {
1392 1
      return false;
1393
    }
1394
1395 9
    return max($this->array);
1396
  }
1397
1398
  /**
1399
   * Merge the new $array into the current array.
1400
   *
1401
   * - keep key,value from the current array, also if the index is in the new $array
1402
   *
1403
   * @param array $array
1404
   * @param bool  $recursive
1405
   *
1406
   * @return Arrayy (Immutable)
1407
   */
1408 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...
1409
  {
1410 25
    if (true === $recursive) {
1411 4
      $result = array_replace_recursive($this->array, $array);
1412
    } else {
1413 21
      $result = array_replace($this->array, $array);
1414
    }
1415
1416 25
    return static::create($result);
1417
  }
1418
1419
  /**
1420
   * Merge the new $array into the current array.
1421
   *
1422
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1423
   * - create new indexes
1424
   *
1425
   * @param array $array
1426
   * @param bool  $recursive
1427
   *
1428
   * @return Arrayy (Immutable)
1429
   */
1430 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...
1431
  {
1432 16
    if (true === $recursive) {
1433 4
      $result = array_merge_recursive($this->array, $array);
1434
    } else {
1435 12
      $result = array_merge($this->array, $array);
1436
    }
1437
1438 16
    return static::create($result);
1439
  }
1440
1441
  /**
1442
   * Merge the the current array into the $array.
1443
   *
1444
   * - use key,value from the new $array, also if the index is in the current array
1445
   *
1446
   * @param array $array
1447
   * @param bool  $recursive
1448
   *
1449
   * @return Arrayy (Immutable)
1450
   */
1451 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...
1452
  {
1453 16
    if (true === $recursive) {
1454 4
      $result = array_replace_recursive($array, $this->array);
1455
    } else {
1456 12
      $result = array_replace($array, $this->array);
1457
    }
1458
1459 16
    return static::create($result);
1460
  }
1461
1462
  /**
1463
   * Merge the current array into the new $array.
1464
   *
1465
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1466
   * - create new indexes
1467
   *
1468
   * @param array $array
1469
   * @param bool  $recursive
1470
   *
1471
   * @return Arrayy (Immutable)
1472
   */
1473 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...
1474
  {
1475 16
    if (true === $recursive) {
1476 4
      $result = array_merge_recursive($array, $this->array);
1477
    } else {
1478 12
      $result = array_merge($array, $this->array);
1479
    }
1480
1481 16
    return static::create($result);
1482
  }
1483
1484
  /**
1485
   * Get the min value from an array.
1486
   *
1487
   * @return mixed
1488
   */
1489 10
  public function min()
1490
  {
1491 10
    if ($this->count() === 0) {
1492 1
      return false;
1493
    }
1494
1495 9
    return min($this->array);
1496
  }
1497
1498
  /**
1499
   * Pad array to the specified size with a given value.
1500
   *
1501
   * @param int   $size  Size of the result array
1502
   * @param mixed $value Empty value by default
1503
   *
1504
   * @return Arrayy (Immutable) Arrayy object padded to $size with $value
1505
   */
1506 4
  public function pad($size, $value)
1507
  {
1508 4
    $result = array_pad($this->array, $size, $value);
1509
1510 4
    return static::create($result);
1511
  }
1512
1513
  /**
1514
   * Pop a specified value off the end of the current array.
1515
   *
1516
   * @return mixed The popped element from the current array.
1517
   */
1518 16
  public function pop()
1519
  {
1520 16
    return array_pop($this->array);
1521
  }
1522
1523
  /**
1524
   * Prepend a value to the current array.
1525
   *
1526
   * @param mixed $value
1527
   *
1528
   * @return self (Mutable) Return this Arrayy object, with the prepended value.
1529
   */
1530 7
  public function prepend($value)
1531
  {
1532 7
    array_unshift($this->array, $value);
1533
1534 7
    return $this;
1535
  }
1536
1537
  /**
1538
   * Push one or more values onto the end of array at once.
1539
   *
1540
   * @return self (Mutable) Return this Arrayy object, with pushed elements to the end of array.
1541
   */
1542 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...
1543
  {
1544 4
    if (func_num_args()) {
1545 4
      $args = array_merge(array(&$this->array), func_get_args());
1546 4
      call_user_func_array('array_push', $args);
1547
    }
1548
1549 4
    return $this;
1550
  }
1551
1552
  /**
1553
   * Get a random value from the current array.
1554
   *
1555
   * @param null|int $number how many values you will take?
1556
   *
1557
   * @return self (Mutable)
1558
   */
1559 16
  public function randomMutable($number = null)
1560
  {
1561 16
    if ($this->count() === 0) {
1562
      return static::create();
1563
    }
1564
1565 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...
1566 6
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1567 6
      $this->array = $arrayRandValue;
1568
1569 6
      return $this;
1570
    }
1571
1572 11
    shuffle($this->array);
1573
1574 11
    return $this->firstsMutable($number);
1575
  }
1576
1577
  /**
1578
   * Get a random value from the current array.
1579
   *
1580
   * @param null|int $number how many values you will take?
1581
   *
1582
   * @return Arrayy (Immutable)
1583
   */
1584 17
  public function randomImmutable($number = null)
1585
  {
1586 17
    if ($this->count() === 0) {
1587
      return static::create();
1588
    }
1589
1590 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...
1591 14
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1592
1593 14
      return static::create($arrayRandValue);
1594
    }
1595
1596 5
    $arrayTmp = $this->array;
1597 5
    shuffle($arrayTmp);
1598
1599 5
    return self::create($arrayTmp)->firstsImmutable($number);
1600
  }
1601
1602
  /**
1603
   * Pick a random key/index from the keys of this array.
1604
   *
1605
   *
1606
   * @return mixed get a key/index or null if there wasn't a key/index
1607
   *
1608
   * @throws \RangeException If array is empty
1609
   */
1610 4
  public function randomKey()
1611
  {
1612 4
    $result = $this->randomKeys(1);
1613
1614 4
    if (!isset($result[0])) {
1615
      $result[0] = null;
1616
    }
1617
1618 4
    return $result[0];
1619
  }
1620
1621
  /**
1622
   * Pick a given number of random keys/indexes out of this array.
1623
   *
1624
   * @param int $number The number of keys/indexes (should be <= $this->count())
1625
   *
1626
   * @return Arrayy (Immutable)
1627
   *
1628
   * @throws \RangeException If array is empty
1629
   */
1630 14
  public function randomKeys($number)
1631
  {
1632 14
    $number = (int)$number;
1633 14
    $count = $this->count();
1634
1635 14
    if ($number === 0 || $number > $count) {
1636 3
      throw new \RangeException(
1637
          sprintf(
1638 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1639
              $number,
1640
              $count
1641
          )
1642
      );
1643
    }
1644
1645 11
    $result = (array)array_rand($this->array, $number);
1646
1647 11
    return static::create($result);
1648
  }
1649
1650
  /**
1651
   * Pick a random value from the values of this array.
1652
   *
1653
   * @return mixed get a random value or null if there wasn't a value
1654
   */
1655 4
  public function randomValue()
1656
  {
1657 4
    $result = $this->randomImmutable();
1658
1659 4
    if (!isset($result[0])) {
1660
      $result[0] = null;
1661
    }
1662
1663 4
    return $result[0];
1664
  }
1665
1666
  /**
1667
   * Pick a given number of random values out of this array.
1668
   *
1669
   * @param int $number
1670
   *
1671
   * @return self (Mutable)
1672
   */
1673 7
  public function randomValues($number)
1674
  {
1675 7
    $number = (int)$number;
1676
1677 7
    return $this->randomMutable($number);
1678
  }
1679
1680
  /**
1681
   * Get a random value from an array, with the ability to skew the results.
1682
   *
1683
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
1684
   *
1685
   * @param array    $array
1686
   * @param null|int $number how many values you will take?
1687
   *
1688
   * @return Arrayy (Immutable)
1689
   */
1690 9
  public function randomWeighted(array $array, $number = null)
1691
  {
1692 9
    $options = array();
1693 9
    foreach ($array as $option => $weight) {
1694 9
      if ($this->searchIndex($option) !== false) {
1695 9
        for ($i = 0; $i < $weight; ++$i) {
1696 1
          $options[] = $option;
1697
        }
1698
      }
1699
    }
1700
1701 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
1702
  }
1703
1704
  /**
1705
   * Reduce the current array via callable e.g. anonymous-function.
1706
   *
1707
   * @param mixed $callable
1708
   * @param array $init
1709
   *
1710
   * @return Arrayy (Immutable)
1711
   */
1712 3
  public function reduce($callable, array $init = array())
1713
  {
1714 3
    $result = array_reduce($this->array, $callable, $init);
1715
1716 3
    if ($result === null) {
1717
      $this->array = array();
1718
    } else {
1719 3
      $this->array = $result;
0 ignored issues
show
Documentation Bug introduced by
It seems like $result 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...
1720
    }
1721
1722 3
    return static::create((array)$this->array);
1723
  }
1724
1725
  /**
1726
   * Create a numerically re-indexed Arrayy object.
1727
   *
1728
   * @return self (Mutable) Return this Arrayy object, with re-indexed array-elements.
1729
   */
1730 9
  public function reindex()
1731
  {
1732 9
    $this->array = array_values($this->array);
1733
1734 9
    return $this;
1735
  }
1736
1737
  /**
1738
   * Return all items that fail the truth test.
1739
   *
1740
   * @param \Closure $closure
1741
   *
1742
   * @return Arrayy (Immutable)
1743
   */
1744 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...
1745
  {
1746 1
    $filtered = array();
1747
1748 1
    foreach ($this->array as $key => $value) {
1749 1
      if (!$closure($value, $key)) {
1750 1
        $filtered[$key] = $value;
1751
      }
1752
    }
1753
1754 1
    return static::create($filtered);
1755
  }
1756
1757
  /**
1758
   * Remove a value from the current array (optional using dot-notation).
1759
   *
1760
   * @param mixed $key
1761
   *
1762
   * @return Arrayy (Immutable)
1763
   */
1764 18
  public function remove($key)
1765
  {
1766
    // Recursive call
1767 18
    if (is_array($key)) {
1768
      foreach ($key as $k) {
1769
        $this->internalRemove($k);
1770
      }
1771
1772
      return static::create($this->array);
1773
    }
1774
1775 18
    $this->internalRemove($key);
1776
1777 18
    return static::create($this->array);
1778
  }
1779
1780
  /**
1781
   * Remove the first value from the current array.
1782
   *
1783
   * @return Arrayy (Immutable)
1784
   */
1785 7
  public function removeFirst()
1786
  {
1787 7
    array_shift($this->array);
1788
1789 7
    return static::create($this->array);
1790
  }
1791
1792
  /**
1793
   * Remove the last value from the current array.
1794
   *
1795
   * @return Arrayy (Immutable)
1796
   */
1797 7
  public function removeLast()
1798
  {
1799 7
    array_pop($this->array);
1800
1801 7
    return static::create($this->array);
1802
  }
1803
1804
  /**
1805
   * Removes a particular value from an array (numeric or associative).
1806
   *
1807
   * @param mixed $value
1808
   *
1809
   * @return Arrayy (Immutable)
1810
   */
1811 7
  public function removeValue($value)
1812
  {
1813 7
    $isNumericArray = true;
1814 7
    foreach ($this->array as $key => $item) {
1815 6
      if ($item === $value) {
1816 6
        if (!is_int($key)) {
1817
          $isNumericArray = false;
1818
        }
1819 6
        unset($this->array[$key]);
1820
      }
1821
    }
1822
1823 7
    if ($isNumericArray) {
1824 7
      $this->array = array_values($this->array);
1825
    }
1826
1827 7
    return static::create($this->array);
1828
  }
1829
1830
  /**
1831
   * Replace a key with a new key/value pair.
1832
   *
1833
   * @param $replace
1834
   * @param $key
1835
   * @param $value
1836
   *
1837
   * @return Arrayy (Immutable)
1838
   */
1839 2
  public function replace($replace, $key, $value)
1840
  {
1841 2
    $this->remove($replace);
1842
1843 2
    return $this->set($key, $value);
1844
  }
1845
1846
  /**
1847
   * Create an array using the current array as values and the other array as keys.
1848
   *
1849
   * @param array $keys Keys array
1850
   *
1851
   * @return Arrayy (Immutable) Arrayy object with keys from the other array.
1852
   */
1853 2
  public function replaceAllKeys(array $keys)
1854
  {
1855 2
    $result = array_combine($keys, $this->array);
1856
1857 2
    return static::create($result);
1858
  }
1859
1860
  /**
1861
   * Create an array using the current array as keys and the other array as values.
1862
   *
1863
   * @param array $array Values array
1864
   *
1865
   * @return Arrayy (Immutable) Arrayy object with values from the other array.
1866
   */
1867 2
  public function replaceAllValues(array $array)
1868
  {
1869 2
    $result = array_combine($this->array, $array);
1870
1871 2
    return static::create($result);
1872
  }
1873
1874
  /**
1875
   * Replace the keys in an array with another set.
1876
   *
1877
   * @param array $keys An array of keys matching the array's size
1878
   *
1879
   * @return Arrayy (Immutable)
1880
   */
1881 1
  public function replaceKeys(array $keys)
1882
  {
1883 1
    $values = array_values($this->array);
1884 1
    $result = array_combine($keys, $values);
1885
1886 1
    return static::create($result);
1887
  }
1888
1889
  /**
1890
   * Replace the first matched value in an array.
1891
   *
1892
   * @param mixed $search
1893
   * @param mixed $replacement
1894
   *
1895
   * @return Arrayy (Immutable)
1896
   */
1897 3
  public function replaceOneValue($search, $replacement = '')
1898
  {
1899 3
    $array = $this->array;
1900 3
    $key = array_search($search, $array, true);
1901
1902 3
    if ($key !== false) {
1903 3
      $array[$key] = $replacement;
1904
    }
1905
1906 3
    return static::create($array);
1907
  }
1908
1909
  /**
1910
   * Replace values in the current array.
1911
   *
1912
   * @param string $search      The string to replace.
1913
   * @param string $replacement What to replace it with.
1914
   *
1915
   * @return Arrayy (Immutable)
1916
   */
1917 1
  public function replaceValues($search, $replacement = '')
1918
  {
1919 1
    $array = $this->each(
1920
        function ($value) use ($search, $replacement) {
1921 1
          return UTF8::str_replace($search, $replacement, $value);
1922 1
        }
1923
    );
1924
1925 1
    return static::create($array);
0 ignored issues
show
Documentation introduced by
$array is of type object<Arrayy\Arrayy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1926
  }
1927
1928
  /**
1929
   * Get the last elements from index $from until the end of this array.
1930
   *
1931
   * @param int $from
1932
   *
1933
   * @return Arrayy (Immutable)
1934
   */
1935 16
  public function rest($from = 1)
1936
  {
1937 16
    $result = array_splice($this->array, $from);
1938
1939 16
    return static::create($result);
1940
  }
1941
1942
  /**
1943
   * Return the array in the reverse order.
1944
   *
1945
   * @return self (Mutable) Return this Arrayy object.
1946
   */
1947 7
  public function reverse()
1948
  {
1949 7
    $this->array = array_reverse($this->array);
1950
1951 7
    return $this;
1952
  }
1953
1954
  /**
1955
   * Search for the first index of the current array via $value.
1956
   *
1957
   * @param mixed $value
1958
   *
1959
   * @return mixed
1960
   */
1961 20
  public function searchIndex($value)
1962
  {
1963 20
    return array_search($value, $this->array, true);
1964
  }
1965
1966
  /**
1967
   * Search for the value of the current array via $index.
1968
   *
1969
   * @param mixed $index
1970
   *
1971
   * @return Arrayy (Immutable) will return a empty Arrayy if the value wasn't found
1972
   */
1973 7
  public function searchValue($index)
1974
  {
1975
    // init
1976 7
    $return = array();
1977
1978 7
    if (null !== $index) {
1979 7
      $keyExists = isset($this->array[$index]);
1980
1981 7
      if ($keyExists !== false) {
1982 5
        $return = array($this->array[$index]);
1983
      }
1984
    }
1985
1986 7
    return static::create($return);
1987
  }
1988
1989
  /**
1990
   * Set a value for the current array (optional using dot-notation).
1991
   *
1992
   * @param string $key   The key to set
1993
   * @param mixed  $value Its value
1994
   *
1995
   * @return Arrayy (Immutable)
1996
   */
1997 17
  public function set($key, $value)
1998
  {
1999 17
    $this->internalSet($key, $value);
2000
2001 17
    return static::create($this->array);
2002
  }
2003
2004
  /**
2005
   * Get a value from a array and set it if it was not.
2006
   *
2007
   * WARNING: this method only set the value, if the $key is not already set
2008
   *
2009
   * @param string $key      The key
2010
   * @param mixed  $fallback The default value to set if it isn't
2011
   *
2012
   * @return mixed (Mutable)
2013
   */
2014 10
  public function setAndGet($key, $fallback = null)
2015
  {
2016
    // If the key doesn't exist, set it
2017 10
    if (!$this->has($key)) {
2018 5
      $this->array = $this->set($key, $fallback)->getArray();
2019
    }
2020
2021 10
    return $this->get($key);
2022
  }
2023
2024
  /**
2025
   * Shifts a specified value off the beginning of array.
2026
   *
2027
   * @return mixed A shifted element from the current array.
2028
   */
2029 4
  public function shift()
2030
  {
2031 4
    return array_shift($this->array);
2032
  }
2033
2034
  /**
2035
   * Shuffle the current array.
2036
   *
2037
   * @return Arrayy (Immutable)
2038
   */
2039 1
  public function shuffle()
2040
  {
2041 1
    $array = $this->array;
2042
2043 1
    shuffle($array);
2044
2045 1
    return static::create($array);
2046
  }
2047
2048
  /**
2049
   * Get the size of an array.
2050
   *
2051
   * @return int
2052
   */
2053 109
  public function size()
2054
  {
2055 109
    return count($this->array);
2056
  }
2057
2058
  /**
2059
   * Extract a slice of the array.
2060
   *
2061
   * @param int      $offset       Slice begin index
2062
   * @param int|null $length       Length of the slice
2063
   * @param bool     $preserveKeys Whether array keys are preserved or no
2064
   *
2065
   * @return static A slice of the original array with length $length
2066
   */
2067 4
  public function slice($offset, $length = null, $preserveKeys = false)
2068
  {
2069 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
2070
2071 4
    return static::create($result);
2072
  }
2073
2074
  /**
2075
   * Sort the current array and optional you can keep the keys.
2076
   *
2077
   * @param integer $direction use SORT_ASC or SORT_DESC
2078
   * @param integer $strategy
2079
   * @param bool       $keepKeys
2080
   *
2081
   * @return self (Mutable) Return this Arrayy object.
2082
   */
2083 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2084
  {
2085 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2086
2087 19
    return $this;
2088
  }
2089
2090
  /**
2091
   * Sort the current array by key.
2092
   *
2093
   * @link http://php.net/manual/en/function.ksort.php
2094
   * @link http://php.net/manual/en/function.krsort.php
2095
   *
2096
   * @param int|string $direction use SORT_ASC or SORT_DESC
2097
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2098
   *
2099
   * @return self (Mutable) Return this Arrayy object.
2100
   */
2101 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2102
  {
2103 18
    $this->sorterKeys($this->array, $direction, $strategy);
2104
2105 18
    return $this;
2106
  }
2107
2108
  /**
2109
   * Sort the current array by value.
2110
   *
2111
   * @param int $direction use SORT_ASC or SORT_DESC
2112
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2113
   *
2114
   * @return Arrayy (Immutable)
2115
   */
2116 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2117
  {
2118 1
    return $this->sort($direction, $strategy, true);
2119
  }
2120
2121
  /**
2122
   * Sort the current array by value.
2123
   *
2124
   * @param int $direction use SORT_ASC or SORT_DESC
2125
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2126
   *
2127
   * @return Arrayy (Immutable)
2128
   */
2129 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2130
  {
2131 1
    return $this->sort($direction, $strategy, false);
2132
  }
2133
2134
  /**
2135
   * Sort a array by value, by a closure or by a property.
2136
   *
2137
   * - If the sorter is null, the array is sorted naturally.
2138
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2139
   *
2140
   * @param null       $sorter
2141
   * @param string|int $direction
2142
   * @param int        $strategy
2143
   *
2144
   * @return Arrayy (Immutable)
2145
   */
2146 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2147
  {
2148 1
    $array = (array)$this->array;
2149 1
    $direction = $this->getDirection($direction);
2150
2151
    // Transform all values into their results.
2152 1
    if ($sorter) {
2153 1
      $arrayy = new self($array);
2154
2155 1
      $that = $this;
2156 1
      $results = $arrayy->each(
2157
          function ($value) use ($sorter, $that) {
2158 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2159 1
          }
2160
      );
2161
2162 1
      $results = $results->getArray();
2163
    } else {
2164 1
      $results = $array;
2165
    }
2166
2167
    // Sort by the results and replace by original values
2168 1
    array_multisort($results, $direction, $strategy, $array);
2169
2170 1
    return static::create($array);
2171
  }
2172
2173
  /**
2174
   * sorting keys
2175
   *
2176
   * @param array $elements
2177
   * @param int   $direction
2178
   * @param int   $strategy
2179
   */
2180 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2181
  {
2182 18
    $direction = $this->getDirection($direction);
2183
2184
    switch ($direction) {
2185 18
      case 'desc':
2186 18
      case SORT_DESC:
2187 6
        krsort($elements, $strategy);
2188 6
        break;
2189 13
      case 'asc':
2190 13
      case SORT_ASC:
2191
      default:
2192 13
        ksort($elements, $strategy);
2193
    }
2194 18
  }
2195
2196
  /**
2197
   * @param array      &$elements
2198
   * @param int|string $direction
2199
   * @param int        $strategy
2200
   * @param bool       $keepKeys
2201
   */
2202 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2203
  {
2204 19
    $direction = $this->getDirection($direction);
2205
2206 19
    if (!$strategy) {
2207 19
      $strategy = SORT_REGULAR;
2208
    }
2209
2210
    switch ($direction) {
2211 19
      case 'desc':
2212 19
      case SORT_DESC:
2213 9
        if ($keepKeys) {
2214 5
          arsort($elements, $strategy);
2215
        } else {
2216 4
          rsort($elements, $strategy);
2217
        }
2218 9
        break;
2219 10
      case 'asc':
2220 10
      case SORT_ASC:
2221
      default:
2222 10
        if ($keepKeys) {
2223 4
          asort($elements, $strategy);
2224
        } else {
2225 6
          sort($elements, $strategy);
2226
        }
2227
    }
2228 19
  }
2229
2230
  /**
2231
   * Split an array in the given amount of pieces.
2232
   *
2233
   * @param int  $numberOfPieces
2234
   * @param bool $keepKeys
2235
   *
2236
   * @return Arrayy (Immutable)
2237
   */
2238 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2239
  {
2240 1
    if (count($this->array) === 0) {
2241 1
      $result = array();
2242
    } else {
2243 1
      $numberOfPieces = (int)$numberOfPieces;
2244 1
      $splitSize = ceil(count($this->array) / $numberOfPieces);
2245 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
2246
    }
2247
2248 1
    return static::create($result);
2249
  }
2250
2251
  /**
2252
   * alias: for "Arrayy->getArray()"
2253
   */
2254 153
  public function toArray()
2255
  {
2256 153
    return $this->getArray();
2257
  }
2258
2259
  /**
2260
   * Convert the current array to JSON.
2261
   *
2262
   * @param null $options e.g. JSON_PRETTY_PRINT
2263
   *
2264
   * @return string
2265
   */
2266 5
  public function toJson($options = null)
2267
  {
2268 5
    return UTF8::json_encode($this->array, $options);
2269
  }
2270
2271
  /**
2272
   * Implodes array to a string with specified separator.
2273
   *
2274
   * @param string $separator The element's separator
2275
   *
2276
   * @return string The string representation of array, separated by ","
2277
   */
2278 15
  public function toString($separator = ',')
2279
  {
2280 15
    return $this->implode($separator);
2281
  }
2282
2283
  /**
2284
   * Return a duplicate free copy of the current array.
2285
   *
2286
   * @return Arrayy (Mutable)
2287
   */
2288 7
  public function unique()
2289
  {
2290 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...
2291 7
        $this->array,
2292 7
        function ($resultArray, $value) {
2293 6
          if (in_array($value, $resultArray, true) === false) {
2294 6
            $resultArray[] = $value;
2295
          }
2296
2297 6
          return $resultArray;
2298 7
        },
2299 7
        array()
2300
    );
2301
2302 7
    return $this;
2303
  }
2304
2305
  /**
2306
   * Prepends one or more values to the beginning of array at once.
2307
   *
2308
   * @return self (Mutable) Return this Arrayy object, with prepended elements to the beginning of array.
2309
   */
2310 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...
2311
  {
2312 4
    if (func_num_args()) {
2313 4
      $args = array_merge(array(&$this->array), func_get_args());
2314 4
      call_user_func_array('array_unshift', $args);
2315
    }
2316
2317 4
    return $this;
2318
  }
2319
2320
  /**
2321
   * Get all values from a array.
2322
   *
2323
   * @return Arrayy (Immutable)
2324
   */
2325 1
  public function values()
2326
  {
2327 1
    $array = array_values((array)$this->array);
2328
2329 1
    return static::create($array);
2330
  }
2331
2332
  /**
2333
   * Apply the given function to every element in the array, discarding the results.
2334
   *
2335
   * @param callable $callable
2336
   * @param bool     $recursive Whether array will be walked recursively or no
2337
   *
2338
   * @return self (Mutable) Return this Arrayy object, with modified elements
2339
   */
2340 9
  public function walk($callable, $recursive = false)
2341
  {
2342 9
    if (true === $recursive) {
2343 4
      array_walk_recursive($this->array, $callable);
2344
    } else {
2345 5
      array_walk($this->array, $callable);
2346
    }
2347
2348 9
    return $this;
2349
  }
2350
2351
2352
}
2353