Completed
Push — master ( 213fa3...a80ca9 )
by Lars
03:25
created

Arrayy::filter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Arrayy;
4
5
use ArrayAccess;
6
use Closure;
7
use voku\helper\UTF8;
8
9
/**
10
 * Methods to manage arrays.
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
class Arrayy extends \ArrayObject 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 684
  public function __construct($array = array())
28
  {
29 684
    $array = $this->fallbackForArray($array);
30
31 682
    $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 682
  }
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.
115
   */
116 1
  public function add($value)
117
  {
118 1
    $this->array[] = $value;
119
120 1
    return $this;
121
  }
122
123
  /**
124
   * Append a value to the current array.
125
   *
126
   * @param mixed $value
127
   *
128
   * @return self (Mutable) Return this Arrayy object, with the appended values.
129
   */
130 8
  public function append($value)
131
  {
132 8
    $this->array[] = $value;
133
134 8
    return $this;
135
  }
136
137
  /**
138
   * Count the values from the current array.
139
   *
140
   * INFO: only a alias for "$arrayy->size()"
141
   *
142
   * @return int
143
   */
144 105
  public function count()
145
  {
146 105
    return $this->size();
147
  }
148
149
  /**
150
   * Returns a new ArrayIterator, thus implementing the IteratorAggregate interface.
151
   *
152
   * @return \ArrayIterator An iterator for the values in the array.
153
   */
154 16
  public function getIterator()
155
  {
156 16
    return new \ArrayIterator($this->array);
157
  }
158
159
  /**
160
   * Whether or not an offset exists.
161
   *
162
   * @param mixed $offset
163
   *
164
   * @return bool
165
   */
166 27
  public function offsetExists($offset)
167
  {
168 27
    return isset($this->array[$offset]);
169
  }
170
171
  /**
172
   * Returns the value at specified offset.
173
   *
174
   * @param mixed $offset
175
   *
176
   * @return mixed return null if the offset did not exists
177
   */
178 18
  public function offsetGet($offset)
179
  {
180 18
    return $this->offsetExists($offset) ? $this->array[$offset] : null;
181
  }
182
183
  /**
184
   * Assigns a value to the specified offset.
185
   *
186
   * @param mixed $offset
187
   * @param mixed $value
188
   */
189 13
  public function offsetSet($offset, $value)
190
  {
191 13
    if (null === $offset) {
192 4
      $this->array[] = $value;
193 4
    } else {
194 9
      $this->array[$offset] = $value;
195
    }
196 13
  }
197
198
  /**
199
   * Unset an offset.
200
   *
201
   * @param mixed $offset
202
   */
203 5
  public function offsetUnset($offset)
204
  {
205 5
    if ($this->offsetExists($offset)) {
206 3
      unset($this->array[$offset]);
207 3
    }
208 5
  }
209
210
  /**
211
   * Serialize the current array.
212
   *
213
   * @return string
214
   */
215
  public function serialize()
216
  {
217
    return serialize($this->array);
218
  }
219
220
  /**
221
   * Unserialize an string and return this object.
222
   *
223
   * @param string $string
224
   *
225
   * @return self (Mutable)
226
   */
227
  public function unserialize($string)
228
  {
229
    $this->array = unserialize($string);
230
231
    return $this;
232
  }
233
234
  /**
235
   * Iterate over an array and execute a callback for each loop.
236
   *
237
   * @param \Closure $closure
238
   *
239
   * @return Arrayy (Immutable)
240
   */
241 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...
242
  {
243 2
    $array = $this->array;
244
245 2
    foreach ($array as $key => $value) {
246 2
      $closure($value, $key);
247 2
    }
248
249 2
    return static::create($array);
250
  }
251
252
  /**
253
   * Returns the average value of the current array.
254
   *
255
   * @param int $decimals The number of decimals to return
256
   *
257
   * @return int|double The average value
258
   */
259 10
  public function average($decimals = null)
260
  {
261 10
    $count = $this->count();
262
263 10
    if (!$count) {
264 2
      return 0;
265
    }
266
267 8
    if (!is_int($decimals)) {
268 3
      $decimals = null;
269 3
    }
270
271 8
    return round(array_sum($this->array) / $count, $decimals);
272
  }
273
274
  /**
275
   * Create a chunked version of this array.
276
   *
277
   * @param int  $size         Size of each chunk
278
   * @param bool $preserveKeys Whether array keys are preserved or no
279
   *
280
   * @return Arrayy (Immutable) A new array of chunks from the original array.
281
   */
282 4
  public function chunk($size, $preserveKeys = false)
283
  {
284 4
    $result = array_chunk($this->array, $size, $preserveKeys);
285
286 4
    return static::create($result);
287
  }
288
289
  /**
290
   * Clean all falsy values from an array.
291
   *
292
   * @return Arrayy (Immutable)
293
   */
294 8
  public function clean()
295
  {
296 8
    return $this->filter(
297
        function ($value) {
298 7
          return (bool)$value;
299
        }
300 8
    );
301
  }
302
303
  /**
304
   * WARNING!!! -> Clear the current array.
305
   *
306
   * @return self (Mutable) Return this Arrayy object, with an empty array.
307
   */
308 4
  public function clear()
309
  {
310 4
    $this->array = array();
311
312 4
    return $this;
313
  }
314
315
  /**
316
   * Check if an item is in the current array.
317
   *
318
   * @param mixed $value
319
   *
320
   * @return bool
321
   */
322 13
  public function contains($value)
323
  {
324 13
    return in_array($value, $this->array, true);
325
  }
326
327
  /**
328
   * Check if the given key/index exists in the array.
329
   *
330
   * @param mixed $key Key/index to search for
331
   *
332
   * @return bool Returns true if the given key/index exists in the array, false otherwise
333
   */
334 4
  public function containsKey($key)
335
  {
336 4
    return array_key_exists($key, $this->array);
337
  }
338
339
  /**
340
   * Creates a Arrayy object.
341
   *
342
   * @param array $array
343
   *
344
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
345
   */
346 427
  public static function create($array = array())
347
  {
348 427
    return new static($array);
349
  }
350
351
  /**
352
   * WARNING: Creates a Arrayy object by reference.
353
   *
354
   * @param array $array
355
   *
356
   * @return self (Mutable) Return this Arrayy object.
357
   */
358
  public function createByReference(&$array = array())
359
  {
360
    $array = $this->fallbackForArray($array);
361
362
    $this->array = &$array;
363
364
    return $this;
365
  }
366
367
  /**
368
   * Create a new Arrayy object via JSON.
369
   *
370
   * @param string $json
371
   *
372
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
373
   */
374 5
  public static function createFromJson($json)
375
  {
376 5
    $array = UTF8::json_decode($json, true);
377
378 5
    return static::create($array);
379
  }
380
381
  /**
382
   * Create a new instance filled with values from an object that have implemented ArrayAccess.
383
   *
384
   * @param ArrayAccess $elements Object that implements ArrayAccess
385
   *
386
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
387
   */
388 4
  public static function createFromObject(ArrayAccess $elements)
389
  {
390 4
    $array = new static();
391 4
    foreach ($elements as $key => $value) {
392
      /** @noinspection OffsetOperationsInspection */
393 3
      $array[$key] = $value;
394 4
    }
395
396 4
    return $array;
397
  }
398
399
  /**
400
   * Create a new Arrayy object via string.
401
   *
402
   * @param string      $str       The input string.
403
   * @param string|null $delimiter The boundary string.
404
   * @param string|null $regEx     Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be used.
405
   *
406
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
407
   */
