Completed
Push — master ( bca288...04fb36 )
by Lars
02:19
created

Arrayy::reject()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 12
Ratio 100 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 12
loc 12
ccs 6
cts 6
cp 1
rs 9.4285
cc 3
eloc 6
nc 3
nop 1
crap 3
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. use the current array, if it's a array
548
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
549
   * 3. fallback to empty array, if there is nothing
550
   * 4. call "createFromObject()" on object, if there is a "ArrayAccess"-object
551
   * 5. call "__toArray()" on object, if the method exists
552
   * 6. cast a string or object with "__toString()" into an array
553
   * 7. throw a "InvalidArgumentException"-Exception
554
   *
555
   * @param $array
556
   *
557
   * @return array
558
   *
559
   * @throws \InvalidArgumentException
560
   */
561 698
  protected function fallbackForArray(&$array)
562
  {
563 698
    if (is_array($array)) {
564 695
      return $array;
565
    }
566
567 5
    if ($array instanceof self) {
568 1
      return $array->getArray();
569
    }
570
571 4
    if (!$array) {
572 1
      return array();
573
    }
574
    
575 3
    if ($array instanceof ArrayAccess) {
576
      return self::createFromObject($array);
577
    }
578
579 3
    if (is_object($array) && method_exists($array, '__toArray')) {
580
      return (array)$array->__toArray();
581
    }
582
583
    if (
584 3
        is_string($array)
585
        ||
586 3
        (is_object($array) && method_exists($array, '__toString'))
587
    ) {
588 1
      return (array)$array;
589
    }
590
591 2
    throw new \InvalidArgumentException(
592 2
        'Passed value should be a array'
593
    );
594
  }
595
596
  /**
597
   * Find all items in an array that pass the truth test.
598
   *
599
   * @param \Closure|null $closure
600
   *
601
   * @return Arrayy (Immutable)
602
   */
603 8
  public function filter($closure = null)
604
  {
605 8
    if (!$closure) {
606 1
      return $this->clean();
607
    }
608
609 8
    $array = array_filter($this->array, $closure);
610
611 8
    return static::create($array);
612
  }
613
614
  /**
615
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
616
   * within that.
617
   *
618
   * @param        $property
619
   * @param        $value
620
   * @param string $comparisonOp
621
   *                            'eq' (equals),<br />
622
   *                            'gt' (greater),<br />
623
   *                            'gte' || 'ge' (greater or equals),<br />
624
   *                            'lt' (less),<br />
625
   *                            'lte' || 'le' (less or equals),<br />
626
   *                            'ne' (not equals),<br />
627
   *                            'contains',<br />
628
   *                            'notContains',<br />
629
   *                            'newer' (via strtotime),<br />
630
   *                            'older' (via strtotime),<br />
631
   *
632
   * @return Arrayy (Immutable)
633
   */
634 1
  public function filterBy($property, $value, $comparisonOp = null)
635
  {
636 1
    if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
637 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
638
    }
639
640
    $ops = array(
641
        'eq'          => function ($item, $prop, $value) {
642 1
          return $item[$prop] === $value;
643 1
        },
644
        'gt'          => function ($item, $prop, $value) {
645
          return $item[$prop] > $value;
646 1
        },
647
        'ge'         => function ($item, $prop, $value) {
648
          return $item[$prop] >= $value;
649 1
        },
650
        'gte'         => function ($item, $prop, $value) {
651
          return $item[$prop] >= $value;
652 1
        },
653
        'lt'          => function ($item, $prop, $value) {
654 1
          return $item[$prop] < $value;
655 1
        },
656
        'le'         => function ($item, $prop, $value) {
657
          return $item[$prop] <= $value;
658 1
        },
659
        'lte'         => function ($item, $prop, $value) {
660
          return $item[$prop] <= $value;
661 1
        },
662
        'ne'          => function ($item, $prop, $value) {
663
          return $item[$prop] !== $value;
664 1
        },
665
        'contains'    => function ($item, $prop, $value) {
666 1
          return in_array($item[$prop], (array)$value, true);
667 1
        },
668
        'notContains' => function ($item, $prop, $value) {
669
          return !in_array($item[$prop], (array)$value, true);
670 1
        },
671
        'newer'       => function ($item, $prop, $value) {
672
          return strtotime($item[$prop]) > strtotime($value);
673 1
        },
674
        'older'       => function ($item, $prop, $value) {
675
          return strtotime($item[$prop]) < strtotime($value);
676 1
        },
677
    );
678
679 1
    $result = array_values(
680
        array_filter(
681 1
            (array)$this->array,
682
            function ($item) use (
683 1
                $property,
684 1
                $value,
685 1
                $ops,
686 1
                $comparisonOp
687
            ) {
688 1
              $item = (array)$item;
689 1
              $itemArrayy = new Arrayy($item);
690 1
              $item[$property] = $itemArrayy->get($property, array());
691
692 1
              return $ops[$comparisonOp]($item, $property, $value);
693 1
            }
694
        )
695
    );
696
697 1
    return static::create($result);
698
  }
699
700
  /**
701
   * Find the first item in an array that passes the truth test,
702
   *  otherwise return false
703
   *
704
   * @param \Closure $closure
705
   *
706
   * @return mixed|false false if we did not find the value
707
   */
708 8
  public function find(\Closure $closure)
709
  {
710 8
    foreach ($this->array as $key => $value) {
711 6
      if ($closure($value, $key)) {
712 6
        return $value;
713
      }
714
    }
715
716 3
    return false;
717
  }
718
719
  /**
720
   * find by ...
721
   *
722
   * @param        $property
723
   * @param        $value
724
   * @param string $comparisonOp
725
   *
726
   * @return Arrayy (Immutable)
727
   */
728
  public function findBy($property, $value, $comparisonOp = 'eq')
729
  {
730
    $array = $this->filterBy($property, $value, $comparisonOp);
731
732
    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...
733
  }
734
735
  /**
736
   * Get the first value from the current array.
737
   *
738
   * @return mixed Return null if there wasn't a element.
739
   */
740 13
  public function first()