408 8
  public static function createFromString($str, $delimiter, $regEx = null)
409
  {
410 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...
411 1
      preg_match_all($regEx, $str, $array);
412
413 1
      if (count($array) > 0) {
414 1
        $array = $array[0];
415 1
      }
416
417 1
    } else {
418 7
      $array = explode($delimiter, $str);
419
    }
420
421
    // trim all string in the array
422 8
    array_walk(
423 8
        $array,
424
        function (&$val) {
425 8
          if (is_string($val)) {
426 8
            $val = trim($val);
427 8
          }
428 8
        }
429 8
    );
430
431 8
    return static::create($array);
432
  }
433
434
  /**
435
   * Create a new instance containing a range of elements.
436
   *
437
   * @param mixed $low  First value of the sequence
438
   * @param mixed $high The sequence is ended upon reaching the end value
439
   * @param int   $step Used as the increment between elements in the sequence
440
   *
441
   * @return Arrayy (Immutable) Returns an new instance of the Arrayy object.
442
   */
443 1
  public static function createWithRange($low, $high, $step = 1)
444
  {
445 1
    return static::create(range($low, $high, $step));
446
  }
447
448
  /**
449
   * Custom sort by index via "uksort"
450
   *
451
   * @link http://php.net/manual/en/function.uksort.php
452
   *
453
   * @param callable $func
454
   *
455
   * @return self (Mutable) Return this Arrayy object.
456
   */
457 4
  public function customSortKeys($func)
458
  {
459 4
    uksort($this->array, $func);
460
461 4
    return $this;
462
  }
463
464
  /**
465
   * Custom sort by value via "usort"
466
   *
467
   * @link http://php.net/manual/en/function.usort.php
468
   *
469
   * @param callable $func
470
   *
471
   * @return self (Mutable) Return this Arrayy object.
472
   */
473 4
  public function customSortValues($func)
474
  {
475 4
    usort($this->array, $func);
476
477 4
    return $this;
478
  }
479
480
  /**
481
   * Return values that are only in the current array.
482
   *
483
   * @param array $array
484
   *
485
   * @return Arrayy (Immutable)
486
   */
487 12
  public function diff(array $array = array())
488
  {
489 12
    $result = array_diff($this->array, $array);
490
491 12
    return static::create($result);
492
  }
493
494
  /**
495
   * Return values that are only in the new $array.
496
   *
497
   * @param array $array
498
   *
499
   * @return Arrayy (Immutable)
500
   */
501 8
  public function diffReverse(array $array = array())
502
  {
503 8
    $result = array_diff($array, $this->array);
504
505 8
    return static::create($result);
506
  }
507
508
  /**
509
   * Iterate over the current array and modify the array's value.
510
   *
511
   * @param \Closure $closure
512
   *
513
   * @return Arrayy (Immutable)
514
   */
515 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...
516
  {
517 22
    $array = $this->array;
518
519 22
    foreach ($array as $key => &$value) {
520 18
      $value = $closure($value, $key);
521 22
    }
522
523 22
    return static::create($array);
524
  }
525
526
  /**
527
   * Check if a value is in the current array using a closure.
528
   *
529
   * @param \Closure $closure
530
   *
531
   * @return bool Returns true if the given value is found, false otherwise
532
   */
533 4
  public function exists(\Closure $closure)
534
  {
535 4
    $isExists = false;
536 4
    foreach ($this->array as $key => $value) {
537 3
      if ($closure($value, $key)) {
538 1
        $isExists = true;
539 1
        break;
540
      }
541 4
    }
542
543 4
    return $isExists;
544
  }
545
546
  /**
547
   * create a fallback for array
548
   *
549
   * 1. fallback to empty array, if there is nothing
550
   * 2. cast a String or Object with "__toString" into an array
551
   * 3. call "__toArray" on Object, if the method exists
552
   * 4. throw a "InvalidArgumentException"-Exception
553
   *
554
   * @param $array
555
   *
556
   * @return array
557
   */
558 684
  protected function fallbackForArray(&$array)
559
  {
560 684
    if (is_array($array)) {
561 681
      return $array;
562
    }
563
564 5
    if ($array instanceof self) {
565 1
      return $array->getArray();
566
    }
567
568 4
    if (!$array) {
569 1
      return array();
570
    }
571
572
    if (
573 3
        is_string($array)
574
        ||
575 2
        (is_object($array) && method_exists($array, '__toString'))
576 3
    ) {
577 1
      return (array)$array;
578
    }
579
580 2
    if ($array instanceof ArrayAccess) {
581
      return self::createFromObject($array);
582
    }
583
584 2
    if (is_object($array) && method_exists($array, '__toArray')) {
585
      return (array)$array->__toArray();
586
    }
587
588 2
    throw new \InvalidArgumentException(
589
        'Passed value should be a array'
590 2
    );
591
  }
592
593
  /**
594
   * Find all items in an array that pass the truth test.
595
   *
596
   * @param \Closure|null $closure
597
   *
598
   * @return Arrayy (Immutable)
599
   */
600 8
  public function filter($closure = null)
601
  {
602 8
    if (!$closure) {
603 1
      return $this->clean();
604
    }
605
606 8
    $array = array_filter($this->array, $closure);
607
608 8
    return static::create($array);
609
  }
610
611
  /**
612
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
613
   * within that.
614
   *
615
   * @param        $property
616
   * @param        $value
617
   * @param string $comparisonOp
618
   *
619
   * @return Arrayy (Immutable)
620
   */
621 1
  public function filterBy($property, $value, $comparisonOp = null)
622
  {
623 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...
624 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
625 1
    }
626
627
    $ops = array(
628
        'eq'          => function ($item, $prop, $value) {
629 1
          return $item[$prop] === $value;
630 1
        },
631
        'gt'          => function ($item, $prop, $value) {
632
          return $item[$prop] > $value;
633 1
        },
634
        'gte'         => function ($item, $prop, $value) {
635
          return $item[$prop] >= $value;
636 1
        },
637
        'lt'          => function ($item, $prop, $value) {
638 1
          return $item[$prop] < $value;
639 1
        },
640
        'lte'         => function ($item, $prop, $value) {
641
          return $item[$prop] <= $value;
642 1
        },
643
        'ne'          => function ($item, $prop, $value) {
644
          return $item[$prop] !== $value;
645 1
        },
646
        'contains'    => function ($item, $prop, $value) {
647 1
          return in_array($item[$prop], (array)$value, true);
648 1
        },
649
        'notContains' => function ($item, $prop, $value) {
650
          return !in_array($item[$prop], (array)$value, true);
651 1
        },
652
        'newer'       => function ($item, $prop, $value) {
653
          return strtotime($item[$prop]) > strtotime($value);
654 1
        },
655
        'older'       => function ($item, $prop, $value) {
656
          return strtotime($item[$prop]) < strtotime($value);
657 1
        },
658 1
    );
659
660 1
    $result = array_values(
661 1
        array_filter(
662 1
            (array)$this->array,
663
            function ($item) use (
664 1
                $property,
665 1
                $value,
666 1
                $ops,
667 1
                $comparisonOp
668
            ) {
669 1
              $item = (array)$item;
670 1
              $itemArrayy = new Arrayy($item);
671 1
              $item[$property] = $itemArrayy->get($property, array());
672
673 1
              return $ops[$comparisonOp]($item, $property, $value);
674
            }
675 1
        )
676 1
    );
677
678 1
    return static::create($result);
679
  }
680
681
  /**
682
   * Find the first item in an array that passes the truth test,
683
   *  otherwise return false
684
   *
685
   * @param \Closure $closure
686
   *
687
   * @return mixed|false false if we did not find the value
688
   */
689 8
  public function find(\Closure $closure)
690
  {
691 8
    foreach ($this->array as $key => $value) {
692 6
      if ($closure($value, $key)) {
693 5
        return $value;
694
      }
695 5
    }
696
697 3
    return false;
698
  }
699
700
  /**
701
   * find by ...
702
   *
703
   * @param        $property
704
   * @param        $value
705
   * @param string $comparisonOp
706
   *
707
   * @return Arrayy (Immutable)
708
   */
709
  public function findBy($property, $value, $comparisonOp = 'eq')
710
  {
711
    $array = $this->filterBy($property, $value, $comparisonOp);
712
713
    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...
714
  }
715
716
  /**
717
   * Get the first value from the current array.
718
   *
719
   * @return mixed Return null if there wasn't a element.
720
   */
721 13
  public function first()
722
  {
723 13
    $result = array_shift($this->array);
724
725 13
    if (null === $result) {
726 3
      return null;
727
    } else {
728 10
      return $result;
729
    }
730
  }
731
732
  /**
733
   * Get the first value(s) from the current array.
734
   *
735
   * @param int|null $number how many values you will take?
736
   *
737
   * @return self (Mutable)
738
   */
739 25
  public function firstsMutable($number = null)
740
  {
741 25
    if ($number === null) {
742 11
      $this->array = (array)array_shift($this->array);
743 11
    } else {
744 14
      $number = (int)$number;
745 14
      $this->array = array_splice($this->array, 0, $number, true);
746
    }
747
748 25
    return $this;
749
  }
750
751
  /**
752
   * Get the first value(s) from the current array.
753
   *
754
   * @param int|null $number how many values you will take?
755
   *
756
   * @return Arrayy (Immutable)
757
   */
758 28
  public function firstsImmutable($number = null)
759
  {
760 28
    if ($number === null) {
761 7
      $array = (array)array_shift($this->array);
762 7
    } else {
763 21
      $number = (int)$number;
764 21
      $array = array_splice($this->array, 0, $number, true);
765
    }
766
767 28
    return static::create($array);
768
  }
769
770
  /**
771
   * Exchanges all keys with their associated values in an array.
772
   *
773
   * @return Arrayy (Immutable)
774
   */
775 1
  public function flip()
776
  {
777 1
    $result = array_flip($this->array);
778
779 1
    return static::create($result);
780
  }
781
782
  /**
783
   * Get a value from an array (optional using dot-notation).
784
   *
785
   * @param string $key     The key to look for
786
   * @param mixed  $default Default value to fallback to
787
   * @param array  $array   The array to get from,
788
   *                        if it's set to "null" we use the current array from the class
789
   *
790
   * @return mixed
791
   */
792 31
  public function get($key, $default = null, $array = null)
793
  {
794 31
    if (is_array($array) === true) {
795 3
      $usedArray = $array;
796 3
    } else {
797 29
      $usedArray = $this->array;
798
    }
799
800 31
    if (null === $key) {
801 1
      return $usedArray;
802
    }
803
804 31
    if (isset($usedArray[$key])) {
805 22
      return $usedArray[$key];
806
    }
807
808
    // Crawl through array, get key according to object or not
809 16
    foreach (explode('.', $key) as $segment) {
810 16
      if (!isset($usedArray[$segment])) {
811 16
        return $default instanceof Closure ? $default() : $default;
812
      }
813
814
      $usedArray = $usedArray[$segment];
815
    }
816
817
    return $usedArray;
818
  }
819
820
  /**
821
   * Get the current array from the "Arrayy"-object
822
   *
823
   * @return array
824
   */
825 469
  public function getArray()
826
  {
827 469
    return $this->array;
828
  }
829
830
  /**
831
   * Returns the values from a single column of the input array, identified by
832
   * the $columnKey, can be used to extract data-columns from multi-arrays.
833
   *
834
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
835
   * array by the values from the $indexKey column in the input array.
836
   *
837
   * @param mixed $columnKey
838
   * @param mixed $indexKey
839
   *
840
   * @return Arrayy (Immutable)
841
   */
842 1
  public function getColumn($columnKey = null, $indexKey = null)
843
  {
844 1
    $result = array_column($this->array, $columnKey, $indexKey);
845
846 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 844 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...
847
  }
848
849
  /**
850
   * Get correct PHP constant for direction.
851
   *
852
   * @param int|string $direction
853
   *
854
   * @return int
855
   */
856 38
  protected function getDirection($direction)
857
  {
858 38
    if (is_string($direction)) {
859 10
      $direction = strtolower($direction);
860
861 10
      if ($direction === 'desc') {
862 2
        $direction = SORT_DESC;
863 2
      } else {
864 8
        $direction = SORT_ASC;
865
      }
866 10
    }
867
868
    if (
869
        $direction !== SORT_DESC
870 38
        &&
871
        $direction !== SORT_ASC
872 38
    ) {
873
      $direction = SORT_ASC;
874
    }
875
876 38
    return $direction;
877
  }
878
879
  /**
880
   * alias: for "Arrayy->keys()"
881
   *
882
   * @return Arrayy (Immutable)
883
   */
884 15
  public function getKeys()
885
  {
886 15
    return $this->keys();
887
  }
888
889
  /**
890
   * alias: for "Arrayy->random()"
891
   *
892
   * @return Arrayy (Immutable)
893
   */
894 3
  public function getRandom()
895
  {
896 3
    return $this->randomImmutable();
897
  }
898
899
  /**
900
   * alias: for "Arrayy->randomKey()"
901
   *
902
   * @return mixed get a key/index or null if there wasn't a key/index
903
   */
904 3
  public function getRandomKey()
905
  {
906 3
    return $this->randomKey();
907
  }
908
909
  /**
910
   * alias: for "Arrayy->randomKeys()"
911
   *
912
   * @param int $number
913
   *
914
   * @return Arrayy (Immutable)
915
   */
916 9
  public function getRandomKeys($number)
917
  {
918 9
    return $this->randomKeys($number);
919
  }
920
921
  /**
922
   * alias: for "Arrayy->randomValue()"
923
   *
924
   * @return mixed get a random value or null if there wasn't a value
925
   */
926 3
  public function getRandomValue()
927
  {
928 3
    return $this->randomValue();
929
  }
930
931
  /**
932
   * alias: for "Arrayy->randomValues()"
933
   *
934
   * @param int $number
935
   *
936
   * @return Arrayy (Immutable)
937
   */
938 6
  public function getRandomValues($number)
939
  {
940 6
    return $this->randomValues($number);
941
  }
942
943
  /**
944
   * Group values from a array according to the results of a closure.
945
   *
946
   * @param string $grouper a callable function name
947
   * @param bool   $saveKeys
948
   *
949
   * @return Arrayy (Immutable)
950
   */
951 3
  public function group($grouper, $saveKeys = false)
952
  {
953 3
    $array = (array)$this->array;
954 3
    $result = array();
955
956
    // Iterate over values, group by property/results from closure
957 3
    foreach ($array as $key => $value) {
958 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
959 3
      $newValue = $this->get($groupKey, null, $result);
960
961
      // Add to results
962 3
      if ($groupKey !== null) {
963 2
        if ($saveKeys) {
964 1
          $result[$groupKey] = $newValue;
965 1
          $result[$groupKey][$key] = $value;
966 1
        } else {
967 1
          $result[$groupKey] = $newValue;
968 1
          $result[$groupKey][] = $value;
969
        }
970 2
      }
971
972 3
    }
973
974 3
    return static::create($result);
975
  }