741
  {
742 13
    $result = array_shift($this->array);
743
744 13
    if (null === $result) {
745 3
      return null;
746
    } else {
747 10
      return $result;
748
    }
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 self (Mutable)
757
   */
758 26
  public function firstsMutable($number = null)
759
  {
760 26
    if ($number === null) {
761 11
      $this->array = (array)array_shift($this->array);
762
    } else {
763 15
      $number = (int)$number;
764 15
      $this->array = array_splice($this->array, 0, $number, true);
765
    }
766
767 26
    return $this;
768
  }
769
770
  /**
771
   * Get the first value(s) from the current array.
772
   *
773
   * @param int|null $number how many values you will take?
774
   *
775
   * @return Arrayy (Immutable)
776
   */
777 28
  public function firstsImmutable($number = null)
778
  {
779 28
    if ($number === null) {
780 7
      $array = (array)array_shift($this->array);
781
    } else {
782 21
      $number = (int)$number;
783 21
      $array = array_splice($this->array, 0, $number, true);
784
    }
785
786 28
    return static::create($array);
787
  }
788
789
  /**
790
   * Exchanges all keys with their associated values in an array.
791
   *
792
   * @return Arrayy (Immutable)
793
   */
794 1
  public function flip()
795
  {
796 1
    $result = array_flip($this->array);
797
798 1
    return static::create($result);
799
  }
800
801
  /**
802
   * Get a value from an array (optional using dot-notation).
803
   *
804
   * @param string $key     The key to look for.
805
   * @param mixed  $default Default value to fallback to.
806
   * @param array  $array   The array to get from, if it's set to "null" we use the current array from the class.
807
   *
808
   * @return mixed
809
   */
810 34
  public function get($key, $default = null, $array = null)
811
  {
812 34
    if (is_array($array) === true) {
813 3
      $usedArray = $array;
814
    } else {
815 32
      $usedArray = $this->array;
816
    }
817
818 34
    if (null === $key) {
819 1
      return $usedArray;
820
    }
821
822 34
    if (isset($usedArray[$key])) {
823 23
      return $usedArray[$key];
824
    }
825
826
    // Crawl through array, get key according to object or not
827 19
    foreach (explode('.', $key) as $segment) {
828 19
      if (!isset($usedArray[$segment])) {
829 17
        return $default instanceof Closure ? $default() : $default;
830
      }
831
832 2
      $usedArray = $usedArray[$segment];
833
    }
834
835 2
    return $usedArray;
836
  }
837
838
  /**
839
   * Get the current array from the "Arrayy"-object.
840
   *
841
   * @return array
842
   */
843 475
  public function getArray()
844
  {
845 475
    return $this->array;
846
  }
847
848
  /**
849
   * Returns the values from a single column of the input array, identified by
850
   * the $columnKey, can be used to extract data-columns from multi-arrays.
851
   *
852
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
853
   * array by the values from the $indexKey column in the input array.
854
   *
855
   * @param mixed $columnKey
856
   * @param mixed $indexKey
857
   *
858
   * @return Arrayy (Immutable)
859
   */
860 1
  public function getColumn($columnKey = null, $indexKey = null)
861
  {
862 1
    $result = array_column($this->array, $columnKey, $indexKey);
863
864 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 862 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...
865
  }
866
867
  /**
868
   * Get correct PHP constant for direction.
869
   *
870
   * @param int|string $direction
871
   *
872
   * @return int
873
   */
874 38
  protected function getDirection($direction)
875
  {
876 38
    if (is_string($direction)) {
877 10
      $direction = strtolower($direction);
878
879 10
      if ($direction === 'desc') {
880 2
        $direction = SORT_DESC;
881
      } else {
882 8
        $direction = SORT_ASC;
883
      }
884
    }
885
886
    if (
887 38
        $direction !== SORT_DESC
888
        &&
889 38
        $direction !== SORT_ASC
890
    ) {
891
      $direction = SORT_ASC;
892
    }
893
894 38
    return $direction;
895
  }
896
897
  /**
898
   * alias: for "Arrayy->keys()"
899
   *
900
   * @return Arrayy (Immutable)
901
   */
902
  public function getKeys()
903
  {
904
    return $this->keys();
905
  }
906
907
  /**
908
   * alias: for "Arrayy->random()"
909
   *
910
   * @return Arrayy (Immutable)
911
   */
912 3
  public function getRandom()
913
  {
914 3
    return $this->randomImmutable();
915
  }
916
917
  /**
918
   * alias: for "Arrayy->randomKey()"
919
   *
920
   * @return mixed get a key/index or null if there wasn't a key/index
921
   */
922 3
  public function getRandomKey()
923
  {
924 3
    return $this->randomKey();
925
  }
926
927
  /**
928
   * alias: for "Arrayy->randomKeys()"
929
   *
930
   * @param int $number
931
   *
932
   * @return Arrayy (Immutable)
933
   */
934 9
  public function getRandomKeys($number)
935
  {
936 9
    return $this->randomKeys($number);
937
  }
938
939
  /**
940
   * alias: for "Arrayy->randomValue()"
941
   *
942
   * @return mixed get a random value or null if there wasn't a value
943
   */
944 3
  public function getRandomValue()
945
  {
946 3
    return $this->randomValue();
947
  }
948
949
  /**
950
   * alias: for "Arrayy->randomValues()"
951
   *
952
   * @param int $number
953
   *
954
   * @return Arrayy (Immutable)
955
   */
956 6
  public function getRandomValues($number)
957
  {
958 6
    return $this->randomValues($number);
959
  }
960
961
  /**
962
   * Group values from a array according to the results of a closure.
963
   *
964
   * @param string $grouper a callable function name
965
   * @param bool   $saveKeys
966
   *
967
   * @return Arrayy (Immutable)
968
   */
969 3
  public function group($grouper, $saveKeys = false)
970
  {
971 3
    $array = (array)$this->array;
972 3
    $result = array();
973
974
    // Iterate over values, group by property/results from closure
975 3
    foreach ($array as $key => $value) {
976 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
977 3
      $newValue = $this->get($groupKey, null, $result);
978
979
      // Add to results
980 3
      if ($groupKey !== null) {
981 2
        if ($saveKeys) {
982 1
          $result[$groupKey] = $newValue;
983 1
          $result[$groupKey][$key] = $value;
984
        } else {
985 1
          $result[$groupKey] = $newValue;
986 3
          $result[$groupKey][] = $value;
987
        }
988
      }
989
990
    }
991
992 3
    return static::create($result);
993
  }
994
995
  /**
996
   * Check if an array has a given key.
997
   *
998
   * @param mixed $key
999
   *
1000
   * @return bool
1001
   */
1002 19
  public function has($key)
1003
  {
1004
    // Generate unique string to use as marker.
1005 19
    $unFound = (string)uniqid('arrayy', true);
1006
1007 19
    return $this->get($key, $unFound) !== $unFound;
1008
  }
1009
1010
  /**
1011
   * Implodes an array.
1012
   *
1013
   * @param string $with What to implode it with
1014
   *
1015
   * @return string
1016
   */
1017 23
  public function implode($with = '')
1018
  {
1019 23
    return implode($with, $this->array);
1020
  }
1021
1022
  /**
1023
   * Given a list and an iterate-function that returns
1024
   * a key for each element in the list (or a property name),
1025
   * returns an object with an index of each item.
1026
   *
1027
   * Just like groupBy, but for when you know your keys are unique.
1028
   *
1029
   * @param mixed $key
1030
   *
1031
   * @return Arrayy (Immutable)
1032
   */
1033 3
  public function indexBy($key)
1034
  {
1035 3
    $results = array();
1036
1037 3
    foreach ($this->array as $a) {
1038 3
      if (isset($a[$key])) {
1039 3
        $results[$a[$key]] = $a;
1040
      }
1041
    }
1042
1043 3
    return static::create($results);
1044
  }
1045
1046
  /**
1047
   * alias: for "Arrayy->searchIndex()"
1048
   *
1049
   * @param mixed $value Value to search for
1050
   *
1051
   * @return mixed
1052
   */
1053 4
  public function indexOf($value)
1054
  {
1055 4
    return $this->searchIndex($value);
1056
  }
1057
1058
  /**
1059
   * Get everything but the last..$to items.
1060
   *
1061
   * @param int $to
1062
   *
1063
   * @return Arrayy (Immutable)
1064
   */
1065 12
  public function initial($to = 1)
1066
  {
1067 12
    $slice = count($this->array) - $to;
1068
1069 12
    return $this->firstsImmutable($slice);
1070
  }
1071
1072
  /**
1073
   * Internal mechanics of remove method.
1074
   *
1075
   * @param $key
1076
   *
1077
   * @return boolean
1078
   */
1079 18
  protected function internalRemove($key)
1080
  {
1081
    // Explode keys
1082 18
    $keys = explode('.', $key);
1083
1084
    // Crawl though the keys
1085 18
    while (count($keys) > 1) {
1086
      $key = array_shift($keys);
1087
1088
      if (!$this->has($key)) {
1089
        return false;
1090
      }
1091
1092
      $this->array = &$this->array[$key];
1093
    }
1094
1095 18
    $key = array_shift($keys);
1096
1097 18
    unset($this->array[$key]);
1098
1099 18
    return true;
1100
  }
1101
1102
  /**
1103
   * Internal mechanic of set method.
1104
   *
1105
   * @param string $key
1106
   * @param mixed $value
1107
   *
1108
   * @return bool
1109
   */
1110 17
  protected function internalSet($key, $value)
1111
  {
1112 17
    if (null === $key) {
1113
      return false;
1114
    }
1115
1116
    // init
1117 17
    $array = &$this->array;
1118
1119
    // Explode the keys
1120 17
    $keys = explode('.', $key);
1121
1122
    // Crawl through the keys
1123 17
    while (count($keys) > 1) {
1124 1
      $key = array_shift($keys);
1125
      // If the key doesn't exist at this depth, we will just create an empty array
1126
      // to hold the next value, allowing us to create the arrays to hold final
1127
      // values at the correct depth. Then we'll keep digging into the array.
1128 1
      if (! isset($array[$key]) || ! is_array($array[$key])) {
1129
        $array[$key] = array();
1130
      }
1131 1
      $array = &$array[$key];
1132
    }
1133
1134 17
    $array[array_shift($keys)] = $value;
1135
1136 17
    return true;
1137
  }
1138
1139
  /**
1140
   * Return an array with all elements found in input array.
1141
   *
1142
   * @param array $search
1143
   *
1144
   * @return Arrayy (Immutable)
1145
   */
1146 2
  public function intersection(array $search)
1147
  {
1148 2
    $result = array_values(array_intersect($this->array, $search));
1149
1150 2
    return static::create($result);
1151
  }
1152
1153
  /**
1154
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1155
   *
1156
   * @param array $search
1157
   *
1158
   * @return bool
1159
   */
1160 1
  public function intersects(array $search)
1161
  {
1162 1
    return count($this->intersection($search)->array) > 0;
1163
  }
1164
1165
  /**
1166
   * Invoke a function on all of an array's values.
1167
   *
1168
   * @param mixed $callable
1169
   * @param array $arguments
1170
   *
1171
   * @return Arrayy (Immutable)
1172
   */
1173 1
  public function invoke($callable, $arguments = array())
1174
  {
1175
    // If one argument given for each iteration, create an array for it.
1176 1
    if (!is_array($arguments)) {
1177 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1178
    }
1179
1180
    // If the callable has arguments, pass them.
1181 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...
1182 1
      $array = array_map($callable, $this->array, $arguments);
1183
    } else {
1184 1
      $array = array_map($callable, $this->array);
1185
    }
1186
1187 1
    return static::create($array);
1188
  }