976
977
  /**
978
   * Check if an array has a given key.
979
   *
980
   * @param mixed $key
981
   *
982
   * @return bool
983
   */
984 18
  public function has($key)
985
  {
986
    // Generate unique string to use as marker.
987 18
    $unFound = (string)uniqid('arrayy', true);
988
989 18
    return $this->get($key, $unFound) !== $unFound;
990
  }
991
992
  /**
993
   * Implodes an array.
994
   *
995
   * @param string $with What to implode it with
996
   *
997
   * @return string
998
   */
999 23
  public function implode($with = '')
1000
  {
1001 23
    return implode($with, $this->array);
1002
  }
1003
1004
  /**
1005
   * Given a list and an iterate-function that returns
1006
   * a key for each element in the list (or a property name),
1007
   * returns an object with an index of each item.
1008
   *
1009
   * Just like groupBy, but for when you know your keys are unique.
1010
   *
1011
   * @param mixed $key
1012
   *
1013
   * @return Arrayy (Immutable)
1014
   */
1015 3
  public function indexBy($key)
1016
  {
1017 3
    $results = array();
1018
1019 3
    foreach ($this->array as $a) {
1020 3
      if (isset($a[$key])) {
1021 2
        $results[$a[$key]] = $a;
1022 2
      }
1023 3
    }
1024
1025 3
    return static::create($results);
1026
  }
1027
1028
  /**
1029
   * alias: for "Arrayy->searchIndex()"
1030
   *
1031
   * @param mixed $value Value to search for
1032
   *
1033
   * @return mixed
1034
   */
1035 4
  public function indexOf($value)
1036
  {
1037 4
    return $this->searchIndex($value);
1038
  }
1039
1040
  /**
1041
   * Get everything but the last..$to items.
1042
   *
1043
   * @param int $to
1044
   *
1045
   * @return Arrayy (Immutable)
1046
   */
1047 12
  public function initial($to = 1)
1048
  {
1049 12
    $slice = count($this->array) - $to;
1050
1051 12
    return $this->firstsImmutable($slice);
1052
  }
1053
1054
  /**
1055
   * Internal mechanics of remove method.
1056
   *
1057
   * @param $key
1058
   *
1059
   * @return boolean
1060
   */
1061 17
  protected function internalRemove($key)
1062
  {
1063
    // Explode keys
1064 17
    $keys = explode('.', $key);
1065
1066
    // Crawl though the keys
1067 17 View Code Duplication
    while (count($keys) > 1) {
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...
1068
      $key = array_shift($keys);
1069
1070
      if (!$this->has($key)) {
1071
        return false;
1072
      }
1073
1074
      $this->array = &$this->array[$key];
1075
    }
1076
1077 17
    $key = array_shift($keys);
1078
1079 17
    unset($this->array[$key]);
1080
1081 17
    return true;
1082
  }
1083
1084
  /**
1085
   * Internal mechanic of set method.
1086
   *
1087
   * @param mixed $key
1088
   * @param mixed $value
1089
   *
1090
   * @return bool
1091
   */
1092 14
  protected function internalSet($key, $value)
1093
  {
1094 14
    if (null === $key) {
1095
      return false;
1096
    }
1097
1098
    // Explode the keys
1099 14
    $keys = explode('.', $key);
1100
1101
    // Crawl through the keys
1102 14 View Code Duplication
    while (count($keys) > 1) {
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...
1103
      $key = array_shift($keys);
1104
1105
      $this->array[$key] = $this->get(array(), null, $key);
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string.

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...
1106
      $this->array = &$this->array[$key];
1107
    }
1108
1109
    // Bind final tree on the array
1110 14
    $key = array_shift($keys);
1111
1112 14
    $this->array[$key] = $value;
1113
1114 14
    return true;
1115
  }
1116
1117
  /**
1118
   * Return an array with all elements found in input array.
1119
   *
1120
   * @param array $search
1121
   *
1122
   * @return Arrayy (Immutable)
1123
   */
1124 2
  public function intersection(array $search)
1125
  {
1126 2
    $result = array_values(array_intersect($this->array, $search));
1127
1128 2
    return static::create($result);
1129
  }
1130
1131
  /**
1132
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1133
   *
1134
   * @param array $search
1135
   *
1136
   * @return bool
1137
   */
1138 1
  public function intersects(array $search)
1139
  {
1140 1
    return count($this->intersection($search)->array) > 0;
1141
  }
1142
1143
  /**
1144
   * Invoke a function on all of an array's values.
1145
   *
1146
   * @param mixed $callable
1147
   * @param array $arguments
1148
   *
1149
   * @return Arrayy (Immutable)
1150
   */
1151 1
  public function invoke($callable, $arguments = array())
1152
  {
1153
    // If one argument given for each iteration, create an array for it.
1154 1
    if (!is_array($arguments)) {
1155 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1156 1
    }
1157
1158
    // If the callable has arguments, pass them.
1159 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...
1160 1
      $array = array_map($callable, $this->array, $arguments);
1161 1
    } else {
1162 1
      $array = array_map($callable, $this->array);
1163
    }
1164
1165 1
    return static::create($array);
1166
  }
1167
1168
  /**
1169
   * Check whether array is associative or not.
1170
   *
1171
   * @return bool Returns true if associative, false otherwise
1172
   */
1173 14
  public function isAssoc()
1174
  {
1175 14
    if ($this->isEmpty()) {
1176 2
      return false;
1177
    }
1178
1179 12
    foreach ($this->getKeys()->getArray() as $key) {
1180 12
      if (!is_string($key)) {
1181 10
        return false;
1182
      }
1183 2
    }
1184
1185 2
    return true;
1186
  }
1187
1188
  /**
1189
   * Check whether the array is empty or not.
1190
   *
1191
   * @return bool Returns true if empty, false otherwise
1192
   */
1193 22
  public function isEmpty()
1194
  {
1195 22
    return !$this->array;
1196
  }
1197
1198
  /**
1199
   * Check if the current array is a multi-array.
1200
   *
1201
   * @return bool
1202
   */
1203 13
  public function isMultiArray()
1204
  {
1205 13
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1206
  }
1207
1208
  /**
1209
   * Check whether array is numeric or not.
1210
   *
1211
   * @return bool Returns true if numeric, false otherwise
1212
   */
1213 4
  public function isNumeric()
1214
  {
1215 4
    if ($this->isEmpty()) {
1216 1
      return false;
1217
    }
1218
1219 3
    foreach ($this->getKeys() as $key) {
1220 3
      if (!is_int($key)) {
1221 2
        return false;
1222
      }
1223 2
    }
1224
1225 1
    return true;
1226
  }
1227
1228
  /**
1229
   * Get all keys from the current array.
1230
   *
1231
   * @return Arrayy (Immutable)
1232
   */
1233 20
  public function keys()
1234
  {
1235 20
    $array = array_keys((array)$this->array);
1236
1237 20
    return static::create($array);
1238
  }
1239
1240
  /**
1241
   * Get the last value from the current array.
1242
   *
1243
   * @return mixed Return null if there wasn't a element.
1244
   */
1245 4
  public function last()
1246
  {
1247 4
    $result = $this->pop();
1248
1249 4
    if (null === $result) {
1250 1
      return null;
1251
    } else {
1252 3
      return $result;
1253
    }
1254
  }
1255
1256
  /**
1257
   * Get the last value(s) from the current array.
1258
   *
1259
   * @param int|null $number
1260
   *
1261
   * @return Arrayy (Immutable)
1262
   */
1263 12
  public function lastsImmutable($number = null)
1264
  {
1265 12
    if ($number === null) {
1266 8
      $poppedValue = (array)$this->pop();
1267 8
      $arrayy = static::create($poppedValue);
1268 8
    } else {
1269 4
      $number = (int)$number;
1270 4
      $arrayy = $this->rest(-$number);
1271
    }
1272
1273 12
    return $arrayy;
1274
  }
1275
1276
  /**
1277
   * Get the last value(s) from the current array.
1278
   *
1279
   * @param int|null $number
1280
   *
1281
   * @return self (Mutable)
1282
   */
1283 12
  public function lastsMutable($number = null)
1284
  {
1285 12
    if ($number === null) {
1286 8
      $poppedValue = (array)$this->pop();
1287 8
      $this->array = static::create($poppedValue)->array;
1288 8
    } else {
1289 4
      $number = (int)$number;
1290 4
      $this->array = $this->rest(-$number)->array;
1291
    }
1292
1293 12
    return $this;
1294
  }
1295
1296
  /**
1297
   * Count the values from the current array.
1298
   *
1299
   * INFO: only a alias for "$arrayy->size()"
1300
   *
1301
   * @return int
1302
   */
1303 10
  public function length()
1304
  {
1305 10
    return $this->size();
1306
  }
1307
1308
  /**
1309
   * Apply the given function to the every element of the array,
1310
   * collecting the results.
1311
   *
1312
   * @param callable $callable
1313
   *
1314
   * @return Arrayy (Immutable) Arrayy object with modified elements
1315
   */
1316 4
  public function map($callable)
1317
  {
1318 4
    $result = array_map($callable, $this->array);
1319
1320 4
    return static::create($result);
1321
  }
1322
1323
  /**
1324
   * Check if all items in current array match a truth test.
1325
   *
1326
   * @param \Closure $closure
1327
   *
1328
   * @return bool
1329
   */
1330 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...
1331
  {
1332
    // Reduce the array to only booleans
1333 9
    $array = $this->each($closure);
1334
1335
    // Check the results
1336 9
    if (count($array) === 0) {
1337 2
      return true;
1338
    }
1339
1340 7
    $array = array_search(false, $array->toArray(), false);
1341
1342 7
    return is_bool($array);
1343
  }
1344
1345
  /**
1346
   * Check if any item in the current array matches a truth test.
1347
   *
1348
   * @param \Closure $closure
1349
   *
1350
   * @return bool
1351
   */
1352 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...
1353
  {
1354
    // Reduce the array to only booleans
1355 9
    $array = $this->each($closure);
1356
1357
    // Check the results
1358 9
    if (count($array) === 0) {
1359 2
      return true;
1360
    }
1361
1362 7
    $array = array_search(true, $array->toArray(), false);
1363
1364 7
    return is_int($array);
1365
  }
1366
1367
  /**
1368
   * Get the max value from an array.
1369
   *
1370
   * @return mixed
1371
   */
1372 10
  public function max()
1373
  {
1374 10
    if ($this->count() === 0) {
1375 1
      return false;
1376
    }
1377
1378 9
    return max($this->array);
1379
  }
1380
1381
  /**
1382
   * Merge the new $array into the current array.
1383
   *
1384
   * - keep key,value from the current array, also if the index is in the new $array
1385
   *
1386
   * @param array $array
1387
   * @param bool  $recursive
1388
   *
1389
   * @return Arrayy (Immutable)
1390
   */
1391 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...
1392
  {
1393 25
    if (true === $recursive) {
1394 4
      $result = array_replace_recursive($this->array, $array);
1395 4
    } else {
1396 21
      $result = array_replace($this->array, $array);
1397
    }
1398
1399 25
    return static::create($result);
1400
  }
1401
1402
  /**
1403
   * Merge the new $array into the current array.
1404
   *
1405
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1406
   * - create new indexes
1407
   *
1408
   * @param array $array
1409
   * @param bool  $recursive
1410
   *
1411
   * @return Arrayy (Immutable)
1412
   */
1413 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...
1414
  {
1415 16
    if (true === $recursive) {
1416 4
      $result = array_merge_recursive($this->array, $array);
1417 4
    } else {
1418 12
      $result = array_merge($this->array, $array);
1419
    }
1420
1421 16
    return static::create($result);
1422
  }
1423
1424
  /**
1425
   * Merge the the current array into the $array.
1426
   *
1427
   * - use key,value from the new $array, also if the index is in the current array
1428
   *
1429
   * @param array $array
1430
   * @param bool  $recursive
1431
   *
1432
   * @return Arrayy (Immutable)
1433
   */
1434 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...
1435
  {
1436 16
    if (true === $recursive) {
1437 4
      $result = array_replace_recursive($array, $this->array);
1438 4
    } else {
1439 12
      $result = array_replace($array, $this->array);
1440
    }
1441
1442 16
    return static::create($result);
1443
  }
1444
1445
  /**
1446
   * Merge the current array into the new $array.
1447
   *
1448
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1449
   * - create new indexes
1450
   *
1451
   * @param array $array
1452
   * @param bool  $recursive
1453
   *
1454
   * @return Arrayy (Immutable)
1455
   */
1456 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...
1457
  {
1458 16
    if (true === $recursive) {
1459 4
      $result = array_merge_recursive($array, $this->array);
1460 4
    } else {
1461 12
      $result = array_merge($array, $this->array);
1462
    }
1463
1464 16
    return static::create($result);
1465
  }
1466
1467
  /**
1468
   * Get the min value from an array.
1469
   *
1470
   * @return mixed
1471
   */
1472 10
  public function min()
1473
  {
1474 10
    if ($this->count() === 0) {
1475 1
      return false;
1476
    }
1477
1478 9
    return min($this->array);
1479
  }
1480
1481
  /**
1482
   * Pad array to the specified size with a given value.
1483
   *
1484
   * @param int   $size  Size of the result array
1485
   * @param mixed $value Empty value by default
1486
   *
1487
   * @return Arrayy (Immutable) Arrayy object padded to $size with $value
1488
   */
1489 4
  public function pad($size, $value)
1490
  {
1491 4
    $result = array_pad($this->array, $size, $value);
1492
1493 4
    return static::create($result);
1494
  }
1495
1496
  /**
1497
   * Pop a specified value off the end of the current array.
1498
   *
1499
   * @return mixed The popped element from the current array.
1500
   */
1501 16
  public function pop()
1502
  {
1503 16
    return array_pop($this->array);
1504
  }
1505
1506
  /**
1507
   * Prepend a value to the current array.
1508
   *
1509
   * @param mixed $value
1510
   *
1511
   * @return self (Mutable) Return this Arrayy object, with the prepended value.
1512
   */
1513 7
  public function prepend($value)
1514
  {
1515 7
    array_unshift($this->array, $value);
1516
1517 7
    return $this;
1518
  }
1519
1520
  /**
1521
   * Push one or more values onto the end of array at once.
1522
   *
1523
   * @return self (Mutable) Return this Arrayy object, with pushed elements to the end of array.
1524
   */