1189
1190
  /**
1191
   * Check whether array is associative or not.
1192
   *
1193
   * @return bool Returns true if associative, false otherwise
1194
   */
1195 14
  public function isAssoc()
1196
  {
1197 14
    if ($this->isEmpty()) {
1198 2
      return false;
1199
    }
1200
1201 12
    foreach ($this->keys()->getArray() as $key) {
1202 12
      if (!is_string($key)) {
1203 12
        return false;
1204
      }
1205
    }
1206
1207 2
    return true;
1208
  }
1209
1210
  /**
1211
   * Check whether the array is empty or not.
1212
   *
1213
   * @return bool Returns true if empty, false otherwise
1214
   */
1215 22
  public function isEmpty()
1216
  {
1217 22
    return !$this->array;
1218
  }
1219
1220
  /**
1221
   * Check if the current array is a multi-array.
1222
   *
1223
   * @return bool
1224
   */
1225 13
  public function isMultiArray()
1226
  {
1227 13
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1228
  }
1229
1230
  /**
1231
   * Check whether array is numeric or not.
1232
   *
1233
   * @return bool Returns true if numeric, false otherwise
1234
   */
1235 4
  public function isNumeric()
1236
  {
1237 4
    if ($this->isEmpty()) {
1238 1
      return false;
1239
    }
1240
1241 3
    foreach ($this->keys() as $key) {
1242 3
      if (!is_int($key)) {
1243 3
        return false;
1244
      }
1245
    }
1246
1247 1
    return true;
1248
  }