1525 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...
1526
  {
1527 4
    if (func_num_args()) {
1528 4
      $args = array_merge(array(&$this->array), func_get_args());
1529 4
      call_user_func_array('array_push', $args);
1530 4
    }
1531
1532 4
    return $this;
1533
  }
1534
1535
  /**
1536
   * Get a random value from the current array.
1537
   *
1538
   * @param null|int $number how many values you will take?
1539
   *
1540
   * @return self (Mutable)
1541
   */
1542 15
  public function randomMutable($number = null)
1543
  {
1544 15
    if ($this->count() === 0) {
1545
      return static::create();
1546
    }
1547
1548 15 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...
1549 6
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1550 6
      $this->array = $arrayRandValue;
1551
1552 6
      return $this;
1553
    }
1554
1555 10
    shuffle($this->array);
1556
1557 10
    return $this->firstsMutable($number);
1558
  }
1559
1560
  /**
1561
   * Get a random value from the current array.
1562
   *
1563
   * @param null|int $number how many values you will take?
1564
   *
1565
   * @return Arrayy (Immutable)
1566
   */
1567 16
  public function randomImmutable($number = null)
1568
  {
1569 16
    if ($this->count() === 0) {
1570
      return static::create();
1571
    }
1572
1573 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...
1574 13
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1575
1576 13
      return static::create($arrayRandValue);
1577
    }
1578
1579 5
    $arrayTmp = $this->array;
1580 5
    shuffle($arrayTmp);
1581
1582 5
    return self::create($arrayTmp)->firstsImmutable($number);
1583
  }
1584
1585
  /**
1586
   * Pick a random key/index from the keys of this array.
1587
   *
1588
   *
1589
   * @return mixed get a key/index or null if there wasn't a key/index
1590
   *
1591
   * @throws \RangeException If array is empty
1592
   */
1593 3
  public function randomKey()
1594
  {
1595 3
    $result = $this->randomKeys(1);
1596
1597 3
    if (!isset($result[0])) {
1598
      $result[0] = null;
1599
    }
1600
1601 3
    return $result[0];
1602
  }
1603
1604
  /**
1605
   * Pick a given number of random keys/indexes out of this array.
1606
   *
1607
   * @param int $number The number of keys/indexes (should be <= $this->count())
1608
   *
1609
   * @return Arrayy (Immutable)
1610
   *
1611
   * @throws \RangeException If array is empty
1612
   */
1613 12
  public function randomKeys($number)
1614
  {
1615 12
    $number = (int)$number;
1616 12
    $count = $this->count();
1617
1618 12
    if ($number === 0 || $number > $count) {
1619 3
      throw new \RangeException(
1620 3
          sprintf(
1621 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1622 3
              $number,
1623
              $count
1624 3
          )
1625 3
      );
1626
    }
1627
1628 9
    $result = (array)array_rand($this->array, $number);
1629
1630 9
    return static::create($result);
1631
  }
1632
1633
  /**
1634
   * Pick a random value from the values of this array.
1635
   *
1636
   * @return mixed get a random value or null if there wasn't a value
1637
   */
1638 3
  public function randomValue()
1639
  {
1640 3
    $result = $this->randomImmutable();
1641
1642 3
    if (!isset($result[0])) {
1643
      $result[0] = null;
1644
    }
1645
1646 3
    return $result[0];
1647
  }
1648
1649
  /**
1650
   * Pick a given number of random values out of this array.
1651
   *
1652
   * @param int $number
1653
   *
1654
   * @return self (Mutable)
1655
   */
1656 6
  public function randomValues($number)
1657
  {
1658 6
    $number = (int)$number;
1659
1660 6
    return $this->randomMutable($number);
1661
  }
1662
1663
  /**
1664
   * Get a random value from an array, with the ability to skew the results.
1665
   *
1666
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
1667
   *
1668
   * @param array    $array
1669
   * @param null|int $number how many values you will take?
1670
   *
1671
   * @return Arrayy (Immutable)
1672
   */
1673 9
  public function randomWeighted(array $array, $number = null)
1674
  {
1675 9
    $options = array();
1676 9
    foreach ($array as $option => $weight) {
1677 9
      if ($this->searchIndex($option) !== false) {
1678 2
        for ($i = 0; $i < $weight; ++$i) {
1679 1
          $options[] = $option;
1680 1
        }
1681 2
      }
1682 9
    }
1683
1684 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
1685
  }
1686
1687
  /**
1688
   * Reduce the current array via callable e.g. anonymous-function.
1689
   *
1690
   * @param mixed $callable
1691
   * @param array $init
1692
   *
1693
   * @return Arrayy (Immutable)
1694
   */
1695 3
  public function reduce($callable, array $init = array())
1696
  {
1697 3
    $result = array_reduce($this->array, $callable, $init);
1698
1699 3
    if ($result === null) {
1700
      $this->array = array();
1701
    } else {
1702 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...
1703
    }
1704
1705 3
    return static::create((array)$this->array);
1706
  }
1707
1708
  /**
1709
   * Create a numerically re-indexed Arrayy object.
1710
   *
1711
   * @return self (Mutable) Return this Arrayy object, with re-indexed array-elements.
1712
   */
1713 9
  public function reindex()
1714
  {
1715 9
    $this->array = array_values($this->array);
1716
1717 9
    return $this;
1718
  }
1719
1720
  /**
1721
   * Return all items that fail the truth test.
1722
   *
1723
   * @param \Closure $closure
1724
   *
1725
   * @return Arrayy (Immutable)
1726
   */
1727 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...
1728
  {
1729 1
    $filtered = array();
1730
1731 1
    foreach ($this->array as $key => $value) {
1732 1
      if (!$closure($value, $key)) {
1733 1
        $filtered[$key] = $value;
1734 1
      }
1735 1
    }
1736
1737 1
    return static::create($filtered);
1738
  }
1739
1740
  /**
1741
   * Remove a value from the current array (optional using dot-notation).
1742
   *
1743
   * @param mixed $key
1744
   *
1745
   * @return Arrayy (Immutable)
1746
   */
1747 17
  public function remove($key)
1748
  {
1749
    // Recursive call
1750 17
    if (is_array($key)) {
1751
      foreach ($key as $k) {
1752
        $this->internalRemove($k);
1753
      }
1754
1755
      return static::create($this->array);
1756
    }
1757
1758 17
    $this->internalRemove($key);
1759
1760 17
    return static::create($this->array);
1761
  }
1762
1763
  /**
1764
   * Remove the first value from the current array.
1765
   *
1766
   * @return Arrayy (Immutable)
1767
   */
1768 7
  public function removeFirst()
1769
  {
1770 7
    array_shift($this->array);
1771
1772 7
    return static::create($this->array);
1773
  }
1774
1775
  /**
1776
   * Remove the last value from the current array.
1777
   *
1778
   * @return Arrayy (Immutable)
1779
   */
1780 7
  public function removeLast()
1781
  {
1782 7
    array_pop($this->array);
1783
1784 7
    return static::create($this->array);
1785
  }
1786
1787
  /**
1788
   * Removes a particular value from an array (numeric or associative).
1789
   *
1790
   * @param mixed $value
1791
   *
1792
   * @return Arrayy (Immutable)
1793
   */
1794 7
  public function removeValue($value)
1795
  {
1796 7
    $isNumericArray = true;
1797 7
    foreach ($this->array as $key => $item) {
1798 6
      if ($item === $value) {
1799 6
        if (!is_int($key)) {
1800
          $isNumericArray = false;
1801
        }
1802 6
        unset($this->array[$key]);
1803 6
      }
1804 7
    }
1805
1806 7
    if ($isNumericArray) {
1807 7
      $this->array = array_values($this->array);
1808 7
    }
1809
1810 7
    return static::create($this->array);
1811
  }
1812
1813
  /**
1814
   * Replace a key with a new key/value pair.
1815
   *
1816
   * @param $replace
1817
   * @param $key
1818
   * @param $value
1819
   *
1820
   * @return Arrayy (Immutable)
1821
   */
1822 1
  public function replace($replace, $key, $value)
1823
  {
1824 1
    $this->remove($replace);
1825
1826 1
    return $this->set($key, $value);
1827
  }
1828
1829
  /**
1830
   * Create an array using the current array as values and the other array as keys.
1831
   *
1832
   * @param array $keys Keys array
1833
   *
1834
   * @return Arrayy (Immutable) Arrayy object with keys from the other array.
1835
   */
1836 1
  public function replaceAllKeys(array $keys)
1837
  {
1838 1
    $result = array_combine($keys, $this->array);
1839
1840 1
    return static::create($result);
1841
  }
1842
1843
  /**
1844
   * Create an array using the current array as keys and the other array as values.
1845
   *
1846
   * @param array $array Values array
1847
   *
1848
   * @return Arrayy (Immutable) Arrayy object with values from the other array.
1849
   */
1850 1
  public function replaceAllValues(array $array)
1851
  {
1852 1
    $result = array_combine($this->array, $array);
1853
1854 1
    return static::create($result);
1855
  }
1856
1857
  /**
1858
   * Replace the keys in an array with another set.
1859
   *
1860
   * @param array $keys An array of keys matching the array's size
1861
   *
1862
   * @return Arrayy (Immutable)
1863
   */
1864 1
  public function replaceKeys(array $keys)
1865
  {
1866 1
    $values = array_values($this->array);
1867 1
    $result = array_combine($keys, $values);
1868
1869 1
    return static::create($result);
1870
  }
1871
1872
  /**
1873
   * Replace the first matched value in an array.
1874
   *
1875
   * @param mixed $search
1876
   * @param mixed $replacement
1877
   *
1878
   * @return Arrayy (Immutable)
1879
   */
1880 3
  public function replaceOneValue($search, $replacement = '')
1881
  {
1882 3
    $array = $this->array;
1883 3
    $key = array_search($search, $array, true);
1884
1885 3
    if ($key !== false) {
1886 3
      $array[$key] = $replacement;
1887 3
    }
1888
1889 3
    return static::create($array);
1890
  }
1891
1892
  /**
1893
   * Replace values in the current array.
1894
   *
1895
   * @param string $search      The string to replace.
1896
   * @param string $replacement What to replace it with.
1897
   *
1898
   * @return Arrayy (Immutable)
1899
   */
1900 1
  public function replaceValues($search, $replacement = '')
1901
  {
1902 1
    $array = $this->each(
1903
        function ($value) use ($search, $replacement) {
1904 1
          return UTF8::str_replace($search, $replacement, $value);
1905
        }
1906 1
    );
1907
1908 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...
1909
  }
1910
1911
  /**
1912
   * Get the last elements from index $from until the end of this array.
1913
   *
1914
   * @param int $from
1915
   *
1916
   * @return Arrayy (Immutable)
1917
   */
1918 16
  public function rest($from = 1)
1919
  {
1920 16
    $result = array_splice($this->array, $from);
1921
1922 16
    return static::create($result);
1923
  }
1924
1925
  /**
1926
   * Return the array in the reverse order.
1927
   *
1928
   * @return self (Mutable) Return this Arrayy object.
1929
   */
1930 7
  public function reverse()
1931
  {
1932 7
    $this->array = array_reverse($this->array);
1933
1934 7
    return $this;
1935
  }
1936
1937
  /**
1938
   * Search for the first index of the current array via $value.
1939
   *
1940
   * @param mixed $value
1941
   *
1942
   * @return mixed
1943
   */
1944 20
  public function searchIndex($value)
1945
  {
1946 20
    return array_search($value, $this->array, true);
1947
  }
1948
1949
  /**
1950
   * Search for the value of the current array via $index.
1951
   *
1952
   * @param mixed $index
1953
   *
1954
   * @return Arrayy (Immutable) will return a empty Arrayy if the value wasn't found
1955
   */
1956 7
  public function searchValue($index)
1957
  {
1958
    // init
1959 7
    $return = array();
1960
1961 7
    if (null !== $index) {
1962 7
      $keyExists = isset($this->array[$index]);
1963
1964 7
      if ($keyExists !== false) {
1965 5
        $return = array($this->array[$index]);
1966 5
      }
1967 7
    }
1968
1969 7
    return static::create($return);
1970
  }
1971
1972
  /**
1973
   * Set a value for the current array (optional using dot-notation).
1974
   *
1975
   * @param string $key   The key to set
1976
   * @param mixed  $value Its value
1977
   *
1978
   * @return Arrayy (Immutable)
1979
   */
1980 14
  public function set($key, $value)
1981
  {
1982 14
    $this->internalSet($key, $value);
1983
1984 14
    return static::create($this->array);
1985
  }
1986
1987
  /**
1988
   * Get a value from a array and set it if it was not.
1989
   *
1990
   * WARNING: this method only set the value, if the $key is not already set
1991
   *
1992
   * @param string $key     The key
1993
   * @param mixed  $default The default value to set if it isn't
1994
   *
1995
   * @return mixed
1996
   */
1997 9
  public function setAndGet($key, $default = null)
1998
  {
1999
    // If the key doesn't exist, set it
2000 9
    if (!$this->has($key)) {
2001 4
      $this->array = $this->set($key, $default)->getArray();
2002 4
    }
2003
2004 9
    return $this->get($key);
2005
  }
2006
2007
  /**
2008
   * Shifts a specified value off the beginning of array.
2009
   *
2010
   * @return mixed A shifted element from the current array.
2011
   */
2012 4
  public function shift()
2013
  {
2014 4
    return array_shift($this->array);
2015
  }
2016
2017
  /**
2018
   * Shuffle the current array.
2019
   *
2020
   * @return Arrayy (Immutable)
2021
   */
2022 1
  public function shuffle()
2023
  {
2024 1
    $array = $this->array;
2025
2026 1
    shuffle($array);
2027
2028 1
    return static::create($array);
2029
  }
2030
2031
  /**
2032
   * Get the size of an array.
2033
   *
2034
   * @return int
2035
   */
2036 105
  public function size()
2037
  {
2038 105
    return count($this->array);
2039
  }
2040
2041
  /**
2042
   * Extract a slice of the array.
2043
   *
2044
   * @param int      $offset       Slice begin index
2045
   * @param int|null $length       Length of the slice
2046
   * @param bool     $preserveKeys Whether array keys are preserved or no
2047
   *
2048
   * @return static A slice of the original array with length $length
2049
   */
2050 4
  public function slice($offset, $length = null, $preserveKeys = false)
2051
  {
2052 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
2053
2054 4
    return static::create($result);
2055
  }
2056
2057
  /**
2058
   * Sort the current array and optional you can keep the keys.
2059
   *
2060
   * @param string|int $direction use SORT_ASC or SORT_DESC
2061
   * @param int|string $strategy
2062
   * @param bool       $keepKeys
2063
   *
2064
   * @return self (Mutable) Return this Arrayy object.
2065
   */
2066 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2067
  {
2068 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2069
2070 19
    return $this;
2071
  }