1249
1250
  /**
1251
   * Get all keys from the current array.
1252
   *
1253
   * @return Arrayy (Immutable)
1254
   */
1255 20
  public function keys()
1256
  {
1257 20
    $array = array_keys((array)$this->array);
1258
1259 20
    return static::create($array);
1260
  }
1261
1262
  /**
1263
   * Get the last value from the current array.
1264
   *
1265
   * @return mixed Return null if there wasn't a element.
1266
   */
1267 4
  public function last()
1268
  {
1269 4
    $result = $this->pop();
1270
1271 4
    if (null === $result) {
1272 1
      return null;
1273
    } else {
1274 3
      return $result;
1275
    }
1276
  }
1277
1278
  /**
1279
   * Get the last value(s) from the current array.
1280
   *
1281
   * @param int|null $number
1282
   *
1283
   * @return Arrayy (Immutable)
1284
   */
1285 12
  public function lastsImmutable($number = null)
1286
  {
1287 12
    if ($number === null) {
1288 8
      $poppedValue = (array)$this->pop();
1289 8
      $arrayy = static::create($poppedValue);
1290
    } else {
1291 4
      $number = (int)$number;
1292 4
      $arrayy = $this->rest(-$number);
1293
    }
1294
1295 12
    return $arrayy;
1296
  }
1297
1298
  /**
1299
   * Get the last value(s) from the current array.
1300
   *
1301
   * @param int|null $number
1302
   *
1303
   * @return self (Mutable)
1304
   */
1305 12
  public function lastsMutable($number = null)
1306
  {
1307 12
    if ($number === null) {
1308 8
      $poppedValue = (array)$this->pop();
1309 8
      $this->array = static::create($poppedValue)->array;
1310
    } else {
1311 4
      $number = (int)$number;
1312 4
      $this->array = $this->rest(-$number)->array;
1313
    }
1314
1315 12
    return $this;
1316
  }
1317
1318
  /**
1319
   * Count the values from the current array.
1320
   *
1321
   * INFO: only a alias for "$arrayy->size()"
1322
   *
1323
   * @return int
1324
   */
1325 10
  public function length()
1326
  {
1327 10
    return $this->size();
1328
  }
1329
1330
  /**
1331
   * Apply the given function to the every element of the array,
1332
   * collecting the results.
1333
   *
1334
   * @param callable $callable
1335
   *
1336
   * @return Arrayy (Immutable) Arrayy object with modified elements
1337
   */
1338 4
  public function map($callable)
1339
  {
1340 4
    $result = array_map($callable, $this->array);
1341
1342 4
    return static::create($result);
1343
  }
1344
1345
  /**
1346
   * Check if all items in current array match a truth test.
1347
   *
1348
   * @param \Closure $closure
1349
   *
1350
   * @return bool
1351
   */
1352 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...
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(false, $array->toArray(), false);
1363
1364 7
    return is_bool($array);
1365
  }
1366
1367
  /**
1368
   * Check if any item in the current array matches a truth test.
1369
   *
1370
   * @param \Closure $closure
1371
   *
1372
   * @return bool
1373
   */
1374 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...
1375
  {
1376
    // Reduce the array to only booleans
1377 9
    $array = $this->each($closure);
1378
1379
    // Check the results
1380 9
    if (count($array) === 0) {
1381 2
      return true;
1382
    }
1383
1384 7
    $array = array_search(true, $array->toArray(), false);
1385
1386 7
    return is_int($array);
1387
  }
1388
1389
  /**
1390
   * Get the max value from an array.
1391
   *
1392
   * @return mixed
1393
   */
1394 10
  public function max()
1395
  {
1396 10
    if ($this->count() === 0) {
1397 1
      return false;
1398
    }
1399
1400 9
    return max($this->array);
1401
  }
1402
1403
  /**
1404
   * Merge the new $array into the current array.
1405
   *
1406
   * - keep key,value from the current array, also if the index is in the new $array
1407
   *
1408
   * @param array $array
1409
   * @param bool  $recursive
1410
   *
1411
   * @return Arrayy (Immutable)
1412
   */
1413 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...
1414
  {
1415 25
    if (true === $recursive) {
1416 4
      $result = array_replace_recursive($this->array, $array);
1417
    } else {
1418 21
      $result = array_replace($this->array, $array);
1419
    }
1420
1421 25
    return static::create($result);
1422
  }
1423
1424
  /**
1425
   * Merge the new $array into the current array.
1426
   *
1427
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1428
   * - create new indexes
1429
   *
1430
   * @param array $array
1431
   * @param bool  $recursive
1432
   *
1433
   * @return Arrayy (Immutable)
1434
   */
1435 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...
1436
  {
1437 16
    if (true === $recursive) {
1438 4
      $result = array_merge_recursive($this->array, $array);
1439
    } else {
1440 12
      $result = array_merge($this->array, $array);
1441
    }
1442
1443 16
    return static::create($result);
1444
  }
1445
1446
  /**
1447
   * Merge the the current array into the $array.
1448
   *
1449
   * - use key,value from the new $array, also if the index is in the current array
1450
   *
1451
   * @param array $array
1452
   * @param bool  $recursive
1453
   *
1454
   * @return Arrayy (Immutable)
1455
   */