2072
2073
  /**
2074
   * Sort the current array by key.
2075
   *
2076
   * @link http://php.net/manual/en/function.ksort.php
2077
   * @link http://php.net/manual/en/function.krsort.php
2078
   *
2079
   * @param int|string $direction use SORT_ASC or SORT_DESC
2080
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2081
   *
2082
   * @return self (Mutable) Return this Arrayy object.
2083
   */
2084 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2085
  {
2086 18
    $this->sorterKeys($this->array, $direction, $strategy);
2087
2088 18
    return $this;
2089
  }
2090
2091
  /**
2092
   * Sort the current array by value.
2093
   *
2094
   * @param int $direction use SORT_ASC or SORT_DESC
2095
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2096
   *
2097
   * @return Arrayy (Immutable)
2098
   */
2099 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2100
  {
2101 1
    return $this->sort($direction, $strategy, true);
2102
  }
2103
2104
  /**
2105
   * Sort the current array by value.
2106
   *
2107
   * @param int $direction use SORT_ASC or SORT_DESC
2108
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2109
   *
2110
   * @return Arrayy (Immutable)
2111
   */
2112 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2113
  {
2114 1
    return $this->sort($direction, $strategy, false);
2115
  }
2116
2117
  /**
2118
   * Sort a array by value, by a closure or by a property.
2119
   *
2120
   * - If the sorter is null, the array is sorted naturally.
2121
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2122
   *
2123
   * @param null       $sorter
2124
   * @param string|int $direction
2125
   * @param int        $strategy
2126
   *
2127
   * @return Arrayy (Immutable)
2128
   */
2129 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2130
  {
2131 1
    $array = (array)$this->array;
2132 1
    $direction = $this->getDirection($direction);
2133
2134
    // Transform all values into their results.
2135 1
    if ($sorter) {
2136 1
      $arrayy = new self($array);
2137
2138 1
      $that = $this;
2139 1
      $results = $arrayy->each(
2140
          function ($value) use ($sorter, $that) {
2141 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2142
          }
2143 1
      );
2144
2145 1
      $results = $results->getArray();
2146 1
    } else {
2147 1
      $results = $array;
2148
    }
2149
2150
    // Sort by the results and replace by original values
2151 1
    array_multisort($results, $direction, $strategy, $array);
2152
2153 1
    return static::create($array);
2154
  }
2155
2156
  /**
2157
   * sorting keys
2158
   *
2159
   * @param array $elements
2160
   * @param int   $direction
2161
   * @param int   $strategy
2162
   */
2163 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2164
  {
2165 18
    $direction = $this->getDirection($direction);
2166
2167
    switch ($direction) {
2168 18
      case 'desc':
2169 18
      case SORT_DESC:
2170 6
        krsort($elements, $strategy);
2171 6
        break;
2172 13
      case 'asc':
2173 13
      case SORT_ASC:
2174 13
      default:
2175 13
        ksort($elements, $strategy);
2176 13
    }
2177 18
  }
2178
2179
  /**
2180
   * @param array      &$elements
2181
   * @param int|string $direction
2182
   * @param int        $strategy
2183
   * @param bool       $keepKeys
2184
   */
2185 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2186
  {
2187 19
    $direction = $this->getDirection($direction);
2188
2189 19
    if (!$strategy) {
2190 19
      $strategy = SORT_REGULAR;
2191 19
    }
2192
2193
    switch ($direction) {
2194 19
      case 'desc':
2195 19
      case SORT_DESC:
2196 9
        if ($keepKeys) {
2197 5
          arsort($elements, $strategy);
2198 5
        } else {
2199 4
          rsort($elements, $strategy);
2200
        }
2201 9
        break;
2202 10
      case 'asc':
2203 10
      case SORT_ASC:
2204 10
      default:
2205 10
        if ($keepKeys) {
2206 4
          asort($elements, $strategy);
2207 4
        } else {
2208 6
          sort($elements, $strategy);
2209
        }
2210 10
    }
2211 19
  }
2212
2213
  /**
2214
   * Split an array in the given amount of pieces.
2215
   *
2216
   * @param int  $numberOfPieces
2217
   * @param bool $keepKeys
2218
   *
2219
   * @return array
2220
   */
2221 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2222
  {
2223 1
    if (count($this->array) === 0) {
2224 1
      $result = array();
2225 1
    } else {
2226 1
      $numberOfPieces = (int)$numberOfPieces;
2227 1
      $splitSize = ceil(count($this->array) / $numberOfPieces);
2228 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
2229
    }
2230
2231 1
    return static::create($result);
2232
  }
2233
2234
  /**
2235
   * alias: for "Arrayy->getArray()"
2236
   */
2237 153
  public function toArray()
2238
  {
2239 153
    return $this->getArray();
2240
  }
2241
2242
  /**
2243
   * Convert the current array to JSON.
2244
   *
2245
   * @param null $options e.g. JSON_PRETTY_PRINT
2246
   *
2247
   * @return string
2248
   */
2249 5
  public function toJson($options = null)
2250
  {
2251 5
    return UTF8::json_encode($this->array, $options);
2252
  }
2253
2254
  /**
2255
   * Implodes array to a string with specified separator.
2256
   *
2257
   * @param string $separator The element's separator
2258
   *
2259
   * @return string The string representation of array, separated by ","
2260
   */
2261 15
  public function toString($separator = ',')
2262
  {
2263 15
    return $this->implode($separator);
2264
  }
2265
2266
  /**
2267
   * Return a duplicate free copy of the current array.
2268
   *
2269
   * @return Arrayy (Immutable)
2270
   */
2271 7
  public function unique()
2272
  {
2273 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...
2274 7
        $this->array,
2275 7
        function ($resultArray, $value) {
2276 6
          if (in_array($value, $resultArray, true) === false) {
2277 6
            $resultArray[] = $value;
2278 6
          }
2279
2280 6
          return $resultArray;
2281 7
        },
2282 7
        array()
2283 7
    );
2284
2285 7
    return static::create($this->array);
2286
  }
2287
2288
  /**
2289
   * Prepends one or more values to the beginning of array at once.
2290
   *
2291
   * @return self (Mutable) Return this Arrayy object, with prepended elements to the beginning of array.
2292
   */
2293 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...
2294
  {
2295 4
    if (func_num_args()) {
2296 4
      $args = array_merge(array(&$this->array), func_get_args());
2297 4
      call_user_func_array('array_unshift', $args);
2298 4
    }
2299
2300 4
    return $this;
2301
  }
2302
2303
  /**
2304
   * Get all values from a array.
2305
   *
2306
   * @return Arrayy (Immutable)
2307
   */
2308 1
  public function values()
2309
  {
2310 1
    $array = array_values((array)$this->array);
2311
2312 1
    return static::create($array);
2313
  }
2314
2315
  /**
2316
   * Apply the given function to every element in the array,
2317
   * discarding the results.
2318
   *
2319
   * @param callable $callable
2320
   * @param bool     $recursive Whether array will be walked recursively or no
2321
   *
2322
   * @return self (Mutable) Return this Arrayy object, with modified elements
2323
   */
2324 8
  public function walk($callable, $recursive = false)
2325
  {
2326 8
    if (true === $recursive) {
2327 4
      array_walk_recursive($this->array, $callable);
2328 4
    } else {
2329 4
      array_walk($this->array, $callable);
2330
    }
2331
2332 8
    return $this;
2333
  }
2334
2335
2336
}
2337