1456 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...
1457
  {
1458 16
    if (true === $recursive) {
1459 4
      $result = array_replace_recursive($array, $this->array);
1460
    } else {
1461 12
      $result = array_replace($array, $this->array);
1462
    }
1463
1464 16
    return static::create($result);
1465
  }
1466
1467
  /**
1468
   * Merge the current array into the new $array.
1469
   *
1470
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1471
   * - create new indexes
1472
   *
1473
   * @param array $array
1474
   * @param bool  $recursive
1475
   *
1476
   * @return Arrayy (Immutable)
1477
   */
1478 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...
1479
  {
1480 16
    if (true === $recursive) {
1481 4
      $result = array_merge_recursive($array, $this->array);
1482
    } else {
1483 12
      $result = array_merge($array, $this->array);
1484
    }
1485
1486 16
    return static::create($result);
1487
  }
1488
1489
  /**
1490
   * Get the min value from an array.
1491
   *
1492
   * @return mixed
1493
   */
1494 10
  public function min()
1495
  {
1496 10
    if ($this->count() === 0) {
1497 1
      return false;
1498
    }
1499
1500 9
    return min($this->array);
1501
  }
1502
1503
  /**
1504
   * Pad array to the specified size with a given value.
1505
   *
1506
   * @param int   $size  Size of the result array
1507
   * @param mixed $value Empty value by default
1508
   *
1509
   * @return Arrayy (Immutable) Arrayy object padded to $size with $value
1510
   */
1511 4
  public function pad($size, $value)
1512
  {
1513 4
    $result = array_pad($this->array, $size, $value);
1514
1515 4
    return static::create($result);
1516
  }
1517
1518
  /**
1519
   * Pop a specified value off the end of the current array.
1520
   *
1521
   * @return mixed The popped element from the current array.
1522
   */
1523 16
  public function pop()
1524
  {
1525 16
    return array_pop($this->array);
1526
  }
1527
1528
  /**
1529
   * Prepend a value to the current array.
1530
   *
1531
   * @param mixed $value
1532
   *
1533
   * @return self (Mutable) Return this Arrayy object, with the prepended value.
1534
   */
1535 7
  public function prepend($value)
1536
  {
1537 7
    array_unshift($this->array, $value);
1538
1539 7
    return $this;
1540
  }
1541
1542
  /**
1543
   * Push one or more values onto the end of array at once.
1544
   *
1545
   * @return self (Mutable) Return this Arrayy object, with pushed elements to the end of array.
1546
   */
1547 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...
1548
  {
1549 4
    if (func_num_args()) {
1550 4
      $args = array_merge(array(&$this->array), func_get_args());
1551 4
      call_user_func_array('array_push', $args);
1552
    }
1553
1554 4
    return $this;
1555
  }
1556
1557
  /**
1558
   * Get a random value from the current array.
1559
   *
1560
   * @param null|int $number how many values you will take?
1561
   *
1562
   * @return self (Mutable)
1563
   */
1564 16
  public function randomMutable($number = null)
1565
  {
1566 16
    if ($this->count() === 0) {
1567
      return static::create();
1568
    }
1569
1570 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...
1571 6
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1572 6
      $this->array = $arrayRandValue;
1573
1574 6
      return $this;
1575
    }
1576
1577 11
    shuffle($this->array);
1578
1579 11
    return $this->firstsMutable($number);
1580
  }
1581
1582
  /**
1583
   * Get a random value from the current array.
1584
   *
1585
   * @param null|int $number how many values you will take?
1586
   *
1587
   * @return Arrayy (Immutable)
1588
   */
1589 17
  public function randomImmutable($number = null)
1590
  {
1591 17
    if ($this->count() === 0) {
1592
      return static::create();
1593
    }
1594
1595 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...
1596 14
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
1597
1598 14
      return static::create($arrayRandValue);
1599
    }
1600
1601 5
    $arrayTmp = $this->array;
1602 5
    shuffle($arrayTmp);
1603
1604 5
    return self::create($arrayTmp)->firstsImmutable($number);
1605
  }
1606
1607
  /**
1608
   * Pick a random key/index from the keys of this array.
1609
   *
1610
   *
1611
   * @return mixed get a key/index or null if there wasn't a key/index
1612
   *
1613
   * @throws \RangeException If array is empty
1614
   */
1615 4
  public function randomKey()
1616
  {
1617 4
    $result = $this->randomKeys(1);
1618
1619 4
    if (!isset($result[0])) {
1620
      $result[0] = null;
1621
    }
1622
1623 4
    return $result[0];
1624
  }
1625
1626
  /**
1627
   * Pick a given number of random keys/indexes out of this array.
1628
   *
1629
   * @param int $number The number of keys/indexes (should be <= $this->count())
1630
   *
1631
   * @return Arrayy (Immutable)
1632
   *
1633
   * @throws \RangeException If array is empty
1634
   */
1635 14
  public function randomKeys($number)
1636
  {
1637 14
    $number = (int)$number;
1638 14
    $count = $this->count();
1639
1640 14
    if ($number === 0 || $number > $count) {
1641 3
      throw new \RangeException(
1642
          sprintf(
1643 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1644
              $number,
1645
              $count
1646
          )
1647
      );
1648
    }
1649
1650 11
    $result = (array)array_rand($this->array, $number);
1651
1652 11
    return static::create($result);
1653
  }
1654
1655
  /**
1656
   * Pick a random value from the values of this array.
1657
   *
1658
   * @return mixed get a random value or null if there wasn't a value
1659
   */
1660 4
  public function randomValue()
1661
  {
1662 4
    $result = $this->randomImmutable();
1663
1664 4
    if (!isset($result[0])) {
1665
      $result[0] = null;
1666
    }
1667
1668 4
    return $result[0];
1669
  }
1670
1671
  /**
1672
   * Pick a given number of random values out of this array.
1673
   *
1674
   * @param int $number
1675
   *
1676
   * @return self (Mutable)
1677
   */
1678 7
  public function randomValues($number)
1679
  {
1680 7
    $number = (int)$number;
1681
1682 7
    return $this->randomMutable($number);
1683
  }
1684
1685
  /**
1686
   * Get a random value from an array, with the ability to skew the results.
1687
   *
1688
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
1689
   *
1690
   * @param array    $array
1691
   * @param null|int $number how many values you will take?
1692
   *
1693
   * @return Arrayy (Immutable)
1694
   */
1695 9
  public function randomWeighted(array $array, $number = null)
1696
  {
1697 9
    $options = array();
1698 9
    foreach ($array as $option => $weight) {
1699 9
      if ($this->searchIndex($option) !== false) {
1700 9
        for ($i = 0; $i < $weight; ++$i) {
1701 1
          $options[] = $option;
1702
        }
1703
      }
1704
    }
1705
1706 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
1707
  }
1708
1709
  /**
1710
   * Reduce the current array via callable e.g. anonymous-function.
1711
   *
1712
   * @param mixed $callable
1713
   * @param array $init
1714
   *
1715
   * @return Arrayy (Immutable)
1716
   */
1717 3
  public function reduce($callable, array $init = array())
1718
  {
1719 3
    $result = array_reduce($this->array, $callable, $init);
1720
1721 3
    if ($result === null) {
1722
      $this->array = array();
1723
    } else {
1724 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...
1725
    }
1726
1727 3
    return static::create((array)$this->array);
1728
  }
1729
1730
  /**
1731
   * Create a numerically re-indexed Arrayy object.
1732
   *
1733
   * @return self (Mutable) Return this Arrayy object, with re-indexed array-elements.
1734
   */
1735 9
  public function reindex()
1736
  {
1737 9
    $this->array = array_values($this->array);
1738
1739 9
    return $this;
1740
  }
1741
1742
  /**
1743
   * Return all items that fail the truth test.
1744
   *
1745
   * @param \Closure $closure
1746
   *
1747
   * @return Arrayy (Immutable)
1748
   */
1749 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...
1750
  {
1751 1
    $filtered = array();
1752
1753 1
    foreach ($this->array as $key => $value) {
1754 1
      if (!$closure($value, $key)) {
1755 1
        $filtered[$key] = $value;
1756
      }
1757
    }
1758
1759 1
    return static::create($filtered);
1760
  }
1761
1762
  /**
1763
   * Remove a value from the current array (optional using dot-notation).
1764
   *
1765
   * @param mixed $key
1766
   *
1767
   * @return Arrayy (Immutable)
1768
   */
1769 18
  public function remove($key)
1770
  {
1771
    // Recursive call
1772 18
    if (is_array($key)) {
1773
      foreach ($key as $k) {
1774
        $this->internalRemove($k);
1775
      }
1776
1777
      return static::create($this->array);
1778
    }
1779
1780 18
    $this->internalRemove($key);
1781
1782 18
    return static::create($this->array);
1783
  }
1784
1785
  /**
1786
   * Remove the first value from the current array.
1787
   *
1788
   * @return Arrayy (Immutable)
1789
   */
1790 7
  public function removeFirst()
1791
  {
1792 7
    array_shift($this->array);
1793
1794 7
    return static::create($this->array);
1795
  }
1796
1797
  /**
1798
   * Remove the last value from the current array.
1799
   *
1800
   * @return Arrayy (Immutable)
1801
   */
1802 7
  public function removeLast()
1803
  {
1804 7
    array_pop($this->array);
1805
1806 7
    return static::create($this->array);
1807
  }
1808
1809
  /**
1810
   * Removes a particular value from an array (numeric or associative).
1811
   *
1812
   * @param mixed $value
1813
   *
1814
   * @return Arrayy (Immutable)
1815
   */
1816 7
  public function removeValue($value)
1817
  {
1818 7
    $isNumericArray = true;
1819 7
    foreach ($this->array as $key => $item) {
1820 6
      if ($item === $value) {
1821 6
        if (!is_int($key)) {
1822
          $isNumericArray = false;
1823
        }
1824 6
        unset($this->array[$key]);
1825
      }
1826
    }
1827
1828 7
    if ($isNumericArray) {
1829 7
      $this->array = array_values($this->array);
1830
    }
1831
1832 7
    return static::create($this->array);
1833
  }
1834
1835
  /**
1836
   * Replace a key with a new key/value pair.
1837
   *
1838
   * @param $replace
1839
   * @param $key
1840
   * @param $value
1841
   *
1842
   * @return Arrayy (Immutable)
1843
   */
1844 2
  public function replace($replace, $key, $value)
1845
  {
1846 2
    $this->remove($replace);
1847
1848 2
    return $this->set($key, $value);
1849
  }
1850
1851
  /**
1852
   * Create an array using the current array as values and the other array as keys.
1853
   *
1854
   * @param array $keys Keys array
1855
   *
1856
   * @return Arrayy (Immutable) Arrayy object with keys from the other array.
1857
   */
1858 2
  public function replaceAllKeys(array $keys)
1859
  {
1860 2
    $result = array_combine($keys, $this->array);
1861
1862 2
    return static::create($result);
1863
  }
1864
1865
  /**
1866
   * Create an array using the current array as keys and the other array as values.
1867
   *
1868
   * @param array $array Values array
1869
   *
1870
   * @return Arrayy (Immutable) Arrayy object with values from the other array.
1871
   */
1872 2
  public function replaceAllValues(array $array)
1873
  {
1874 2
    $result = array_combine($this->array, $array);
1875
1876 2
    return static::create($result);
1877
  }
1878
1879
  /**
1880
   * Replace the keys in an array with another set.
1881
   *
1882
   * @param array $keys An array of keys matching the array's size
1883
   *
1884
   * @return Arrayy (Immutable)
1885
   */
1886 1
  public function replaceKeys(array $keys)
1887
  {
1888 1
    $values = array_values($this->array);
1889 1
    $result = array_combine($keys, $values);
1890
1891 1
    return static::create($result);
1892
  }
1893
1894
  /**
1895
   * Replace the first matched value in an array.
1896
   *
1897
   * @param mixed $search
1898
   * @param mixed $replacement
1899
   *
1900
   * @return Arrayy (Immutable)
1901
   */
1902 3
  public function replaceOneValue($search, $replacement = '')
1903
  {
1904 3
    $array = $this->array;
1905 3
    $key = array_search($search, $array, true);
1906
1907 3
    if ($key !== false) {
1908 3
      $array[$key] = $replacement;
1909
    }
1910
1911 3
    return static::create($array);
1912
  }
1913
1914
  /**
1915
   * Replace values in the current array.
1916
   *
1917
   * @param string $search      The string to replace.
1918
   * @param string $replacement What to replace it with.
1919
   *
1920
   * @return Arrayy (Immutable)
1921
   */
1922 1
  public function replaceValues($search, $replacement = '')
1923
  {
1924 1
    $array = $this->each(
1925
        function ($value) use ($search, $replacement) {
1926 1
          return UTF8::str_replace($search, $replacement, $value);
1927 1
        }
1928
    );
1929
1930 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...
1931
  }
1932
1933
  /**
1934
   * Get the last elements from index $from until the end of this array.
1935
   *
1936
   * @param int $from
1937
   *
1938
   * @return Arrayy (Immutable)
1939
   */
1940 16
  public function rest($from = 1)
1941
  {
1942 16
    $result = array_splice($this->array, $from);
1943
1944 16
    return static::create($result);
1945
  }
1946
1947
  /**
1948
   * Return the array in the reverse order.
1949
   *
1950
   * @return self (Mutable) Return this Arrayy object.
1951
   */
1952 7
  public function reverse()
1953
  {
1954 7
    $this->array = array_reverse($this->array);
1955
1956 7
    return $this;
1957
  }
1958
1959
  /**
1960
   * Search for the first index of the current array via $value.
1961
   *
1962
   * @param mixed $value
1963
   *
1964
   * @return mixed
1965
   */
1966 20
  public function searchIndex($value)
1967
  {
1968 20
    return array_search($value, $this->array, true);
1969
  }
1970
1971
  /**
1972
   * Search for the value of the current array via $index.
1973
   *
1974
   * @param mixed $index
1975
   *
1976
   * @return Arrayy (Immutable) will return a empty Arrayy if the value wasn't found
1977
   */
1978 7
  public function searchValue($index)
1979
  {
1980
    // init
1981 7
    $return = array();
1982
1983 7
    if (null !== $index) {
1984 7
      $keyExists = isset($this->array[$index]);
1985
1986 7
      if ($keyExists !== false) {
1987 5
        $return = array($this->array[$index]);
1988
      }
1989
    }
1990
1991 7
    return static::create($return);
1992
  }
1993
1994
  /**
1995
   * Set a value for the current array (optional using dot-notation).
1996
   *
1997
   * @param string $key   The key to set
1998
   * @param mixed  $value Its value
1999
   *
2000
   * @return Arrayy (Immutable)
2001
   */
2002 17
  public function set($key, $value)
2003
  {
2004 17
    $this->internalSet($key, $value);
2005
2006 17
    return static::create($this->array);
2007
  }
2008
2009
  /**
2010
   * Get a value from a array and set it if it was not.
2011
   *
2012
   * WARNING: this method only set the value, if the $key is not already set
2013
   *
2014
   * @param string $key      The key
2015
   * @param mixed  $fallback The default value to set if it isn't
2016
   *
2017
   * @return mixed (Mutable)
2018
   */
2019 10
  public function setAndGet($key, $fallback = null)
2020
  {
2021
    // If the key doesn't exist, set it
2022 10
    if (!$this->has($key)) {
2023 5
      $this->array = $this->set($key, $fallback)->getArray();
2024
    }
2025
2026 10
    return $this->get($key);
2027
  }
2028
2029
  /**
2030
   * Shifts a specified value off the beginning of array.
2031
   *
2032
   * @return mixed A shifted element from the current array.
2033
   */
2034 4
  public function shift()
2035
  {
2036 4
    return array_shift($this->array);
2037
  }
2038
2039
  /**
2040
   * Shuffle the current array.
2041
   *
2042
   * @return Arrayy (Immutable)
2043
   */
2044 1
  public function shuffle()
2045
  {
2046 1
    $array = $this->array;
2047
2048 1
    shuffle($array);
2049
2050 1
    return static::create($array);
2051
  }
2052
2053
  /**
2054
   * Get the size of an array.
2055
   *
2056
   * @return int
2057
   */
2058 109
  public function size()
2059
  {
2060 109
    return count($this->array);
2061
  }
2062
2063
  /**
2064
   * Extract a slice of the array.
2065
   *
2066
   * @param int      $offset       Slice begin index
2067
   * @param int|null $length       Length of the slice
2068
   * @param bool     $preserveKeys Whether array keys are preserved or no
2069
   *
2070
   * @return static A slice of the original array with length $length
2071
   */
2072 4
  public function slice($offset, $length = null, $preserveKeys = false)
2073
  {
2074 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
2075
2076 4
    return static::create($result);
2077
  }
2078
2079
  /**
2080
   * Sort the current array and optional you can keep the keys.
2081
   *
2082
   * @param integer $direction use SORT_ASC or SORT_DESC
2083
   * @param integer $strategy
2084
   * @param bool       $keepKeys
2085
   *
2086
   * @return self (Mutable) Return this Arrayy object.
2087
   */
2088 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2089
  {
2090 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2091
2092 19
    return $this;
2093
  }
2094
2095
  /**
2096
   * Sort the current array by key.
2097
   *
2098
   * @link http://php.net/manual/en/function.ksort.php
2099
   * @link http://php.net/manual/en/function.krsort.php
2100
   *
2101
   * @param int|string $direction use SORT_ASC or SORT_DESC
2102
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2103
   *
2104
   * @return self (Mutable) Return this Arrayy object.
2105
   */
2106 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2107
  {
2108 18
    $this->sorterKeys($this->array, $direction, $strategy);
2109
2110 18
    return $this;
2111
  }
2112
2113
  /**
2114
   * Sort the current array by value.
2115
   *
2116
   * @param int $direction use SORT_ASC or SORT_DESC
2117
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2118
   *
2119
   * @return Arrayy (Immutable)
2120
   */
2121 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2122
  {
2123 1
    return $this->sort($direction, $strategy, true);
2124
  }
2125
2126
  /**
2127
   * Sort the current array by value.
2128
   *
2129
   * @param int $direction use SORT_ASC or SORT_DESC
2130
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2131
   *
2132
   * @return Arrayy (Immutable)
2133
   */
2134 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2135
  {
2136 1
    return $this->sort($direction, $strategy, false);
2137
  }
2138
2139
  /**
2140
   * Sort a array by value, by a closure or by a property.
2141
   *
2142
   * - If the sorter is null, the array is sorted naturally.
2143
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2144
   *
2145
   * @param null       $sorter
2146
   * @param string|int $direction
2147
   * @param int        $strategy
2148
   *
2149
   * @return Arrayy (Immutable)
2150
   */
2151 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2152
  {
2153 1
    $array = (array)$this->array;
2154 1
    $direction = $this->getDirection($direction);
2155
2156
    // Transform all values into their results.
2157 1
    if ($sorter) {
2158 1
      $arrayy = new self($array);
2159
2160 1
      $that = $this;
2161 1
      $results = $arrayy->each(
2162
          function ($value) use ($sorter, $that) {
2163 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2164 1
          }
2165
      );
2166
2167 1
      $results = $results->getArray();
2168
    } else {
2169 1
      $results = $array;
2170
    }
2171
2172
    // Sort by the results and replace by original values
2173 1
    array_multisort($results, $direction, $strategy, $array);
2174
2175 1
    return static::create($array);
2176
  }
2177
2178
  /**
2179
   * sorting keys
2180
   *
2181
   * @param array $elements
2182
   * @param int   $direction
2183
   * @param int   $strategy
2184
   */
2185 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2186
  {
2187 18
    $direction = $this->getDirection($direction);
2188
2189
    switch ($direction) {
2190 18
      case 'desc':
2191 18
      case SORT_DESC:
2192 6
        krsort($elements, $strategy);
2193 6
        break;
2194 13
      case 'asc':
2195 13
      case SORT_ASC:
2196
      default:
2197 13
        ksort($elements, $strategy);
2198
    }
2199 18
  }
2200
2201
  /**
2202
   * @param array      &$elements
2203
   * @param int|string $direction
2204
   * @param int        $strategy
2205
   * @param bool       $keepKeys
2206
   */
2207 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2208
  {
2209 19
    $direction = $this->getDirection($direction);
2210
2211 19
    if (!$strategy) {
2212 19
      $strategy = SORT_REGULAR;
2213
    }
2214
2215
    switch ($direction) {
2216 19
      case 'desc':
2217 19
      case SORT_DESC:
2218 9
        if ($keepKeys) {
2219 5
          arsort($elements, $strategy);
2220
        } else {
2221 4
          rsort($elements, $strategy);
2222
        }
2223 9
        break;
2224 10
      case 'asc':
2225 10
      case SORT_ASC:
2226
      default:
2227 10
        if ($keepKeys) {
2228 4
          asort($elements, $strategy);
2229
        } else {
2230 6
          sort($elements, $strategy);
2231
        }
2232
    }
2233 19
  }
2234
2235
  /**
2236
   * Split an array in the given amount of pieces.
2237
   *
2238
   * @param int  $numberOfPieces
2239
   * @param bool $keepKeys
2240
   *
2241
   * @return Arrayy (Immutable)
2242
   */
2243 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2244
  {
2245 1
    if (count($this->array) === 0) {
2246 1
      $result = array();
2247
    } else {
2248 1
      $numberOfPieces = (int)$numberOfPieces;
2249 1
      $splitSize = ceil(count($this->array) / $numberOfPieces);
2250 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
2251
    }
2252
2253 1
    return static::create($result);
2254
  }
2255
2256
  /**
2257
   * alias: for "Arrayy->getArray()"
2258
   */
2259 153
  public function toArray()
2260
  {
2261 153
    return $this->getArray();
2262
  }
2263
2264
  /**
2265
   * Convert the current array to JSON.
2266
   *
2267
   * @param null $options e.g. JSON_PRETTY_PRINT
2268
   *
2269
   * @return string
2270
   */
2271 5
  public function toJson($options = null)
2272
  {
2273 5
    return UTF8::json_encode($this->array, $options);
2274
  }
2275
2276
  /**
2277
   * Implodes array to a string with specified separator.
2278
   *
2279
   * @param string $separator The element's separator
2280
   *
2281
   * @return string The string representation of array, separated by ","
2282
   */
2283 15
  public function toString($separator = ',')
2284
  {
2285 15
    return $this->implode($separator);
2286
  }
2287
2288
  /**
2289
   * Return a duplicate free copy of the current array.
2290
   *
2291
   * @return Arrayy (Mutable)
2292
   */
2293 7
  public function unique()
2294
  {
2295 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...
2296 7
        $this->array,
2297 7
        function ($resultArray, $value) {
2298 6
          if (in_array($value, $resultArray, true) === false) {
2299 6
            $resultArray[] = $value;
2300
          }
2301
2302 6
          return $resultArray;
2303 7
        },
2304 7
        array()
2305
    );
2306
2307 7
    return $this;
2308
  }
2309
2310
  /**
2311
   * Prepends one or more values to the beginning of array at once.
2312
   *
2313
   * @return self (Mutable) Return this Arrayy object, with prepended elements to the beginning of array.
2314
   */
2315 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...
2316
  {
2317 4
    if (func_num_args()) {
2318 4
      $args = array_merge(array(&$this->array), func_get_args());
2319 4
      call_user_func_array('array_unshift', $args);
2320
    }
2321
2322 4
    return $this;
2323
  }
2324
2325
  /**
2326
   * Get all values from a array.
2327
   *
2328
   * @return Arrayy (Immutable)
2329
   */
2330 1
  public function values()
2331
  {
2332 1
    $array = array_values((array)$this->array);
2333
2334 1
    return static::create($array);
2335
  }
2336
2337
  /**
2338
   * Apply the given function to every element in the array, discarding the results.
2339
   *
2340
   * @param callable $callable
2341
   * @param bool     $recursive Whether array will be walked recursively or no
2342
   *
2343
   * @return self (Mutable) Return this Arrayy object, with modified elements
2344
   */
2345 9
  public function walk($callable, $recursive = false)
2346
  {
2347 9
    if (true === $recursive) {
2348 4
      array_walk_recursive($this->array, $callable);
2349
    } else {
2350 5
      array_walk($this->array, $callable);
2351
    }
2352
2353 9
    return $this;
2354
  }
2355
2356
2357
}
2358