Completed
Push — master ( 025a38...f7e4e4 )
by Lars
04:57
created

Arrayy   D

Complexity

Total Complexity 401

Size/Duplication

Total Lines 3640
Duplicated Lines 6.87 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 91.15%

Importance

Changes 0
Metric Value
dl 250
loc 3640
ccs 958
cts 1051
cp 0.9115
rs 4.4102
c 0
b 0
f 0
wmc 401
lcom 1
cbo 2

182 Methods

Rating   Name   Duplication   Size   Complexity  
B appendToEachValue() 17 17 5
A containsKeys() 0 8 2
A containsKeysRecursive() 0 4 1
A containsValue() 0 4 1
A countValues() 0 4 1
A getKeys() 0 4 1
A getRandomKey() 0 4 1
A krsort() 0 6 1
A reindex() 0 6 1
A replaceAllValues() 0 6 1
A sizeRecursive() 0 4 1
A size() 0 4 1
A __construct() 0 7 1
A __get() 0 10 2
A __invoke() 0 12 3
A __isset() 0 4 1
A __set() 0 4 1
A __toString() 0 4 1
A __unset() 0 4 1
A add() 0 4 1
A append() 0 10 2
A asort() 0 6 1
A count() 0 4 1
A exchangeArray() 0 6 1
A getArrayCopy() 0 4 1
A getIterator() 0 6 1
A getIteratorClass() 0 4 1
A ksort() 0 6 1
A natcasesort() 0 6 1
A natsort() 0 6 1
C offsetExists() 0 44 7
A offsetGet() 0 4 2
A offsetSet() 0 8 2
B offsetUnset() 0 26 4
A serialize() 0 4 1
A setIteratorClass() 0 19 4
A uasort() 12 12 2
A uksort() 0 4 1
A unserialize() 0 6 1
A appendToEachKey() 15 15 4
B arrayToObject() 0 18 5
A arsort() 0 6 1
A at() 10 10 2
A average() 0 14 3
B callAtPath() 0 23 4
A changeKeyCase() 0 4 1
A changeSeparator() 0 6 1
A chunk() 0 6 1
A clean() 0 8 1
A clear() 0 6 1
A contains() 0 8 2
B in_array_recursive() 0 21 6
B containsCaseInsensitive() 0 26 2
A containsKey() 0 4 1
A containsValueRecursive() 0 4 1
A containsValues() 0 4 1
A create() 0 4 1
A createByReference() 0 8 1
A createFromJson() 0 6 1
A createFromObject() 0 10 2
A createFromObjectVars() 0 4 1
B createFromString() 0 26 4
A createWithRange() 0 4 1
A customSortKeys() 12 12 2
A customSortValues() 12 12 2
A diff() 0 6 1
C diffRecursive() 0 33 8
A diffReverse() 0 6 1
A divide() 0 9 1
A each() 10 10 2
A exists() 0 12 3
C fallbackForArray() 0 42 13
A filter() 0 10 2
A filterBy() 0 65 3
A find() 0 10 3
A findBy() 0 4 1
A first() 0 11 2
A firstsImmutable() 0 13 2
A firstsMutable() 0 11 2
A flip() 0 6 1
D get() 0 40 10
A getArray() 0 6 1
A getColumn() 0 6 1
B getDirection() 0 22 5
A getObject() 0 4 1
A getRandom() 0 4 1
A getRandomKeys() 0 4 1
A getRandomValue() 0 4 1
A getRandomValues() 0 4 1
C group() 0 34 7
A has() 0 7 1
A implodeKeys() 0 4 1
A implode() 0 4 1
B implode_recursive() 0 22 6
A indexBy() 0 12 3
A indexOf() 0 4 1
A initial() 0 6 1
A internalGetArray() 0 17 4
A internalRemove() 0 21 3
B internalSet() 0 28 5
A intersection() 0 4 1
A intersects() 0 4 1
A invoke() 0 16 3
A isAssoc() 0 14 4
A isEmpty() 0 4 1
A isEqual() 0 4 1
A isMultiArray() 0 4 1
A isNumeric() 0 14 4
A isSequential() 0 8 2
A jsonSerialize() 0 4 1
A keys() 0 18 4
C array_keys_recursive() 0 31 7
A last() 0 4 1
B lastsImmutable() 0 23 4
B lastsMutable() 0 23 4
A length() 0 4 1
A map() 0 6 1
A matches() 19 19 4
A matchesAny() 19 19 4
A max() 0 8 2
A mergeAppendKeepIndex() 10 10 2
A mergeAppendNewIndex() 10 10 2
A mergePrependKeepIndex() 10 10 2
A mergePrependNewIndex() 10 10 2
A min() 0 8 2
B moveElement() 0 27 5
A objectToArray() 0 12 3
A only() 0 6 1
A pad() 0 6 1
A pop() 0 4 1
A prepend() 0 11 2
A prependToEachKey() 16 16 4
B prependToEachValue() 17 17 5
A push() 9 9 2
A randomImmutable() 5 17 3
A randomKey() 0 10 2
A randomKeys() 0 18 3
A randomMutable() 6 17 3
A randomValue() 0 10 2
A randomValues() 0 4 1
A randomWeighted() 0 13 4
A reduce() 0 12 2
A reject() 12 12 3
A remove() 0 15 3
A removeFirst() 0 7 1
A removeLast() 0 7 1
B removeValue() 0 18 5
A repeat() 0 8 2
A replace() 0 6 1
A replaceAllKeys() 0 6 1
A replaceKeys() 0 7 1
A replaceOneValue() 0 11 2
A replaceValues() 0 10 1
A rest() 0 6 1
A reverse() 0 6 1
A rsort() 0 6 1
A searchIndex() 0 4 1
A searchValue() 0 21 4
A set() 0 6 1
A setAndGet() 0 9 2
A shift() 0 4 1
C shuffle() 0 33 7
A slice() 0 6 1
A sort() 0 6 1
A sortKeys() 0 6 1
A sortValueKeepIndex() 0 4 1
A sortValueNewIndex() 0 4 1
B sorter() 0 26 3
B sorterKeys() 0 17 5
C sorting() 0 29 8
A split() 0 13 2
A stripEmpty() 0 12 2
A swap() 0 8 1
A toArray() 0 4 1
A toJson() 0 4 1
A toString() 0 4 1
B unique() 5 24 3
B uniqueKeepIndex() 5 27 3
A uniqueNewIndex() 0 4 1
A unshift() 9 9 2
A values() 0 4 1
A walk() 0 10 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Arrayy often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Arrayy, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arrayy;
6
7
use voku\helper\UTF8;
8
9
/** @noinspection ClassReImplementsParentInterfaceInspection */
10
11
/**
12
 * Methods to manage arrays.
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \Countable
18
{
19
  /**
20
   * @var array
21
   */
22
  protected $array = [];
23
24
  /**
25
   * @var string
26
   */
27
  protected $iteratorClass;
28
29
  /**
30
   * @var string
31
   */
32
  protected $pathSeparator = '.';
33
34
  /** @noinspection MagicMethodsValidityInspection */
35
  /**
36
   * Initializes
37
   *
38
   * @param array  $array
39
   * @param string $iteratorClass
40
   */
41 861
  public function __construct($array = [], $iteratorClass = ArrayyIterator::class)
42
  {
43 861
    $array = $this->fallbackForArray($array);
44 859
    $this->array = $array;
45
46 859
    $this->setIteratorClass($iteratorClass);
47 859
  }
48
49
  /**
50
   * Get a value by key.
51
   *
52
   * @param mixed $key
53
   *
54
   * @return mixed <p>Get a Value from the current array.</p>
55
   */
56 2
  public function &__get($key)
57
  {
58 2
    $return = $this->get($key);
59
60 2
    if (\is_array($return)) {
61
      return static::create($return);
62
    }
63
64 2
    return $return;
65
  }
66
67
  /**
68
   * Call object as function.
69
   *
70
   * @param mixed $key
71
   *
72
   * @return mixed
73
   */
74 1
  public function __invoke($key = null)
75
  {
76 1
    if ($key !== null) {
77 1
      if (isset($this->array[$key])) {
78 1
        return $this->array[$key];
79
      }
80
81
      return false;
82
    }
83
84
    return (array)$this->array;
85
  }
86
87
  /**
88
   * Whether or not an element exists by key.
89
   *
90
   * @param mixed $key
91
   *
92
   * @return bool <p>True is the key/index exists, otherwise false.</p>
93
   */
94
  public function __isset($key)
95
  {
96
    return $this->offsetExists($key);
97
  }
98
99
  /**
100
   * Assigns a value to the specified element.
101
   *
102
   * @param mixed $key
103
   * @param mixed $value
104
   */
105 2
  public function __set($key, $value)
106
  {
107 2
    $this->internalSet($key, $value);
108 2
  }
109
110
  /**
111
   * magic to string
112
   *
113
   * @return string
114
   */
115 15
  public function __toString()
116
  {
117 15
    return $this->toString();
118
  }
119
120
  /**
121
   * Unset element by key.
122
   *
123
   * @param mixed $key
124
   */
125
  public function __unset($key)
126
  {
127
    $this->internalRemove($key);
128
  }
129
130
  /**
131
   * alias: for "Arrayy->append()"
132
   *
133
   * @see Arrayy::append()
134
   *
135
   * @param mixed $value
136
   *
137
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
138
   */
139 1
  public function add($value)
140
  {
141 1
    return $this->append($value);
142
  }
143
144
  /**
145
   * Append a (key) + value to the current array.
146
   *
147
   * @param mixed $value
148
   * @param mixed $key
149
   *
150
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
151
   */
152 9
  public function append($value, $key = null)
153
  {
154 9
    if ($key !== null) {
155
      $this->array[$key] = $value;
156
    } else {
157 9
      $this->array[] = $value;
158
    }
159
160 9
    return $this;
161
  }
162
163
  /**
164
   * Sort the entries by value.
165
   *
166
   * @param int $sort_flags [optional] <p>
167
   *                        You may modify the behavior of the sort using the optional
168
   *                        parameter sort_flags, for details
169
   *                        see sort.
170
   *                        </p>
171
   *
172
   * @return static <p>(Mutable) Return this Arrayy object.</p>
173
   */
174 4
  public function asort(int $sort_flags = 0)
175
  {
176 4
    \asort($this->array, $sort_flags);
177
178 4
    return $this;
179
  }
180
181
  /**
182
   * Count the values from the current array.
183
   *
184
   * alias: for "Arrayy->size()"
185
   *
186
   * @see Arrayy::size()
187
   *
188
   * @param int $mode
189
   *
190
   * @return int
191
   */
192 104
  public function count(int $mode = COUNT_NORMAL): int
193
  {
194 104
    return $this->size($mode);
195
  }
196
197
  /**
198
   * Exchange the array for another one.
199
   *
200
   * @param array|static $data
201
   *
202
   * @return array
203
   */
204 1
  public function exchangeArray($data): array
205
  {
206 1
    $this->array = $this->fallbackForArray($data);
207
208 1
    return $this->array;
209
  }
210
211
  /**
212
   * Creates a copy of the ArrayyObject.
213
   *
214
   * @return array
215
   */
216 1
  public function getArrayCopy(): array
217
  {
218 1
    return $this->array;
219
  }
220
221
  /**
222
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
223
   *
224
   * @return ArrayyIterator <p>An iterator for the values in the array.</p>
225
   */
226 20
  public function getIterator(): ArrayyIterator
227
  {
228 20
    $iterator = $this->getIteratorClass();
229
230 20
    return new $iterator($this->array);
231
  }
232
233
  /**
234
   * Gets the iterator classname for the ArrayObject.
235
   *
236
   * @return string
237
   */
238 20
  public function getIteratorClass(): string
239
  {
240 20
    return $this->iteratorClass;
241
  }
242
243
  /**
244
   * Sort the entries by key
245
   *
246
   * @param int $sort_flags [optional] <p>
247
   *                        You may modify the behavior of the sort using the optional
248
   *                        parameter sort_flags, for details
249
   *                        see sort.
250
   *                        </p>
251
   *
252
   * @return static <p>(Mutable) Return this Arrayy object.</p>
253
   */
254 4
  public function ksort(int $sort_flags = 0)
255
  {
256 4
    \ksort($this->array, $sort_flags);
257
258 4
    return $this;
259
  }
260
261
  /**
262
   * Sort an array using a case insensitive "natural order" algorithm
263
   *
264
   * @return static <p>(Mutable) Return this Arrayy object.</p>
265
   */
266
  public function natcasesort()
267
  {
268
    \natcasesort($this->array);
269
270
    return $this;
271
  }
272
273
  /**
274
   * Sort entries using a "natural order" algorithm
275
   *
276
   * @return static <p>(Mutable) Return this Arrayy object.</p>
277
   */
278 1
  public function natsort()
279
  {
280 1
    \natsort($this->array);
281
282 1
    return $this;
283
  }
284
285
  /**
286
   * Whether or not an offset exists.
287
   *
288
   * @param int|float|string $offset
289
   *
290
   * @return bool
291
   */
292 40
  public function offsetExists($offset): bool
293
  {
294 40
    if ($this->isEmpty()) {
295 4
      return false;
296
    }
297
298
    // php cast "bool"-index into "int"-index
299 36
    if ((bool)$offset === $offset) {
300 1
      $offset = (int)$offset;
301
    }
302
303 36
    $tmpReturn = \array_key_exists($offset, $this->array);
304
305
    if (
306 36
        $tmpReturn === true
307
        ||
308
        (
309 12
            $tmpReturn === false
310
            &&
311 36
            \strpos((string)$offset, $this->pathSeparator) === false
312
        )
313
    ) {
314 34
      return $tmpReturn;
315
    }
316
317 3
    $offsetExists = false;
318
319 3
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
320
321 3
      $offsetExists = false;
322 3
      $explodedPath = \explode($this->pathSeparator, (string)$offset);
323 3
      $lastOffset = \array_pop($explodedPath);
324 3
      $containerPath = \implode($this->pathSeparator, $explodedPath);
325
326 3
      $this->callAtPath(
327 3
          $containerPath,
328 3
          function ($container) use ($lastOffset, &$offsetExists) {
0 ignored issues
show
Documentation introduced by
function ($container) us...tOffset, $container); } is of type object<Closure>, but the function expects a object<callable>.

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...
329 3
            $offsetExists = \array_key_exists($lastOffset, $container);
330 3
          }
331
      );
332
    }
333
334 3
    return $offsetExists;
335
  }
336
337
  /**
338
   * Returns the value at specified offset.
339
   *
340
   * @param int|float|string $offset
341
   *
342
   * @return mixed <p>Will return null if the offset did not exists.</p>
343
   */
344 26
  public function offsetGet($offset)
345
  {
346 26
    return $this->offsetExists($offset) ? $this->get($offset) : null;
347
  }
348
349
  /**
350
   * Assigns a value to the specified offset.
351
   *
352
   * @param int|float|string $offset
353
   * @param mixed            $value
354
   */
355 17
  public function offsetSet($offset, $value)
356
  {
357 17
    if ($offset === null) {
358 4
      $this->array[] = $value;
359
    } else {
360 13
      $this->internalSet($offset, $value);
361
    }
362 17
  }
363
364
  /**
365
   * Unset an offset.
366
   *
367
   * @param int|float|string $offset
368
   */
369 7
  public function offsetUnset($offset)
370
  {
371 7
    if ($this->isEmpty()) {
372 1
      return;
373
    }
374
375 6
    if (\array_key_exists($offset, $this->array)) {
376 4
      unset($this->array[$offset]);
377
378 4
      return;
379
    }
380
381 3
    if (\strpos((string)$offset, $this->pathSeparator) !== false) {
382
383 2
      $path = \explode($this->pathSeparator, (string)$offset);
384 2
      $pathToUnset = \array_pop($path);
385
386 2
      $this->callAtPath(
387 2
          \implode($this->pathSeparator, $path),
388 2
          function (&$offset) use ($pathToUnset) {
0 ignored issues
show
Documentation introduced by
function (&$offset) use(...ffset[$pathToUnset]); } is of type object<Closure>, but the function expects a object<callable>.

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...
389 2
            unset($offset[$pathToUnset]);
390 2
          }
391
      );
392
393
    }
394 3
  }
395
396
  /**
397
   * Serialize the current "Arrayy"-object.
398
   *
399
   * @return string
400
   */
401 1
  public function serialize()
402
  {
403 1
    return parent::serialize();
404
  }
405
406
  /**
407
   * Sets the iterator classname for the current "Arrayy"-object.
408
   *
409
   * @param string $class
410
   *
411
   * @return void
412
   *
413
   * @throws \InvalidArgumentException
414
   */
415 859
  public function setIteratorClass($class)
416
  {
417 859
    if (\class_exists($class)) {
418 859
      $this->iteratorClass = $class;
419
420 859
      return;
421
    }
422
423
    if (\strpos($class, '\\') === 0) {
424
      $class = '\\' . $class;
425
      if (\class_exists($class)) {
426
        $this->iteratorClass = $class;
427
428
        return;
429
      }
430
    }
431
432
    throw new \InvalidArgumentException('The iterator class does not exist: ' . $class);
433
  }
434
435
  /**
436
   * Sort the entries with a user-defined comparison function and maintain key association.
437
   *
438
   * @param \callable $function
439
   *
440
   * @return static <p>(Mutable) Return this Arrayy object.</p>
441
   *
442
   * @throws \InvalidArgumentException
443
   */
444 View Code Duplication
  public function uasort($function)
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...
445
  {
446
    if (!\is_callable($function)) {
447
      throw new \InvalidArgumentException(
448
          'Passed function must be callable'
449
      );
450
    }
451
452
    \uasort($this->array, $function);
453
454
    return $this;
455
  }
456
457
  /**
458
   * Sort the entries by keys using a user-defined comparison function.
459
   *
460
   * @param \callable $function
461
   *
462
   * @return static <p>(Mutable) Return this Arrayy object.</p>
463
   *
464
   * @throws \InvalidArgumentException
465
   */
466 5
  public function uksort($function)
467
  {
468 5
    return $this->customSortKeys($function);
469
  }
470
471
  /**
472
   * Unserialize an string and return this object.
473
   *
474
   * @param string $string
475
   *
476
   * @return static <p>(Mutable)</p>
477
   */
478 1
  public function unserialize($string)
479
  {
480 1
    parent::unserialize($string);
481
482 1
    return $this;
483
  }
484
485
  /**
486
   * Add a suffix to each key.
487
   *
488
   * @param mixed $prefix
489
   *
490
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed keys.</p>
491
   */
492 10 View Code Duplication
  public function appendToEachKey($prefix)
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...
493
  {
494 10
    $result = [];
495 10
    foreach ($this->array as $key => $item) {
496 9
      if ($item instanceof self) {
497
        $result[$prefix . $key] = $item->appendToEachKey($prefix);
498 9
      } elseif (\is_array($item)) {
499
        $result[$prefix . $key] = self::create($item)->appendToEachKey($prefix)->toArray();
500
      } else {
501 9
        $result[$prefix . $key] = $item;
502
      }
503
    }
504
505 10
    return self::create($result);
506
  }
507
508
  /**
509
   * Add a prefix to each value.
510
   *
511
   * @param mixed $prefix
512
   *
513
   * @return static <p>(Immutable) Return an Arrayy object, with the prefixed values.</p>
514
   */
515 10 View Code Duplication
  public function appendToEachValue($prefix)
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 10
    $result = [];
518 10
    foreach ($this->array as $key => $item) {
519 9
      if ($item instanceof self) {
520
        $result[$key] = $item->appendToEachValue($prefix);
521 9
      } elseif (\is_array($item)) {
522
        $result[$key] = self::create($item)->appendToEachValue($prefix)->toArray();
523 9
      } elseif (\is_object($item)) {
524 1
        $result[$key] = $item;
525
      } else {
526 9
        $result[$key] = $prefix . $item;
527
      }
528
    }
529
530 10
    return self::create($result);
531
  }
532
533
  /**
534
   * Convert an array into a object.
535
   *
536
   * @param array $array PHP array
537
   *
538
   * @return \stdClass (object)
539
   */
540 4
  protected static function arrayToObject(array $array = []): \stdClass
541
  {
542 4
    $object = new \stdClass();
543
544 4
    if (!\is_array($array) || \count($array) <= 0) {
545 1
      return $object;
546
    }
547
548 3
    foreach ($array as $name => $value) {
549 3
      if (\is_array($value)) {
550 1
        $object->{$name} = self::arrayToObject($value);
551 1
        continue;
552
      }
553 3
      $object->{$name} = $value;
554
    }
555
556 3
    return $object;
557
  }
558
559
  /**
560
   * Sort an array in reverse order and maintain index association.
561
   *
562
   * @return static <p>(Mutable) Return this Arrayy object.</p>
563
   */
564 4
  public function arsort()
565
  {
566 4
    \arsort($this->array);
567
568 4
    return $this;
569
  }
570
571
  /**
572
   * Iterate over the current array and execute a callback for each loop.
573
   *
574
   * @param \Closure $closure
575
   *
576
   * @return static <p>(Immutable)</p>
577
   */
578 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...
579
  {
580 2
    $array = $this->array;
581
582 2
    foreach ($array as $key => $value) {
583 2
      $closure($value, $key);
584
    }
585
586 2
    return static::create($array);
587
  }
588
589
  /**
590
   * Returns the average value of the current array.
591
   *
592
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
593
   *
594
   * @return int|double <p>The average value.</p>
595
   */
596 10
  public function average($decimals = 0)
597
  {
598 10
    $count = $this->count();
599
600 10
    if (!$count) {
601 2
      return 0;
602
    }
603
604 8
    if (!\is_int($decimals)) {
605 3
      $decimals = 0;
606
    }
607
608 8
    return \round(\array_sum($this->array) / $count, $decimals);
609
  }
610
611
  /**
612
   * @param mixed      $path
613
   * @param \callable  $callable
614
   * @param null|array $currentOffset
615
   */
616 4
  protected function callAtPath($path, $callable, &$currentOffset = null)
617
  {
618 4
    if ($currentOffset === null) {
619 4
      $currentOffset = &$this->array;
620
    }
621
622 4
    $explodedPath = \explode($this->pathSeparator, $path);
623 4
    $nextPath = \array_shift($explodedPath);
624
625 4
    if (!isset($currentOffset[$nextPath])) {
626
      return;
627
    }
628
629 4
    if (!empty($explodedPath)) {
630 1
      $this->callAtPath(
631 1
          \implode($this->pathSeparator, $explodedPath),
632 1
          $callable,
633 1
          $currentOffset[$nextPath]
634
      );
635
    } else {
636 4
      $callable($currentOffset[$nextPath]);
637
    }
638 4
  }
639
640
  /**
641
   * Changes all keys in an array.
642
   *
643
   * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
644
   *                  or <strong>CASE_LOWER</strong> (default)</p>
645
   *
646
   * @return static <p>(Immutable)</p>
647
   */
648 1
  public function changeKeyCase(int $case = CASE_LOWER)
649
  {
650 1
    return static::create(UTF8::array_change_key_case($this->array, $case));
651
  }
652
653
  /**
654
   * Change the path separator of the array wrapper.
655
   *
656
   * By default, the separator is: "."
657
   *
658
   * @param string $separator <p>Separator to set.</p>
659
   *
660
   * @return static <p>Mutable</p>
661
   */
662 1
  public function changeSeparator($separator)
663
  {
664 1
    $this->pathSeparator = $separator;
665
666 1
    return $this;
667
  }
668
669
  /**
670
   * Create a chunked version of the current array.
671
   *
672
   * @param int  $size         <p>Size of each chunk.</p>
673
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
674
   *
675
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
676
   */
677 4
  public function chunk($size, $preserveKeys = false)
678
  {
679 4
    $result = \array_chunk($this->array, $size, $preserveKeys);
680
681 4
    return static::create($result);
682
  }
683
684
  /**
685
   * Clean all falsy values from the current array.
686
   *
687
   * @return static <p>(Immutable)</p>
688
   */
689 8
  public function clean()
690
  {
691 8
    return $this->filter(
692 8
        function ($value) {
693 7
          return (bool)$value;
694 8
        }
695
    );
696
  }
697
698
  /**
699
   * WARNING!!! -> Clear the current array.
700
   *
701
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
702
   */
703 4
  public function clear()
704
  {
705 4
    $this->array = [];
706
707 4
    return $this;
708
  }
709
710
  /**
711
   * Check if an item is in the current array.
712
   *
713
   * @param string|int|float $value
714
   * @param bool             $recursive
715
   * @param bool             $strict
716
   *
717
   * @return bool
718
   */
719 22
  public function contains($value, $recursive = false, $strict = true): bool
720
  {
721 22
    if ($recursive === true) {
722 18
      return $this->in_array_recursive($value, $this->array, $strict);
723
    }
724
725 13
    return \in_array($value, $this->array, $strict);
726
  }
727
728
  /**
729
   * @param mixed $needle   <p>
730
   *                        The searched value.
731
   *                        </p>
732
   *                        <p>
733
   *                        If needle is a string, the comparison is done
734
   *                        in a case-sensitive manner.
735
   *                        </p>
736
   * @param array $haystack <p>
737
   *                        The array.
738
   *                        </p>
739
   * @param bool  $strict   [optional] <p>
740
   *                        If the third parameter strict is set to true
741
   *                        then the in_array function will also check the
742
   *                        types of the
743
   *                        needle in the haystack.
744
   *                        </p>
745
   *
746
   * @return bool true if needle is found in the array, false otherwise.
747
   */
748 44
  protected function in_array_recursive($needle, array $haystack = null, $strict = true): bool
749
  {
750 44
    if ($haystack === null) {
751
      $haystack = $this->array;
752
    }
753
754 44
    foreach ($haystack as $item) {
755
756 36
      if (\is_array($item) === true) {
757 8
        $returnTmp = $this->in_array_recursive($needle, $item, $strict);
758
      } else {
759 36
        $returnTmp = ($strict === true ? $item === $needle : $item == $needle);
760
      }
761
762 36
      if ($returnTmp === true) {
763 36
        return true;
764
      }
765
    }
766
767 18
    return false;
768
  }
769
770
  /**
771
   * Check if an (case-insensitive) string is in the current array.
772
   *
773
   * @param string $value
774
   * @param bool   $recursive
775
   *
776
   * @return bool
777
   */
778 26
  public function containsCaseInsensitive($value, $recursive = false): bool
779
  {
780 26
    if ($recursive === true) {
781 26
      return $this->in_array_recursive(
782 26
          UTF8::strtoupper($value),
783 26
          $this->walk(
784 26
              function (&$val) {
0 ignored issues
show
Documentation introduced by
function (&$val) { $...F8::strtoupper($val); } is of type object<Closure>, but the function expects a object<callable>.

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...
785 22
                $val = UTF8::strtoupper($val);
786 26
              },
787 26
              true
788 26
          )->getArray(),
789 26
          true
790
      );
791
    }
792
793 13
    return \in_array(
794 13
        UTF8::strtoupper($value),
795 13
        $this->walk(
796 13
            function (&$val) {
0 ignored issues
show
Documentation introduced by
function (&$val) { $...F8::strtoupper($val); } is of type object<Closure>, but the function expects a object<callable>.

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...
797 11
              $val = UTF8::strtoupper($val);
798 13
            },
799 13
            false
800 13
        )->getArray(),
801 13
        true
802
    );
803
  }
804
805
  /**
806
   * Check if the given key/index exists in the array.
807
   *
808
   * @param string|int|float $key <p>key/index to search for</p>
809
   *
810
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
811
   */
812 4
  public function containsKey($key): bool
813
  {
814 4
    return $this->offsetExists($key);
815
  }
816
817
  /**
818
   * Check if all given needles are present in the array as key/index.
819
   *
820
   * @param array $needles <p>The keys you are searching for.</p>
821
   * @param bool  $recursive
822
   *
823
   * @return bool <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
824
   */
825 2
  public function containsKeys(array $needles, $recursive = false): bool
826
  {
827 2
    if ($recursive === true) {
828 1
      return \count(\array_intersect($needles, $this->keys(true)->getArray())) === \count($needles, COUNT_RECURSIVE);
829
    }
830
831 1
    return \count(\array_intersect($needles, $this->keys()->getArray())) === \count($needles);
832
  }
833
834
  /**
835
   * Check if all given needles are present in the array as key/index.
836
   *
837
   * @param array $needles <p>The keys you are searching for.</p>
838
   *
839
   * @return bool <p>Returns true if all the given keys/indexes exists in the array, false otherwise.</p>
840
   */
841 1
  public function containsKeysRecursive(array $needles): bool
842
  {
843 1
    return $this->containsKeys($needles, true);
844
  }
845
846
  /**
847
   * alias: for "Arrayy->contains()"
848
   *
849
   * @see Arrayy::contains()
850
   *
851
   * @param string|int|float $value
852
   *
853
   * @return bool
854
   */
855 9
  public function containsValue($value): bool
856
  {
857 9
    return $this->contains($value);
858
  }
859
860
  /**
861
   * alias: for "Arrayy->contains($value, true)"
862
   *
863
   * @see Arrayy::contains()
864
   *
865
   * @param string|int|float $value
866
   *
867
   * @return bool
868
   */
869 18
  public function containsValueRecursive($value): bool
870
  {
871 18
    return $this->contains($value, true);
872
  }
873
874
  /**
875
   * Check if all given needles are present in the array.
876
   *
877
   * @param array $needles
878
   *
879
   * @return bool <p>Returns true if all the given values exists in the array, false otherwise.</p>
880
   */
881 1
  public function containsValues(array $needles): bool
882
  {
883 1
    return \count(\array_intersect($needles, $this->array)) === \count($needles);
884
  }
885
886
  /**
887
   * Counts all the values of an array
888
   *
889
   * @link http://php.net/manual/en/function.array-count-values.php
890
   *
891
   * @return static <p>
892
   *                (Immutable)
893
   *                An associative Arrayy-object of values from input as
894
   *                keys and their count as value.
895
   *                </p>
896
   */
897 1
  public function countValues()
898
  {
899 1
    return new static(\array_count_values($this->array));
900
  }
901
902
  /**
903
   * Creates an Arrayy object.
904
   *
905
   * @param array $array
906
   *
907
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
908
   */
909 530
  public static function create($array = [])
910
  {
911 530
    return new static($array);
912
  }
913
914
  /**
915
   * WARNING: Creates an Arrayy object by reference.
916
   *
917
   * @param array $array
918
   *
919
   * @return static <p>(Mutable) Return this Arrayy object.</p>
920
   */
921 1
  public function createByReference(&$array = [])
922
  {
923 1
    $array = $this->fallbackForArray($array);
924
925 1
    $this->array = &$array;
926
927 1
    return $this;
928
  }
929
930
  /**
931
   * Create an new Arrayy object via JSON.
932
   *
933
   * @param string $json
934
   *
935
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
936
   */
937 5
  public static function createFromJson(string $json)
938
  {
939 5
    $array = UTF8::json_decode($json, true);
940
941 5
    return static::create($array);
942
  }
943
944
  /**
945
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
946
   *
947
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
948
   *
949
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
950
   */
951 4
  public static function createFromObject(\ArrayAccess $object)
952
  {
953 4
    $array = new static();
954 4
    foreach ($object as $key => $value) {
955
      /** @noinspection OffsetOperationsInspection */
956 3
      $array[$key] = $value;
957
    }
958
959 4
    return $array;
960
  }
961
962
  /**
963
   * Create an new instance filled with values from an object.
964
   *
965
   * @param object $object
966
   *
967
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
968
   */
969 5
  public static function createFromObjectVars($object)
970
  {
971 5
    return new static(self::objectToArray($object));
972
  }
973
974
  /**
975
   * Create an new Arrayy object via string.
976
   *
977
   * @param string      $str       <p>The input string.</p>
978
   * @param string|null $delimiter <p>The boundary string.</p>
979
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
980
   *                               used.</p>
981
   *
982
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
983
   */
984 8
  public static function createFromString(string $str, string $delimiter = null, string $regEx = null)
985
  {
986 8
    if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type null|string 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...
987 1
      \preg_match_all($regEx, $str, $array);
988
989 1
      if (!empty($array)) {
990 1
        $array = $array[0];
991
      }
992
993
    } else {
994 7
      $array = \explode($delimiter, $str);
995
    }
996
997
    // trim all string in the array
998 8
    \array_walk(
999
        $array,
1000 8
        function (&$val) {
1001
          /** @noinspection ReferenceMismatchInspection */
1002 8
          if (\is_string($val)) {
1003 8
            $val = \trim($val);
1004
          }
1005 8
        }
1006
    );
1007
1008 8
    return static::create($array);
1009
  }
1010
1011
  /**
1012
   * Create an new instance containing a range of elements.
1013
   *
1014
   * @param mixed $low  <p>First value of the sequence.</p>
1015
   * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
1016
   * @param int   $step <p>Used as the increment between elements in the sequence.</p>
1017
   *
1018
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
1019
   */
1020 1
  public static function createWithRange($low, $high, int $step = 1)
1021
  {
1022 1
    return static::create(\range($low, $high, $step));
1023
  }
1024
1025
  /**
1026
   * Custom sort by index via "uksort".
1027
   *
1028
   * @link http://php.net/manual/en/function.uksort.php
1029
   *
1030
   * @param \callable $function
1031
   *
1032
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1033
   *
1034
   * @throws \InvalidArgumentException
1035
   */
1036 5 View Code Duplication
  public function customSortKeys($function)
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...
1037
  {
1038 5
    if (!\is_callable($function)) {
1039
      throw new \InvalidArgumentException(
1040
          'Passed function must be callable'
1041
      );
1042
    }
1043
1044 5
    \uksort($this->array, $function);
1045
1046 5
    return $this;
1047
  }
1048
1049
  /**
1050
   * Custom sort by value via "usort".
1051
   *
1052
   * @link http://php.net/manual/en/function.usort.php
1053
   *
1054
   * @param \callable $function
1055
   *
1056
   * @return static <p>(Mutable) Return this Arrayy object.</p>
1057
   *
1058
   * @throws \InvalidArgumentException
1059
   */
1060 5 View Code Duplication
  public function customSortValues($function)
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...
1061
  {
1062 5
    if (!\is_callable($function)) {
1063
      throw new \InvalidArgumentException(
1064
          'Passed function must be callable'
1065
      );
1066
    }
1067
1068 5
    \usort($this->array, $function);
1069
1070 5
    return $this;
1071
  }
1072
1073
  /**
1074
   * Return values that are only in the current array.
1075
   *
1076
   * @param array $array
1077
   *
1078
   * @return static <p>(Immutable)</p>
1079
   */
1080 12
  public function diff(array $array = [])
1081
  {
1082 12
    $result = \array_diff($this->array, $array);
1083
1084 12
    return static::create($result);
1085
  }
1086
1087
  /**
1088
   * Return values that are only in the current multi-dimensional array.
1089
   *
1090
   * @param array      $array
1091
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
1092
   *
1093
   * @return static <p>(Immutable)</p>
1094
   */
1095 1
  public function diffRecursive(array $array = [], $helperVariableForRecursion = null)
1096
  {
1097 1
    $result = [];
1098
1099
    if (
1100 1
        $helperVariableForRecursion !== null
1101
        &&
1102 1
        \is_array($helperVariableForRecursion)
1103
    ) {
1104 1
      $arrayForTheLoop = $helperVariableForRecursion;
1105
    } else {
1106 1
      $arrayForTheLoop = $this->array;
1107
    }
1108
1109 1
    foreach ($arrayForTheLoop as $key => $value) {
1110 1
      if (\array_key_exists($key, $array)) {
1111 1
        if (\is_array($value)) {
1112 1
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
1113 1
          if (!empty($recursiveDiff)) {
1114 1
            $result[$key] = $recursiveDiff;
1115
          }
1116
        } else {
1117 1
          if ($value != $array[$key]) {
1118 1
            $result[$key] = $value;
1119
          }
1120
        }
1121
      } else {
1122 1
        $result[$key] = $value;
1123
      }
1124
    }
1125
1126 1
    return static::create($result);
1127
  }
1128
1129
  /**
1130
   * Return values that are only in the new $array.
1131
   *
1132
   * @param array $array
1133
   *
1134
   * @return static <p>(Immutable)</p>
1135
   */
1136 8
  public function diffReverse(array $array = [])
1137
  {
1138 8
    $result = \array_diff($array, $this->array);
1139
1140 8
    return static::create($result);
1141
  }
1142
1143
  /**
1144
   * Divide an array into two arrays. One with keys and the other with values.
1145
   *
1146
   * @return static <p>(Immutable)</p>
1147
   */
1148 1
  public function divide()
1149
  {
1150 1
    return static::create(
1151
        [
1152 1
            $this->keys(),
1153 1
            $this->values(),
1154
        ]
1155
    );
1156
  }
1157
1158
  /**
1159
   * Iterate over the current array and modify the array's value.
1160
   *
1161
   * @param \Closure $closure
1162
   *
1163
   * @return static <p>(Immutable)</p>
1164
   */
1165 4 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...
1166
  {
1167 4
    $array = $this->array;
1168
1169 4
    foreach ($array as $key => $value) {
1170 4
      $array[$key] = $closure($value, $key);
1171
    }
1172
1173 4
    return static::create($array);
1174
  }
1175
1176
  /**
1177
   * Check if a value is in the current array using a closure.
1178
   *
1179
   * @param \Closure $closure
1180
   *
1181
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
1182
   */
1183 4
  public function exists(\Closure $closure): bool
1184
  {
1185 4
    $isExists = false;
1186 4
    foreach ($this->array as $key => $value) {
1187 3
      if ($closure($value, $key)) {
1188 1
        $isExists = true;
1189 3
        break;
1190
      }
1191
    }
1192
1193 4
    return $isExists;
1194
  }
1195
1196
  /**
1197
   * create a fallback for array
1198
   *
1199
   * 1. use the current array, if it's a array
1200
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
1201
   * 3. fallback to empty array, if there is nothing
1202
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
1203
   * 5. call "__toArray()" on object, if the method exists
1204
   * 6. cast a string or object with "__toString()" into an array
1205
   * 7. throw a "InvalidArgumentException"-Exception
1206
   *
1207
   * @param $array
1208
   *
1209
   * @return array
1210
   *
1211
   * @throws \InvalidArgumentException
1212
   */
1213 861
  protected function fallbackForArray(&$array): array
1214
  {
1215 861
    if (\is_array($array)) {
1216 858
      return $array;
1217
    }
1218
1219 11
    if ($array instanceof self) {
1220 1
      return $array->getArray();
1221
    }
1222
1223 10
    if (!$array) {
1224 6
      return [];
1225
    }
1226
1227 9
    $isObject = \is_object($array);
1228
1229 9
    if ($isObject && $array instanceof \ArrayAccess) {
1230
      /** @noinspection ReferenceMismatchInspection */
1231
      return static::createFromObject($array)->getArray();
1232
    }
1233
1234 9
    if ($isObject && $array instanceof \ArrayObject) {
1235
      return $array->getArrayCopy();
1236
    }
1237
1238 9
    if ($isObject && \method_exists($array, '__toArray')) {
1239
      return (array)$array->__toArray();
1240
    }
1241
1242
    /** @noinspection ReferenceMismatchInspection */
1243
    if (
1244 9
        \is_string($array)
1245
        ||
1246 9
        ($isObject && \method_exists($array, '__toString'))
1247
    ) {
1248 7
      return [(string)$array];
1249
    }
1250
1251 2
    throw new \InvalidArgumentException(
1252 2
        'Passed value should be a array'
1253
    );
1254
  }
1255
1256
  /**
1257
   * Find all items in an array that pass the truth test.
1258
   *
1259
   * @param \Closure|null $closure [optional] <p>
1260
   *                               The callback function to use
1261
   *                               </p>
1262
   *                               <p>
1263
   *                               If no callback is supplied, all entries of
1264
   *                               input equal to false (see
1265
   *                               converting to
1266
   *                               boolean) will be removed.
1267
   *                               </p>
1268
   *
1269
   *  * @param int $flag [optional] <p>
1270
   *                               Flag determining what arguments are sent to <i>callback</i>:
1271
   *                               </p><ul>
1272
   *                               <li>
1273
   *                               <b>ARRAY_FILTER_USE_KEY</b> [1] - pass key as the only argument
1274
   *                               to <i>callback</i> instead of the value</span>
1275
   *                               </li>
1276
   *                               <li>
1277
   *                               <b>ARRAY_FILTER_USE_BOTH</b> [2] - pass both value and key as
1278
   *                               arguments to <i>callback</i> instead of the value</span>
1279
   *                               </li>
1280
   *                               </ul>
1281
   *
1282
   * @return static <p>(Immutable)</p>
1283
   */
1284 9
  public function filter($closure = null, int $flag = 0)
1285
  {
1286 9
    if (!$closure) {
1287 1
      return $this->clean();
1288
    }
1289
1290 9
    $array = \array_filter($this->array, $closure, $flag);
1291
1292 9
    return static::create($array);
1293
  }
1294
1295
  /**
1296
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
1297
   * within that.
1298
   *
1299
   * @param string          $property
1300
   * @param string|string[] $value
1301
   * @param string          $comparisonOp
1302
   *                            <p>
1303
   *                            'eq' (equals),<br />
1304
   *                            'gt' (greater),<br />
1305
   *                            'gte' || 'ge' (greater or equals),<br />
1306
   *                            'lt' (less),<br />
1307
   *                            'lte' || 'le' (less or equals),<br />
1308
   *                            'ne' (not equals),<br />
1309
   *                            'contains',<br />
1310
   *                            'notContains',<br />
1311
   *                            'newer' (via strtotime),<br />
1312
   *                            'older' (via strtotime),<br />
1313
   *                            </p>
1314
   *
1315
   * @return static <p>(Immutable)</p>
1316
   */
1317 1
  public function filterBy(string $property, $value, string $comparisonOp = null)
1318
  {
1319 1
    if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type null|string 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...
1320 1
      $comparisonOp = \is_array($value) ? 'contains' : 'eq';
1321
    }
1322
1323
    $ops = [
1324 1
        'eq'          => function ($item, $prop, $value) {
1325 1
          return $item[$prop] === $value;
1326 1
        },
1327 1
        'gt'          => function ($item, $prop, $value) {
1328
          return $item[$prop] > $value;
1329 1
        },
1330 1
        'ge'          => function ($item, $prop, $value) {
1331
          return $item[$prop] >= $value;
1332 1
        },
1333 1
        'gte'         => function ($item, $prop, $value) {
1334
          return $item[$prop] >= $value;
1335 1
        },
1336 1
        'lt'          => function ($item, $prop, $value) {
1337 1
          return $item[$prop] < $value;
1338 1
        },
1339 1
        'le'          => function ($item, $prop, $value) {
1340
          return $item[$prop] <= $value;
1341 1
        },
1342 1
        'lte'         => function ($item, $prop, $value) {
1343
          return $item[$prop] <= $value;
1344 1
        },
1345 1
        'ne'          => function ($item, $prop, $value) {
1346
          return $item[$prop] !== $value;
1347 1
        },
1348 1
        'contains'    => function ($item, $prop, $value) {
1349 1
          return \in_array($item[$prop], (array)$value, true);
1350 1
        },
1351 1
        'notContains' => function ($item, $prop, $value) {
1352
          return !\in_array($item[$prop], (array)$value, true);
1353 1
        },
1354 1
        'newer'       => function ($item, $prop, $value) {
1355
          return \strtotime($item[$prop]) > \strtotime($value);
1356 1
        },
1357 1
        'older'       => function ($item, $prop, $value) {
1358
          return \strtotime($item[$prop]) < \strtotime($value);
1359 1
        },
1360
    ];
1361
1362 1
    $result = \array_values(
1363 1
        \array_filter(
1364 1
            (array)$this->array,
1365 1
            function ($item) use (
1366 1
                $property,
1367 1
                $value,
1368 1
                $ops,
1369 1
                $comparisonOp
1370
            ) {
1371 1
              $item = (array)$item;
1372 1
              $itemArrayy = new Arrayy($item);
1373 1
              $item[$property] = $itemArrayy->get($property, []);
1374
1375 1
              return $ops[$comparisonOp]($item, $property, $value);
1376 1
            }
1377
        )
1378
    );
1379
1380 1
    return static::create($result);
1381
  }
1382
1383
  /**
1384
   * Find the first item in an array that passes the truth test,
1385
   *  otherwise return false
1386
   *
1387
   * @param \Closure $closure
1388
   *
1389
   * @return mixed|false <p>Return false if we did not find the value.</p>
1390
   */
1391 8
  public function find(\Closure $closure)
1392
  {
1393 8
    foreach ($this->array as $key => $value) {
1394 6
      if ($closure($value, $key)) {
1395 6
        return $value;
1396
      }
1397
    }
1398
1399 3
    return false;
1400
  }
1401
1402
  /**
1403
   * find by ...
1404
   *
1405
   * @param string          $property
1406
   * @param string|string[] $value
1407
   * @param string          $comparisonOp
1408
   *
1409
   * @return static <p>(Immutable)</p>
1410
   */
1411
  public function findBy(string $property, $value, string $comparisonOp = 'eq')
1412
  {
1413
    return $this->filterBy($property, $value, $comparisonOp);
1414
  }
1415
1416
  /**
1417
   * Get the first value from the current array.
1418
   *
1419
   * @return mixed <p>Return null if there wasn't a element.</p>
1420
   */
1421 13
  public function first()
1422
  {
1423 13
    $tmpArray = $this->array;
1424 13
    $result = \array_shift($tmpArray);
1425
1426 13
    if ($result === null) {
1427 3
      return null;
1428
    }
1429
1430 10
    return $result;
1431
  }
1432
1433
  /**
1434
   * Get the first value(s) from the current array.
1435
   *
1436
   * @param int|null $number <p>How many values you will take?</p>
1437
   *
1438
   * @return static <p>(Immutable)</p>
1439
   */
1440 28
  public function firstsImmutable(int $number = null)
1441
  {
1442 28
    if ($number === null) {
1443 7
      $arrayTmp = $this->array;
1444 7
      $array = (array)\array_shift($arrayTmp);
1445
    } else {
1446 21
      $number = (int)$number;
1447 21
      $arrayTmp = $this->array;
1448 21
      $array = \array_splice($arrayTmp, 0, $number, true);
1449
    }
1450
1451 28
    return static::create($array);
1452
  }
1453
1454
  /**
1455
   * Get the first value(s) from the current array.
1456
   *
1457
   * @param int|null $number <p>How many values you will take?</p>
1458
   *
1459
   * @return static <p>(Mutable)</p>
1460
   */
1461 26
  public function firstsMutable(int $number = null)
1462
  {
1463 26
    if ($number === null) {
1464 11
      $this->array = (array)\array_shift($this->array);
1465
    } else {
1466 15
      $number = (int)$number;
1467 15
      $this->array = \array_splice($this->array, 0, $number, true);
1468
    }
1469
1470 26
    return $this;
1471
  }
1472
1473
  /**
1474
   * Exchanges all keys with their associated values in an array.
1475
   *
1476
   * @return static <p>(Immutable)</p>
1477
   */
1478 1
  public function flip()
1479
  {
1480 1
    $result = \array_flip($this->array);
1481
1482 1
    return static::create($result);
1483
  }
1484
1485
  /**
1486
   * Get a value from an array (optional using dot-notation).
1487
   *
1488
   * @param mixed $key       <p>The key to look for.</p>
1489
   * @param mixed $fallback  <p>Value to fallback to.</p>
1490
   * @param array $array     <p>The array to get from, if it's set to "null" we use the current array from the
1491
   *                         class.</p>
1492
   *
1493
   * @return mixed
1494
   */
1495 61
  public function get($key, $fallback = null, array $array = null)
1496
  {
1497 61
    if ($array !== null) {
1498 3
      $usedArray = $array;
1499
    } else {
1500 58
      $usedArray = $this->array;
1501
    }
1502
1503 61
    if ($key === null) {
1504 1
      return static::create($usedArray);
1505
    }
1506
1507
    // php cast "bool"-index into "int"-index
1508 61
    if ((bool)$key === $key) {
1509 2
      $key = (int)$key;
1510
    }
1511
1512 61
    if (\array_key_exists($key, $usedArray) === true) {
1513 51
      if (\is_array($usedArray[$key])) {
1514 6
        return static::create($usedArray[$key]);
1515
      }
1516
1517 47
      return $usedArray[$key];
1518
    }
1519
1520
    // Crawl through array, get key according to object or not
1521 20
    foreach (\explode($this->pathSeparator, (string)$key) as $segment) {
1522 20
      if (!isset($usedArray[$segment])) {
1523 19
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1524
      }
1525
1526 5
      $usedArray = $usedArray[$segment];
1527
    }
1528
1529 5
    if (\is_array($usedArray)) {
1530
      return static::create($usedArray);
1531
    }
1532
1533 5
    return $usedArray;
1534
  }
1535
1536
  /**
1537
   * Get the current array from the "Arrayy"-object.
1538
   *
1539
   * @return array
1540
   */
1541 571
  public function getArray(): array
1542
  {
1543 571
    \array_map(['self', 'internalGetArray'], $this->array);
1544
1545 571
    return $this->array;
1546
  }
1547
1548
  /**
1549
   * Returns the values from a single column of the input array, identified by
1550
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1551
   *
1552
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1553
   * array by the values from the $indexKey column in the input array.
1554
   *
1555
   * @param mixed $columnKey
1556
   * @param mixed $indexKey
1557
   *
1558
   * @return static <p>(Immutable)</p>
1559
   */
1560 1
  public function getColumn($columnKey = null, $indexKey = null)
1561
  {
1562 1
    $result = \array_column($this->array, $columnKey, $indexKey);
1563
1564 1
    return static::create($result);
1565
  }
1566
1567
  /**
1568
   * Get correct PHP constant for direction.
1569
   *
1570
   * @param int|string $direction
1571
   *
1572
   * @return int
1573
   */
1574 38
  protected function getDirection($direction): int
1575
  {
1576 38
    if (\is_string($direction)) {
1577 10
      $direction = \strtolower($direction);
1578
1579 10
      if ($direction === 'desc') {
1580 2
        $direction = SORT_DESC;
1581
      } else {
1582 8
        $direction = SORT_ASC;
1583
      }
1584
    }
1585
1586
    if (
1587 38
        $direction !== SORT_DESC
1588
        &&
1589 38
        $direction !== SORT_ASC
1590
    ) {
1591
      $direction = SORT_ASC;
1592
    }
1593
1594 38
    return $direction;
1595
  }
1596
1597
  /**
1598
   * alias: for "Arrayy->keys()"
1599
   *
1600
   * @see Arrayy::keys()
1601
   *
1602
   * @return static <p>(Immutable)</p>
1603
   */
1604 1
  public function getKeys()
1605
  {
1606 1
    return $this->keys();
1607
  }
1608
1609
  /**
1610
   * Get the current array from the "Arrayy"-object as object.
1611
   *
1612
   * @return \stdClass (object)
1613
   */
1614 4
  public function getObject(): \stdClass
1615
  {
1616 4
    return self::arrayToObject($this->getArray());
1617
  }
1618
1619
  /**
1620
   * alias: for "Arrayy->randomImmutable()"
1621
   *
1622
   * @see Arrayy::randomImmutable()
1623
   *
1624
   * @return static <p>(Immutable)</p>
1625
   */
1626 4
  public function getRandom()
1627
  {
1628 4
    return $this->randomImmutable();
1629
  }
1630
1631
  /**
1632
   * alias: for "Arrayy->randomKey()"
1633
   *
1634
   * @see Arrayy::randomKey()
1635
   *
1636
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1637
   */
1638 3
  public function getRandomKey()
1639
  {
1640 3
    return $this->randomKey();
1641
  }
1642
1643
  /**
1644
   * alias: for "Arrayy->randomKeys()"
1645
   *
1646
   * @see Arrayy::randomKeys()
1647
   *
1648
   * @param int $number
1649
   *
1650
   * @return static <p>(Immutable)</p>
1651
   */
1652 8
  public function getRandomKeys(int $number)
1653
  {
1654 8
    return $this->randomKeys($number);
1655
  }
1656
1657
  /**
1658
   * alias: for "Arrayy->randomValue()"
1659
   *
1660
   * @see Arrayy::randomValue()
1661
   *
1662
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1663
   */
1664 3
  public function getRandomValue()
1665
  {
1666 3
    return $this->randomValue();
1667
  }
1668
1669
  /**
1670
   * alias: for "Arrayy->randomValues()"
1671
   *
1672
   * @see Arrayy::randomValues()
1673
   *
1674
   * @param int $number
1675
   *
1676
   * @return static <p>(Immutable)</p>
1677
   */
1678 6
  public function getRandomValues(int $number)
1679
  {
1680 6
    return $this->randomValues($number);
1681
  }
1682
1683
  /**
1684
   * Group values from a array according to the results of a closure.
1685
   *
1686
   * @param \callable $grouper <p>A callable function name.</p>
1687
   * @param bool      $saveKeys
1688
   *
1689
   * @return static <p>(Immutable)</p>
1690
   */
1691 3
  public function group($grouper, bool $saveKeys = false)
1692
  {
1693 3
    $array = (array)$this->array;
1694 3
    $result = [];
1695
1696
    // Iterate over values, group by property/results from closure
1697 3
    foreach ($array as $key => $value) {
1698
1699 3
      $groupKey = \is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $array);
1700 3
      $newValue = $this->get($groupKey, null, $result);
1701
1702 3
      if ($groupKey instanceof self) {
1703
        $groupKey = $groupKey->getArray();
1704
      }
1705
1706 3
      if ($newValue instanceof self) {
1707 3
        $newValue = $newValue->getArray();
1708
      }
1709
1710
      // Add to results
1711 3
      if ($groupKey !== null) {
1712 2
        if ($saveKeys) {
1713 1
          $result[$groupKey] = $newValue;
1714 1
          $result[$groupKey][$key] = $value;
1715
        } else {
1716 1
          $result[$groupKey] = $newValue;
1717 3
          $result[$groupKey][] = $value;
1718
        }
1719
      }
1720
1721
    }
1722
1723 3
    return static::create($result);
1724
  }
1725
1726
  /**
1727
   * Check if an array has a given key.
1728
   *
1729
   * @param mixed $key
1730
   *
1731
   * @return bool
1732
   */
1733 22
  public function has($key): bool
1734
  {
1735
    // Generate unique string to use as marker.
1736 22
    $unFound = \uniqid('arrayy', true);
1737
1738 22
    return $this->get($key, $unFound) !== $unFound;
1739
  }
1740
1741
  /**
1742
   * Implodes the keys of this array.
1743
   *
1744
   * @param string $glue
1745
   *
1746
   * @return string
1747
   */
1748 8
  public function implodeKeys(string $glue = ''): string
1749
  {
1750 8
    return $this->implode_recursive($glue, $this->array, true);
1751
  }
1752
1753
  /**
1754
   * Implodes the values of this array.
1755
   *
1756
   * @param string $glue
1757
   *
1758
   * @return string
1759
   */
1760 27
  public function implode(string $glue = ''): string
1761
  {
1762 27
    return $this->implode_recursive($glue, $this->array, false);
1763
  }
1764
1765
  /**
1766
   * @param mixed               $glue
1767
   * @param string|array|static $pieces
1768
   * @param bool                $useKeys
1769
   *
1770
   * @return string
1771
   */
1772 35
  protected function implode_recursive($glue = '', $pieces, bool $useKeys = false): string
1773
  {
1774 35
    if ($pieces instanceof self) {
1775 1
      $pieces = $pieces->getArray();
1776
    }
1777
1778 35
    if (\is_array($pieces)) {
1779 35
      $pieces_count = \count($pieces);
1780 35
      $pieces_count_not_zero = $pieces_count > 0;
1781
1782 35
      return \implode(
1783 35
          $glue,
1784 35
          \array_map(
1785 35
              [$this, 'implode_recursive'],
1786 35
              \array_fill(0, ($pieces_count_not_zero ? $pieces_count : 1), $glue),
1787 35
              ($useKeys === true && $pieces_count_not_zero ? $this->array_keys_recursive($pieces) : $pieces)
1788
          )
1789
      );
1790
    }
1791
1792 35
    return (string)$pieces;
1793
  }
1794
1795
  /**
1796
   * Given a list and an iterate-function that returns
1797
   * a key for each element in the list (or a property name),
1798
   * returns an object with an index of each item.
1799
   *
1800
   * Just like groupBy, but for when you know your keys are unique.
1801
   *
1802
   * @param mixed $key
1803
   *
1804
   * @return static <p>(Immutable)</p>
1805
   */
1806 3
  public function indexBy($key)
1807
  {
1808 3
    $results = [];
1809
1810 3
    foreach ($this->array as $a) {
1811 3
      if (\array_key_exists($key, $a) === true) {
1812 3
        $results[$a[$key]] = $a;
1813
      }
1814
    }
1815
1816 3
    return static::create($results);
1817
  }
1818
1819
  /**
1820
   * alias: for "Arrayy->searchIndex()"
1821
   *
1822
   * @see Arrayy::searchIndex()
1823
   *
1824
   * @param mixed $value <p>The value to search for.</p>
1825
   *
1826
   * @return mixed
1827
   */
1828 4
  public function indexOf($value)
1829
  {
1830 4
    return $this->searchIndex($value);
1831
  }
1832
1833
  /**
1834
   * Get everything but the last..$to items.
1835
   *
1836
   * @param int $to
1837
   *
1838
   * @return static <p>(Immutable)</p>
1839
   */
1840 12
  public function initial(int $to = 1)
1841
  {
1842 12
    $slice = \count($this->array) - $to;
1843
1844 12
    return $this->firstsImmutable($slice);
1845
  }
1846
1847
  /**
1848
   * @param mixed $value
1849
   */
1850 470
  protected function internalGetArray(&$value)
1851
  {
1852 470
    if ($value instanceof self) {
1853
1854
      $valueTmp = $value->getArray();
1855
      if (\count($valueTmp) === 0) {
1856
        $value = [];
1857
      } else {
1858
        /** @noinspection PhpUnusedLocalVariableInspection */
1859
        $value = &$valueTmp;
1860
      }
1861
1862 470
    } elseif ($value instanceof \JsonSerializable) {
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1863
      /** @noinspection PhpUnusedLocalVariableInspection */
1864
      $value = &$value->jsonSerialize();
1865
    }
1866 470
  }
1867
1868
  /**
1869
   * Internal mechanics of remove method.
1870
   *
1871
   * @param mixed $key
1872
   *
1873
   * @return bool
1874
   */
1875 18
  protected function internalRemove($key): bool
1876
  {
1877 18
    $path = \explode($this->pathSeparator, (string)$key);
1878
1879
    // Crawl though the keys
1880 18
    while (\count($path) > 1) {
1881
      $key = \array_shift($path);
1882
1883
      if (!$this->has($key)) {
1884
        return false;
1885
      }
1886
1887
      $this->array = &$this->array[$key];
1888
    }
1889
1890 18
    $key = \array_shift($path);
1891
1892 18
    unset($this->array[$key]);
1893
1894 18
    return true;
1895
  }
1896
1897
  /**
1898
   * Internal mechanic of set method.
1899
   *
1900
   * @param mixed $key
1901
   * @param mixed $value
1902
   *
1903
   * @return bool
1904
   */
1905 30
  protected function internalSet($key, $value): bool
1906
  {
1907 30
    if ($key === null) {
1908
      return false;
1909
    }
1910
1911
    // init
1912 30
    $array =& $this->array;
1913 30
    $path = \explode($this->pathSeparator, (string)$key);
1914
1915
    // Crawl through the keys
1916 30
    while (\count($path) > 1) {
1917 3
      $key = \array_shift($path);
1918
1919
      // If the key doesn't exist at this depth, we will just create an empty array
1920
      // to hold the next value, allowing us to create the arrays to hold final
1921
      // values at the correct depth. Then we'll keep digging into the array.
1922 3
      if (!isset($array[$key]) || !\is_array($array[$key])) {
1923
        $array[$key] = static::create([]);
1924
      }
1925
1926 3
      $array =& $array[$key];
1927
    }
1928
1929 30
    $array[\array_shift($path)] = $value;
1930
1931 30
    return true;
1932
  }
1933
1934
  /**
1935
   * Return an array with all elements found in input array.
1936
   *
1937
   * @param array $search
1938
   *
1939
   * @return static <p>(Immutable)</p>
1940
   */
1941 2
  public function intersection(array $search)
1942
  {
1943 2
    return static::create(\array_values(\array_intersect($this->array, $search)));
1944
  }
1945
1946
  /**
1947
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1948
   *
1949
   * @param array $search
1950
   *
1951
   * @return bool
1952
   */
1953 1
  public function intersects(array $search): bool
1954
  {
1955 1
    return \count($this->intersection($search)->array) > 0;
1956
  }
1957
1958
  /**
1959
   * Invoke a function on all of an array's values.
1960
   *
1961
   * @param mixed $callable
1962
   * @param mixed $arguments
1963
   *
1964
   * @return static <p>(Immutable)</p>
1965
   */
1966 1
  public function invoke($callable, $arguments = [])
1967
  {
1968
    // If one argument given for each iteration, create an array for it.
1969 1
    if (!\is_array($arguments)) {
1970 1
      $arguments = StaticArrayy::repeat($arguments, \count($this->array))->getArray();
1971
    }
1972
1973
    // If the callable has arguments, pass them.
1974 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...
1975 1
      $array = \array_map($callable, $this->array, $arguments);
1976
    } else {
1977 1
      $array = \array_map($callable, $this->array);
1978
    }
1979
1980 1
    return static::create($array);
1981
  }
1982
1983
  /**
1984
   * Check whether array is associative or not.
1985
   *
1986
   * @param bool $recursive
1987
   *
1988
   * @return bool <p>Returns true if associative, false otherwise.</p>
1989
   */
1990 15
  public function isAssoc(bool $recursive = false): bool
1991
  {
1992 15
    if ($this->isEmpty()) {
1993 3
      return false;
1994
    }
1995
1996 13
    foreach ($this->keys($recursive)->getArray() as $key) {
1997 13
      if (!\is_string($key)) {
1998 13
        return false;
1999
      }
2000
    }
2001
2002 3
    return true;
2003
  }
2004
2005
  /**
2006
   * Check whether the array is empty or not.
2007
   *
2008
   * @return bool <p>Returns true if empty, false otherwise.</p>
2009
   */
2010 88
  public function isEmpty(): bool
2011
  {
2012 88
    return !$this->array;
2013
  }
2014
2015
  /**
2016
   * Check if the current array is equal to the given "$array" or not.
2017
   *
2018
   * @param array $array
2019
   *
2020
   * @return bool
2021
   */
2022
  public function isEqual(array $array): bool
2023
  {
2024
    return ($this->array === $array);
2025
  }
2026
2027
  /**
2028
   * Check if the current array is a multi-array.
2029
   *
2030
   * @return bool
2031
   */
2032 14
  public function isMultiArray(): bool
2033
  {
2034 14
    return !(\count($this->array) === \count($this->array, COUNT_RECURSIVE));
2035
  }
2036
2037
  /**
2038
   * Check whether array is numeric or not.
2039
   *
2040
   * @return bool <p>Returns true if numeric, false otherwise.</p>
2041
   */
2042 5
  public function isNumeric(): bool
2043
  {
2044 5
    if ($this->isEmpty()) {
2045 2
      return false;
2046
    }
2047
2048 4
    foreach ($this->keys() as $key) {
2049 4
      if (!\is_int($key)) {
2050 4
        return false;
2051
      }
2052
    }
2053
2054 2
    return true;
2055
  }
2056
2057
  /**
2058
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
2059
   *
2060
   * @param bool $recursive
2061
   *
2062
   * @return bool
2063
   */
2064 1
  public function isSequential(bool $recursive = false): bool
2065
  {
2066 1
    if ($recursive === true) {
2067
      return $this->array_keys_recursive($this->array) === \range(0, \count($this->array, COUNT_RECURSIVE) - 1);
2068
    }
2069
2070 1
    return \array_keys($this->array) === \range(0, \count($this->array) - 1);
2071
  }
2072
2073
  /**
2074
   * @return array
2075
   */
2076
  public function jsonSerialize(): array
2077
  {
2078
    return $this->getArray();
2079
  }
2080
2081
  /**
2082
   * Get all keys from the current array.
2083
   *
2084
   * @param bool  $recursive    [optional] <p>
2085
   *                            Get all keys, also from all sub-arrays from an multi-dimensional array.
2086
   *                            </p>
2087
   * @param mixed $search_value [optional] <p>
2088
   *                            If specified, then only keys containing these values are returned.
2089
   *                            </p>
2090
   * @param bool  $strict       [optional] <p>
2091
   *                            Determines if strict comparison (===) should be used during the search.
2092
   *                            </p>
2093
   *
2094
   * @return static <p>(Immutable) An array of all the keys in input.</p>
2095
   */
2096 26
  public function keys(bool $recursive = false, $search_value = null, bool $strict = true)
2097
  {
2098 26
    if ($recursive === true) {
2099 2
      if ($search_value === null) {
2100 2
        $array = $this->array_keys_recursive($this->array);
2101
      } else {
2102 2
        $array = $this->array_keys_recursive($this->array, $search_value, $strict);
2103
      }
2104
    } else {
2105 25
      if ($search_value === null) {
2106 25
        $array = \array_keys($this->array);
2107
      } else {
2108
        $array = \array_keys($this->array, $search_value, $strict);
2109
      }
2110
    }
2111
2112 26
    return static::create($array);
2113
  }
2114
2115
  /**
2116
   * @param array $input        <p>
2117
   *                            An array containing keys to return.
2118
   *                            </p>
2119
   * @param mixed $search_value [optional] <p>
2120
   *                            If specified, then only keys containing these values are returned.
2121
   *                            </p>
2122
   * @param bool  $strict       [optional] <p>
2123
   *                            Determines if strict comparison (===) should be used during the search.
2124
   *                            </p>
2125
   *
2126
   * @return array an array of all the keys in input.
2127
   */
2128 9
  protected function array_keys_recursive(array $input = null, $search_value = null, bool $strict = true): array
2129
  {
2130
    // init
2131 9
    $keys = [];
2132
2133 9
    if ($input === null) {
2134
      $input = $this->array;
2135
    }
2136
2137 9
    foreach ($input as $key => $value) {
2138
2139
      if (
2140 9
          $search_value === null
2141
          ||
2142
          (
2143
              \is_array($search_value) === true
2144
              &&
2145 9
              \in_array($key, $search_value, $strict)
2146
          )
2147
      ) {
2148 9
        $keys[] = $key;
2149
      }
2150
2151
      // recursive needed?
2152 9
      if (\is_array($value) === true) {
2153 9
        $keys = \array_merge($keys, $this->array_keys_recursive($value));
2154
      }
2155
    }
2156
2157 9
    return $keys;
2158
  }
2159
2160
  /**
2161
   * Sort an array by key in reverse order.
2162
   *
2163
   * @param int $sort_flags [optional] <p>
2164
   *                        You may modify the behavior of the sort using the optional
2165
   *                        parameter sort_flags, for details
2166
   *                        see sort.
2167
   *                        </p>
2168
   *
2169
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2170
   */
2171 4
  public function krsort(int $sort_flags = 0)
2172
  {
2173 4
    krsort($this->array, $sort_flags);
2174
2175 4
    return $this;
2176
  }
2177
2178
  /**
2179
   * Get the last value from the current array.
2180
   *
2181
   * @return mixed <p>Return null if there wasn't a element.</p>
2182
   */
2183 4
  public function last()
2184
  {
2185 4
    return $this->pop();
2186
  }
2187
2188
  /**
2189
   * Get the last value(s) from the current array.
2190
   *
2191
   * @param int|null $number
2192
   *
2193
   * @return static <p>(Immutable)</p>
2194
   */
2195 13
  public function lastsImmutable(int $number = null)
2196
  {
2197 13
    if ($this->isEmpty()) {
2198 1
      return static::create();
2199
    }
2200
2201 12
    if ($number === null) {
2202 8
      $poppedValue = $this->pop();
2203
2204 8
      if ($poppedValue === null) {
2205 1
        $poppedValue = [$poppedValue];
2206
      } else {
2207 7
        $poppedValue = (array)$poppedValue;
2208
      }
2209
2210 8
      $arrayy = static::create($poppedValue);
2211
    } else {
2212 4
      $number = (int)$number;
2213 4
      $arrayy = $this->rest(-$number);
2214
    }
2215
2216 12
    return $arrayy;
2217
  }
2218
2219
  /**
2220
   * Get the last value(s) from the current array.
2221
   *
2222
   * @param int|null $number
2223
   *
2224
   * @return static <p>(Mutable)</p>
2225
   */
2226 13
  public function lastsMutable(int $number = null)
2227
  {
2228 13
    if ($this->isEmpty()) {
2229 1
      return $this;
2230
    }
2231
2232 12
    if ($number === null) {
2233 8
      $poppedValue = $this->pop();
2234
2235 8
      if ($poppedValue === null) {
2236 1
        $poppedValue = [$poppedValue];
2237
      } else {
2238 7
        $poppedValue = (array)$poppedValue;
2239
      }
2240
2241 8
      $this->array = static::create($poppedValue)->array;
2242
    } else {
2243 4
      $number = (int)$number;
2244 4
      $this->array = $this->rest(-$number)->array;
2245
    }
2246
2247 12
    return $this;
2248
  }
2249
2250
  /**
2251
   * Count the values from the current array.
2252
   *
2253
   * alias: for "Arrayy->size()"
2254
   *
2255
   * @see Arrayy::size()
2256
   *
2257
   * @param int $mode
2258
   *
2259
   * @return int
2260
   */
2261 20
  public function length(int $mode = COUNT_NORMAL): int
2262
  {
2263 20
    return $this->size($mode);
2264
  }
2265
2266
  /**
2267
   * Apply the given function to the every element of the array,
2268
   * collecting the results.
2269
   *
2270
   * @param \callable $callable
2271
   *
2272
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
2273
   */
2274 4
  public function map($callable)
2275
  {
2276 4
    $result = \array_map($callable, $this->array);
2277
2278 4
    return static::create($result);
2279
  }
2280
2281
  /**
2282
   * Check if all items in current array match a truth test.
2283
   *
2284
   * @param \Closure $closure
2285
   *
2286
   * @return bool
2287
   */
2288 15 View Code Duplication
  public function matches(\Closure $closure): bool
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...
2289
  {
2290 15
    if (\count($this->array) === 0) {
2291 2
      return false;
2292
    }
2293
2294
    // init
2295 13
    $array = $this->array;
2296
2297 13
    foreach ($array as $key => $value) {
2298 13
      $value = $closure($value, $key);
2299
2300 13
      if ($value === false) {
2301 13
        return false;
2302
      }
2303
    }
2304
2305 7
    return true;
2306
  }
2307
2308
  /**
2309
   * Check if any item in the current array matches a truth test.
2310
   *
2311
   * @param \Closure $closure
2312
   *
2313
   * @return bool
2314
   */
2315 14 View Code Duplication
  public function matchesAny(\Closure $closure): bool
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 14
    if (\count($this->array) === 0) {
2318 2
      return false;
2319
    }
2320
2321
    // init
2322 12
    $array = $this->array;
2323
2324 12
    foreach ($array as $key => $value) {
2325 12
      $value = $closure($value, $key);
2326
2327 12
      if ($value === true) {
2328 12
        return true;
2329
      }
2330
    }
2331
2332 4
    return false;
2333
  }
2334
2335
  /**
2336
   * Get the max value from an array.
2337
   *
2338
   * @return mixed
2339
   */
2340 10
  public function max()
2341
  {
2342 10
    if ($this->count() === 0) {
2343 1
      return false;
2344
    }
2345
2346 9
    return max($this->array);
2347
  }
2348
2349
  /**
2350
   * Merge the new $array into the current array.
2351
   *
2352
   * - keep key,value from the current array, also if the index is in the new $array
2353
   *
2354
   * @param array $array
2355
   * @param bool  $recursive
2356
   *
2357
   * @return static <p>(Immutable)</p>
2358
   */
2359 25 View Code Duplication
  public function mergeAppendKeepIndex(array $array = [], bool $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...
2360
  {
2361 25
    if (true === $recursive) {
2362 4
      $result = \array_replace_recursive($this->array, $array);
2363
    } else {
2364 21
      $result = \array_replace($this->array, $array);
2365
    }
2366
2367 25
    return static::create($result);
2368
  }
2369
2370
  /**
2371
   * Merge the new $array into the current array.
2372
   *
2373
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
2374
   * - create new indexes
2375
   *
2376
   * @param array $array
2377
   * @param bool  $recursive
2378
   *
2379
   * @return static <p>(Immutable)</p>
2380
   */
2381 16 View Code Duplication
  public function mergeAppendNewIndex(array $array = [], bool $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...
2382
  {
2383 16
    if (true === $recursive) {
2384 4
      $result = \array_merge_recursive($this->array, $array);
2385
    } else {
2386 12
      $result = \array_merge($this->array, $array);
2387
    }
2388
2389 16
    return static::create($result);
2390
  }
2391
2392
  /**
2393
   * Merge the the current array into the $array.
2394
   *
2395
   * - use key,value from the new $array, also if the index is in the current array
2396
   *
2397
   * @param array $array
2398
   * @param bool  $recursive
2399
   *
2400
   * @return static <p>(Immutable)</p>
2401
   */
2402 16 View Code Duplication
  public function mergePrependKeepIndex(array $array = [], bool $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...
2403
  {
2404 16
    if (true === $recursive) {
2405 4
      $result = \array_replace_recursive($array, $this->array);
2406
    } else {
2407 12
      $result = \array_replace($array, $this->array);
2408
    }
2409
2410 16
    return static::create($result);
2411
  }
2412
2413
  /**
2414
   * Merge the current array into the new $array.
2415
   *
2416
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
2417
   * - create new indexes
2418
   *
2419
   * @param array $array
2420
   * @param bool  $recursive
2421
   *
2422
   * @return static <p>(Immutable)</p>
2423
   */
2424 17 View Code Duplication
  public function mergePrependNewIndex(array $array = [], bool $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...
2425
  {
2426 17
    if (true === $recursive) {
2427 4
      $result = \array_merge_recursive($array, $this->array);
2428
    } else {
2429 13
      $result = \array_merge($array, $this->array);
2430
    }
2431
2432 17
    return static::create($result);
2433
  }
2434
2435
  /**
2436
   * Get the min value from an array.
2437
   *
2438
   * @return mixed
2439
   */
2440 10
  public function min()
2441
  {
2442 10
    if ($this->count() === 0) {
2443 1
      return false;
2444
    }
2445
2446 9
    return min($this->array);
2447
  }
2448
2449
  /**
2450
   * Move an array element to a new index.
2451
   *
2452
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2453
   *
2454
   * @param int|string $from
2455
   * @param int|string $to
2456
   *
2457
   * @return static <p>(Immutable)</p>
2458
   */
2459 1
  public function moveElement($from, $to)
2460
  {
2461 1
    $array = $this->array;
2462
2463 1
    if (\is_int($from)) {
2464 1
      $tmp = \array_splice($array, $from, 1);
2465 1
      \array_splice($array, $to, 0, $tmp);
2466 1
      $output = $array;
2467 1
    } elseif (\is_string($from)) {
2468 1
      $indexToMove = \array_search($from, \array_keys($array), true);
2469 1
      $itemToMove = $array[$from];
2470 1
      \array_splice($array, $indexToMove, 1);
2471 1
      $i = 0;
2472 1
      $output = [];
2473 1
      foreach ($array as $key => $item) {
2474 1
        if ($i == $to) {
2475 1
          $output[$from] = $itemToMove;
2476
        }
2477 1
        $output[$key] = $item;
2478 1
        $i++;
2479
      }
2480
    } else {
2481
      $output = [];
2482
    }
2483
2484 1
    return static::create($output);
2485
  }
2486
2487
  /**
2488
   * Convert a object into an array.
2489
   *
2490
   * @param object $object
2491
   *
2492
   * @return mixed
2493
   */
2494 5
  protected static function objectToArray($object)
2495
  {
2496 5
    if (!\is_object($object)) {
2497 4
      return $object;
2498
    }
2499
2500 5
    if (\is_object($object)) {
2501 5
      $object = \get_object_vars($object);
2502
    }
2503
2504 5
    return \array_map(['self', 'objectToArray'], $object);
2505
  }
2506
2507
  /**
2508
   * Get a subset of the items from the given array.
2509
   *
2510
   * @param mixed[] $keys
2511
   *
2512
   * @return static <p>(Immutable)</p>
2513
   */
2514
  public function only(array $keys)
2515
  {
2516
    $array = $this->array;
2517
2518
    return static::create(\array_intersect_key($array, \array_flip($keys)));
2519
  }
2520
2521
  /**
2522
   * Pad array to the specified size with a given value.
2523
   *
2524
   * @param int   $size  <p>Size of the result array.</p>
2525
   * @param mixed $value <p>Empty value by default.</p>
2526
   *
2527
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
2528
   */
2529 4
  public function pad(int $size, $value)
2530
  {
2531 4
    $result = \array_pad($this->array, $size, $value);
2532
2533 4
    return static::create($result);
2534
  }
2535
2536
  /**
2537
   * Pop a specified value off the end of the current array.
2538
   *
2539
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
2540
   */
2541 16
  public function pop()
2542
  {
2543 16
    return \array_pop($this->array);
2544
  }
2545
2546
  /**
2547
   * Prepend a (key) + value to the current array.
2548
   *
2549
   * @param mixed $value
2550
   * @param mixed $key
2551
   *
2552
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2553
   */
2554 8
  public function prepend($value, $key = null)
2555
  {
2556 8
    if ($key === null) {
2557 8
      \array_unshift($this->array, $value);
2558
    } else {
2559
      /** @noinspection AdditionOperationOnArraysInspection */
2560 1
      $this->array = [$key => $value] + $this->array;
2561
    }
2562
2563 8
    return $this;
2564
  }
2565
2566
  /**
2567
   * Add a suffix to each key.
2568
   *
2569
   * @param mixed $suffix
2570
   *
2571
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended keys.</p>
2572
   */
2573 10 View Code Duplication
  public function prependToEachKey($suffix)
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...
2574
  {
2575 10
    $result = [];
2576 10
    foreach ($this->array as $key => $item) {
2577 9
      if ($item instanceof self) {
2578
        $result[$key] = $item->prependToEachKey($suffix);
2579 9
      } elseif (\is_array($item)) {
2580
        $result[$key] = self::create($item)->prependToEachKey($suffix)->toArray();
2581
      } else {
2582 9
        $result[$key . $suffix] = $item;
2583
      }
2584
2585
    }
2586
2587 10
    return self::create($result);
2588
  }
2589
2590
  /**
2591
   * Add a suffix to each value.
2592
   *
2593
   * @param mixed $suffix
2594
   *
2595
   * @return static <p>(Immutable) Return an Arrayy object, with the prepended values.</p>
2596
   */
2597 10 View Code Duplication
  public function prependToEachValue($suffix)
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...
2598
  {
2599 10
    $result = [];
2600 10
    foreach ($this->array as $key => $item) {
2601 9
      if ($item instanceof self) {
2602
        $result[$key] = $item->prependToEachValue($suffix);
2603 9
      } elseif (\is_array($item)) {
2604
        $result[$key] = self::create($item)->prependToEachValue($suffix)->toArray();
2605 9
      } elseif (\is_object($item)) {
2606 1
        $result[$key] = $item;
2607
      } else {
2608 9
        $result[$key] = $item . $suffix;
2609
      }
2610
    }
2611
2612 10
    return self::create($result);
2613
  }
2614
2615
  /**
2616
   * Push one or more values onto the end of array at once.
2617
   *
2618
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2619
   */
2620 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...
2621
  {
2622 4
    if (\func_num_args()) {
2623 4
      $args = \array_merge([&$this->array], \func_get_args());
2624 4
      \array_push(...$args);
2625
    }
2626
2627 4
    return $this;
2628
  }
2629
2630
  /**
2631
   * Get a random value from the current array.
2632
   *
2633
   * @param null|int $number <p>How many values you will take?</p>
2634
   *
2635
   * @return static <p>(Immutable)</p>
2636
   */
2637 18
  public function randomImmutable(int $number = null)
2638
  {
2639 18
    if ($this->count() === 0) {
2640 1
      return static::create();
2641
    }
2642
2643 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...
2644 14
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2645
2646 14
      return static::create($arrayRandValue);
2647
    }
2648
2649 5
    $arrayTmp = $this->array;
2650 5
    \shuffle($arrayTmp);
2651
2652 5
    return static::create($arrayTmp)->firstsImmutable($number);
2653
  }
2654
2655
  /**
2656
   * Pick a random key/index from the keys of this array.
2657
   *
2658
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
2659
   *
2660
   * @throws \RangeException If array is empty
2661
   */
2662 4
  public function randomKey()
2663
  {
2664 4
    $result = $this->randomKeys(1);
2665
2666 4
    if (!isset($result[0])) {
2667
      $result[0] = null;
2668
    }
2669
2670 4
    return $result[0];
2671
  }
2672
2673
  /**
2674
   * Pick a given number of random keys/indexes out of this array.
2675
   *
2676
   * @param int $number <p>The number of keys/indexes (should be <= $this->count())</p>
2677
   *
2678
   * @return static <p>(Immutable)</p>
2679
   *
2680
   * @throws \RangeException If array is empty
2681
   */
2682 13
  public function randomKeys(int $number)
2683
  {
2684 13
    $count = $this->count();
2685
2686 13
    if ($number === 0 || $number > $count) {
2687 2
      throw new \RangeException(
2688 2
          \sprintf(
2689 2
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2690 2
              $number,
2691 2
              $count
2692
          )
2693
      );
2694
    }
2695
2696 11
    $result = (array)\array_rand($this->array, $number);
2697
2698 11
    return static::create($result);
2699
  }
2700
2701
  /**
2702
   * Get a random value from the current array.
2703
   *
2704
   * @param null|int $number <p>How many values you will take?</p>
2705
   *
2706
   * @return static <p>(Mutable)</p>
2707
   */
2708 17
  public function randomMutable(int $number = null)
2709
  {
2710 17
    if ($this->count() === 0) {
2711
      return static::create();
2712
    }
2713
2714 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...
2715 7
      $arrayRandValue = [$this->array[\array_rand($this->array)]];
2716 7
      $this->array = $arrayRandValue;
2717
2718 7
      return $this;
2719
    }
2720
2721 11
    \shuffle($this->array);
2722
2723 11
    return $this->firstsMutable($number);
2724
  }
2725
2726
  /**
2727
   * Pick a random value from the values of this array.
2728
   *
2729
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2730
   */
2731 4
  public function randomValue()
2732
  {
2733 4
    $result = $this->randomImmutable();
2734
2735 4
    if (!isset($result[0])) {
2736
      $result[0] = null;
2737
    }
2738
2739 4
    return $result[0];
2740
  }
2741
2742
  /**
2743
   * Pick a given number of random values out of this array.
2744
   *
2745
   * @param int $number
2746
   *
2747
   * @return static <p>(Mutable)</p>
2748
   */
2749 7
  public function randomValues(int $number)
2750
  {
2751 7
    return $this->randomMutable($number);
2752
  }
2753
2754
  /**
2755
   * Get a random value from an array, with the ability to skew the results.
2756
   *
2757
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2758
   *
2759
   * @param array    $array
2760
   * @param null|int $number <p>How many values you will take?</p>
2761
   *
2762
   * @return static <p>(Immutable)</p>
2763
   */
2764 9
  public function randomWeighted(array $array, int $number = null)
2765
  {
2766 9
    $options = [];
2767 9
    foreach ($array as $option => $weight) {
2768 9
      if ($this->searchIndex($option) !== false) {
2769 9
        for ($i = 0; $i < $weight; ++$i) {
2770 1
          $options[] = $option;
2771
        }
2772
      }
2773
    }
2774
2775 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2776
  }
2777
2778
  /**
2779
   * Reduce the current array via callable e.g. anonymous-function.
2780
   *
2781
   * @param \callable $callable
2782
   * @param array     $init
2783
   *
2784
   * @return static <p>(Immutable)</p>
2785
   */
2786 4
  public function reduce($callable, array $init = [])
2787
  {
2788 4
    $result = \array_reduce($this->array, $callable, $init);
2789
2790 4
    if ($result === null) {
2791
      $this->array = [];
2792
    } else {
2793 4
      $this->array = (array)$result;
2794
    }
2795
2796 4
    return static::create($this->array);
2797
  }
2798
2799
  /**
2800
   * Create a numerically re-indexed Arrayy object.
2801
   *
2802
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2803
   */
2804 9
  public function reindex()
2805
  {
2806 9
    $this->array = \array_values($this->array);
2807
2808 9
    return $this;
2809
  }
2810
2811
  /**
2812
   * Return all items that fail the truth test.
2813
   *
2814
   * @param \Closure $closure
2815
   *
2816
   * @return static <p>(Immutable)</p>
2817
   */
2818 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...
2819
  {
2820 1
    $filtered = [];
2821
2822 1
    foreach ($this->array as $key => $value) {
2823 1
      if (!$closure($value, $key)) {
2824 1
        $filtered[$key] = $value;
2825
      }
2826
    }
2827
2828 1
    return static::create($filtered);
2829
  }
2830
2831
  /**
2832
   * Remove a value from the current array (optional using dot-notation).
2833
   *
2834
   * @param mixed $key
2835
   *
2836
   * @return static <p>(Immutable)</p>
2837
   */
2838 18
  public function remove($key)
2839
  {
2840
    // recursive call
2841 18
    if (\is_array($key)) {
2842
      foreach ($key as $k) {
2843
        $this->internalRemove($k);
2844
      }
2845
2846
      return static::create($this->array);
2847
    }
2848
2849 18
    $this->internalRemove($key);
2850
2851 18
    return static::create($this->array);
2852
  }
2853
2854
  /**
2855
   * Remove the first value from the current array.
2856
   *
2857
   * @return static <p>(Immutable)</p>
2858
   */
2859 7
  public function removeFirst()
2860
  {
2861 7
    $tmpArray = $this->array;
2862 7
    \array_shift($tmpArray);
2863
2864 7
    return static::create($tmpArray);
2865
  }
2866
2867
  /**
2868
   * Remove the last value from the current array.
2869
   *
2870
   * @return static <p>(Immutable)</p>
2871
   */
2872 7
  public function removeLast()
2873
  {
2874 7
    $tmpArray = $this->array;
2875 7
    \array_pop($tmpArray);
2876
2877 7
    return static::create($tmpArray);
2878
  }
2879
2880
  /**
2881
   * Removes a particular value from an array (numeric or associative).
2882
   *
2883
   * @param mixed $value
2884
   *
2885
   * @return static <p>(Immutable)</p>
2886
   */
2887 7
  public function removeValue($value)
2888
  {
2889 7
    $isNumericArray = true;
2890 7
    foreach ($this->array as $key => $item) {
2891 6
      if ($item === $value) {
2892 6
        if (!\is_int($key)) {
2893
          $isNumericArray = false;
2894
        }
2895 6
        unset($this->array[$key]);
2896
      }
2897
    }
2898
2899 7
    if ($isNumericArray) {
2900 7
      $this->array = \array_values($this->array);
2901
    }
2902
2903 7
    return static::create($this->array);
2904
  }
2905
2906
  /**
2907
   * Generate array of repeated arrays.
2908
   *
2909
   * @param int $times <p>How many times has to be repeated.</p>
2910
   *
2911
   * @return Arrayy
2912
   */
2913 1
  public function repeat($times): self
2914
  {
2915 1
    if ($times === 0) {
2916 1
      return new static();
2917
    }
2918
2919 1
    return static::create(\array_fill(0, (int)$times, $this->array));
2920
  }
2921
2922
  /**
2923
   * Replace a key with a new key/value pair.
2924
   *
2925
   * @param mixed $replace
2926
   * @param mixed $key
2927
   * @param mixed $value
2928
   *
2929
   * @return static <p>(Immutable)</p>
2930
   */
2931 2
  public function replace($replace, $key, $value)
2932
  {
2933 2
    $this->remove($replace);
2934
2935 2
    return $this->set($key, $value);
2936
  }
2937
2938
  /**
2939
   * Create an array using the current array as values and the other array as keys.
2940
   *
2941
   * @param array $keys <p>An array of keys.</p>
2942
   *
2943
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
2944
   */
2945 2
  public function replaceAllKeys(array $keys)
2946
  {
2947 2
    $result = \array_combine($keys, $this->array);
2948
2949 2
    return static::create($result);
2950
  }
2951
2952
  /**
2953
   * Create an array using the current array as keys and the other array as values.
2954
   *
2955
   * @param array $array <p>An array o values.</p>
2956
   *
2957
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
2958
   */
2959 2
  public function replaceAllValues(array $array)
2960
  {
2961 2
    $result = \array_combine($this->array, $array);
2962
2963 2
    return static::create($result);
2964
  }
2965
2966
  /**
2967
   * Replace the keys in an array with another set.
2968
   *
2969
   * @param array $keys <p>An array of keys matching the array's size</p>
2970
   *
2971
   * @return static <p>(Immutable)</p>
2972
   */
2973 1
  public function replaceKeys(array $keys)
2974
  {
2975 1
    $values = \array_values($this->array);
2976 1
    $result = \array_combine($keys, $values);
2977
2978 1
    return static::create($result);
2979
  }
2980
2981
  /**
2982
   * Replace the first matched value in an array.
2983
   *
2984
   * @param mixed $search      <p>The value to replace.</p>
2985
   * @param mixed $replacement <p>The value to replace.</p>
2986
   *
2987
   * @return static <p>(Immutable)</p>
2988
   */
2989 3
  public function replaceOneValue($search, $replacement = '')
2990
  {
2991 3
    $array = $this->array;
2992 3
    $key = \array_search($search, $array, true);
2993
2994 3
    if ($key !== false) {
2995 3
      $array[$key] = $replacement;
2996
    }
2997
2998 3
    return static::create($array);
2999
  }
3000
3001
  /**
3002
   * Replace values in the current array.
3003
   *
3004
   * @param mixed $search      <p>The value to replace.</p>
3005
   * @param mixed $replacement <p>What to replace it with.</p>
3006
   *
3007
   * @return static <p>(Immutable)</p>
3008
   */
3009 1
  public function replaceValues($search, $replacement = '')
3010
  {
3011 1
    $array = $this->each(
3012 1
        function ($value) use ($search, $replacement) {
3013 1
          return UTF8::str_replace($search, $replacement, $value);
3014 1
        }
3015
    );
3016
3017 1
    return $array;
3018
  }
3019
3020
  /**
3021
   * Get the last elements from index $from until the end of this array.
3022
   *
3023
   * @param int $from
3024
   *
3025
   * @return static <p>(Immutable)</p>
3026
   */
3027 15
  public function rest(int $from = 1)
3028
  {
3029 15
    $tmpArray = $this->array;
3030
3031 15
    return static::create(\array_splice($tmpArray, $from));
3032
  }
3033
3034
  /**
3035
   * Return the array in the reverse order.
3036
   *
3037
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3038
   */
3039 8
  public function reverse()
3040
  {
3041 8
    $this->array = \array_reverse($this->array);
3042
3043 8
    return $this;
3044
  }
3045
3046
  /**
3047
   * Sort an array in reverse order.
3048
   *
3049
   * @param int $sort_flags [optional] <p>
3050
   *                        You may modify the behavior of the sort using the optional
3051
   *                        parameter sort_flags, for details
3052
   *                        see sort.
3053
   *                        </p>
3054
   *
3055
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3056
   */
3057 4
  public function rsort(int $sort_flags = 0)
3058
  {
3059 4
    \rsort($this->array, $sort_flags);
3060
3061 4
    return $this;
3062
  }
3063
3064
  /**
3065
   * Search for the first index of the current array via $value.
3066
   *
3067
   * @param mixed $value
3068
   *
3069
   * @return int|float|string
3070
   */
3071 20
  public function searchIndex($value)
3072
  {
3073 20
    return \array_search($value, $this->array, true);
3074
  }
3075
3076
  /**
3077
   * Search for the value of the current array via $index.
3078
   *
3079
   * @param mixed $index
3080
   *
3081
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
3082
   */
3083 9
  public function searchValue($index)
3084
  {
3085
    // init
3086 9
    $return = [];
3087
3088 9
    if ($this->isEmpty()) {
3089
      return static::create();
3090
    }
3091
3092
    // php cast "bool"-index into "int"-index
3093 9
    if ((bool)$index === $index) {
3094 1
      $index = (int)$index;
3095
    }
3096
3097 9
    if (\array_key_exists($index, $this->array) === true) {
3098 7
      $return = [$this->array[$index]];
3099
    }
3100
3101
3102 9
    return static::create($return);
3103
  }
3104
3105
  /**
3106
   * Set a value for the current array (optional using dot-notation).
3107
   *
3108
   * @param mixed $key   <p>The key to set.</p>
3109
   * @param mixed $value <p>Its value.</p>
3110
   *
3111
   * @return static <p>(Immutable)</p>
3112
   */
3113 17
  public function set($key, $value)
3114
  {
3115 17
    $this->internalSet($key, $value);
3116
3117 17
    return static::create($this->array);
3118
  }
3119
3120
  /**
3121
   * Get a value from a array and set it if it was not.
3122
   *
3123
   * WARNING: this method only set the value, if the $key is not already set
3124
   *
3125
   * @param mixed $key      <p>The key</p>
3126
   * @param mixed $fallback <p>The default value to set if it isn't.</p>
3127
   *
3128
   * @return mixed <p>(Mutable)</p>
3129
   */
3130 11
  public function setAndGet($key, $fallback = null)
3131
  {
3132
    // If the key doesn't exist, set it.
3133 11
    if (!$this->has($key)) {
3134 4
      $this->array = $this->set($key, $fallback)->getArray();
3135
    }
3136
3137 11
    return $this->get($key);
3138
  }
3139
3140
  /**
3141
   * Shifts a specified value off the beginning of array.
3142
   *
3143
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
3144
   */
3145 4
  public function shift()
3146
  {
3147 4
    return \array_shift($this->array);
3148
  }
3149
3150
  /**
3151
   * Shuffle the current array.
3152
   *
3153
   * @param bool  $secure <p>using a CSPRNG | @link https://paragonie.com/b/JvICXzh_jhLyt4y3</p>
3154
   * @param array $array  [optional]
3155
   *
3156
   * @return static <p>(Immutable)</p>
3157
   */
3158 1
  public function shuffle(bool $secure = false, array $array = null)
3159
  {
3160 1
    if ($array === null) {
3161 1
      $array = $this->array;
3162
    }
3163
3164 1
    if ($secure !== true) {
3165 1
      \shuffle($array);
3166
    } else {
3167 1
      $size = \count($array);
3168 1
      $keys = \array_keys($array);
3169 1
      for ($i = $size - 1; $i > 0; --$i) {
3170 1
        $r = \random_int(0, $i);
3171 1
        if ($r !== $i) {
3172
          $temp = $array[$keys[$r]];
3173
          $array[$keys[$r]] = $array[$keys[$i]];
3174
          $array[$keys[$i]] = $temp;
3175
        }
3176
      }
3177
3178
      // Reset indices
3179 1
      $array = \array_values($array);
3180
    }
3181
3182 1
    foreach ($array as $key => $value) {
3183
      // recursive needed?
3184 1
      if (\is_array($value) === true) {
3185 1
        $array[$key] = $this->shuffle($secure, $value);
3186
      }
3187
    }
3188
3189 1
    return static::create($array);
3190
  }
3191
3192
  /**
3193
   * Counts all elements in an array, or something in an object.
3194
   * <p>For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3195
   * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3196
   * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3197
   * implemented and used in PHP.
3198
   *
3199
   * @return int the number of elements in var, which is
3200
   * typically an array, since anything else will have one
3201
   * element.
3202
   * </p>
3203
   * <p>
3204
   * If var is not an array or an object with
3205
   * implemented Countable interface,
3206
   * 1 will be returned.
3207
   * There is one exception, if var is &null;,
3208
   * 0 will be returned.
3209
   * </p>
3210
   * <p>
3211
   * Caution: count may return 0 for a variable that isn't set,
3212
   * but it may also return 0 for a variable that has been initialized with an
3213
   * empty array. Use isset to test if a variable is set.
3214
   *
3215
   * @return int
3216
   */
3217 10
  public function sizeRecursive(): int
3218
  {
3219 10
    return \count($this->array, COUNT_RECURSIVE);
3220
  }
3221
3222
  /**
3223
   * Counts all elements in an array, or something in an object.
3224
   * <p>For objects, if you have SPL installed, you can hook into count() by implementing interface {@see Countable}.
3225
   * The interface has exactly one method, {@see Countable::count()}, which returns the return value for the count()
3226
   * function. Please see the {@see Array} section of the manual for a detailed explanation of how arrays are
3227
   * implemented and used in PHP.
3228
   *
3229
   * @link http://php.net/manual/en/function.count.php
3230
   *
3231
   * @param int $mode [optional] If the optional mode parameter is set to
3232
   *                  COUNT_RECURSIVE (or 1), count
3233
   *                  will recursively count the array. This is particularly useful for
3234
   *                  counting all the elements of a multidimensional array. count does not detect infinite recursion.
3235
   *
3236
   * @return int the number of elements in var, which is
3237
   * typically an array, since anything else will have one
3238
   * element.
3239
   * </p>
3240
   * <p>
3241
   * If var is not an array or an object with
3242
   * implemented Countable interface,
3243
   * 1 will be returned.
3244
   * There is one exception, if var is &null;,
3245
   * 0 will be returned.
3246
   * </p>
3247
   * <p>
3248
   * Caution: count may return 0 for a variable that isn't set,
3249
   * but it may also return 0 for a variable that has been initialized with an
3250
   * empty array. Use isset to test if a variable is set.
3251
   *
3252
   * @return int
3253
   */
3254 104
  public function size(int $mode = COUNT_NORMAL): int
3255
  {
3256 104
    return \count($this->array, $mode);
3257
  }
3258
3259
  /**
3260
   * Extract a slice of the array.
3261
   *
3262
   * @param int      $offset       <p>Slice begin index.</p>
3263
   * @param int|null $length       <p>Length of the slice.</p>
3264
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
3265
   *
3266
   * @return static <p>A slice of the original array with length $length.</p>
3267
   */
3268 4
  public function slice(int $offset, int $length = null, bool $preserveKeys = false)
3269
  {
3270 4
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
3271
3272 4
    return static::create($result);
3273
  }
3274
3275
  /**
3276
   * Sort the current array and optional you can keep the keys.
3277
   *
3278
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3279
   * @param int        $strategy  <p>sort_flags => use e.g.: <strong>SORT_REGULAR</strong> (default) or
3280
   *                              <strong>SORT_NATURAL</strong></p>
3281
   * @param bool       $keepKeys
3282
   *
3283
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3284
   */
3285 19
  public function sort($direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3286
  {
3287 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
3288
3289 19
    return $this;
3290
  }
3291
3292
  /**
3293
   * Sort the current array by key.
3294
   *
3295
   * @link http://php.net/manual/en/function.ksort.php
3296
   * @link http://php.net/manual/en/function.krsort.php
3297
   *
3298
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3299
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3300
   *                              <strong>SORT_NATURAL</strong></p>
3301
   *
3302
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3303
   */
3304 18
  public function sortKeys($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3305
  {
3306 18
    $this->sorterKeys($this->array, $direction, $strategy);
3307
3308 18
    return $this;
3309
  }
3310
3311
  /**
3312
   * Sort the current array by value.
3313
   *
3314
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3315
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3316
   *                              <strong>SORT_NATURAL</strong></p>
3317
   *
3318
   * @return static <p>(Mutable)</p>
3319
   */
3320 1
  public function sortValueKeepIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3321
  {
3322 1
    return $this->sort($direction, $strategy, true);
3323
  }
3324
3325
  /**
3326
   * Sort the current array by value.
3327
   *
3328
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3329
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3330
   *                              <strong>SORT_NATURAL</strong></p>
3331
   *
3332
   * @return static <p>(Mutable)</p>
3333
   */
3334 1
  public function sortValueNewIndex($direction = SORT_ASC, int $strategy = SORT_REGULAR)
3335
  {
3336 1
    return $this->sort($direction, $strategy, false);
3337
  }
3338
3339
  /**
3340
   * Sort a array by value, by a closure or by a property.
3341
   *
3342
   * - If the sorter is null, the array is sorted naturally.
3343
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
3344
   *
3345
   * @param \callable|null $sorter
3346
   * @param string|int     $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3347
   * @param int            $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3348
   *                                  <strong>SORT_NATURAL</strong></p>
3349
   *
3350
   * @return static <p>(Immutable)</p>
3351
   */
3352 1
  public function sorter($sorter = null, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3353
  {
3354 1
    $array = (array)$this->array;
3355 1
    $direction = $this->getDirection($direction);
3356
3357
    // Transform all values into their results.
3358 1
    if ($sorter) {
3359 1
      $arrayy = static::create($array);
3360
3361 1
      $that = $this;
3362 1
      $results = $arrayy->each(
3363 1
          function ($value) use ($sorter, $that) {
3364 1
            return \is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
3365 1
          }
3366
      );
3367
3368 1
      $results = $results->getArray();
3369
    } else {
3370 1
      $results = $array;
3371
    }
3372
3373
    // Sort by the results and replace by original values
3374 1
    \array_multisort($results, $direction, $strategy, $array);
3375
3376 1
    return static::create($array);
3377
  }
3378
3379
  /**
3380
   * sorting keys
3381
   *
3382
   * @param array      $elements
3383
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3384
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3385
   *                              <strong>SORT_NATURAL</strong></p>
3386
   *
3387
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3388
   */
3389 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR)
3390
  {
3391 18
    $direction = $this->getDirection($direction);
3392
3393
    switch ($direction) {
3394 18
      case 'desc':
3395 18
      case SORT_DESC:
3396 6
        \krsort($elements, $strategy);
3397 6
        break;
3398 13
      case 'asc':
3399 13
      case SORT_ASC:
3400
      default:
3401 13
        \ksort($elements, $strategy);
3402
    }
3403
3404 18
    return $this;
3405
  }
3406
3407
  /**
3408
   * @param array      &$elements
3409
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
3410
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
3411
   *                              <strong>SORT_NATURAL</strong></p>
3412
   * @param bool       $keepKeys
3413
   *
3414
   * @return static <p>(Mutable) Return this Arrayy object.</p>
3415
   */
3416 19
  protected function sorting(array &$elements, $direction = SORT_ASC, int $strategy = SORT_REGULAR, bool $keepKeys = false)
3417
  {
3418 19
    $direction = $this->getDirection($direction);
3419
3420 19
    if (!$strategy) {
3421 19
      $strategy = SORT_REGULAR;
3422
    }
3423
3424
    switch ($direction) {
3425 19
      case 'desc':
3426 19
      case SORT_DESC:
3427 9
        if ($keepKeys) {
3428 5
          arsort($elements, $strategy);
3429
        } else {
3430 4
          \rsort($elements, $strategy);
3431
        }
3432 9
        break;
3433 10
      case 'asc':
3434 10
      case SORT_ASC:
3435
      default:
3436 10
        if ($keepKeys) {
3437 4
          \asort($elements, $strategy);
3438
        } else {
3439 6
          \sort($elements, $strategy);
3440
        }
3441
    }
3442
3443 19
    return $this;
3444
  }
3445
3446
  /**
3447
   * Split an array in the given amount of pieces.
3448
   *
3449
   * @param int  $numberOfPieces
3450
   * @param bool $keepKeys
3451
   *
3452
   * @return static <p>(Immutable)</p>
3453
   */
3454 1
  public function split(int $numberOfPieces = 2, bool $keepKeys = false)
3455
  {
3456 1
    $arrayCount = $this->count();
3457
3458 1
    if ($arrayCount === 0) {
3459 1
      $result = [];
3460
    } else {
3461 1
      $splitSize = (int)\ceil($arrayCount / $numberOfPieces);
3462 1
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
3463
    }
3464
3465 1
    return static::create($result);
3466
  }
3467
3468
  /**
3469
   * Stripe all empty items.
3470
   *
3471
   * @return static <p>(Immutable)</p>
3472
   */
3473 1
  public function stripEmpty()
3474
  {
3475 1
    return $this->filter(
3476 1
        function ($item) {
3477 1
          if ($item === null) {
3478 1
            return false;
3479
          }
3480
3481 1
          return (bool)\trim((string)$item);
3482 1
        }
3483
    );
3484
  }
3485
3486
  /**
3487
   * Swap two values between positions by key.
3488
   *
3489
   * @param string|int $swapA <p>a key in the array</p>
3490
   * @param string|int $swapB <p>a key in the array</p>
3491
   *
3492
   * @return static <p>(Immutable)</p>
3493
   */
3494 1
  public function swap($swapA, $swapB)
3495
  {
3496 1
    $array = $this->array;
3497
3498 1
    list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
3499
3500 1
    return static::create($array);
3501
  }
3502
3503
  /**
3504
   * alias: for "Arrayy->getArray()"
3505
   *
3506
   * @see Arrayy::getArray()
3507
   */
3508 186
  public function toArray()
3509
  {
3510 186
    return $this->getArray();
3511
  }
3512
3513
  /**
3514
   * Convert the current array to JSON.
3515
   *
3516
   * @param int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
3517
   * @param int $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
3518
   *
3519
   * @return string
3520
   */
3521 6
  public function toJson(int $options = 0, int $depth = 512): string
3522
  {
3523 6
    return UTF8::json_encode($this->array, $options, $depth);
3524
  }
3525
3526
  /**
3527
   * Implodes array to a string with specified separator.
3528
   *
3529
   * @param string $separator [optional] <p>The element's separator.</p>
3530
   *
3531
   * @return string <p>The string representation of array, separated by ",".</p>
3532
   */
3533 19
  public function toString(string $separator = ','): string
3534
  {
3535 19
    return $this->implode($separator);
3536
  }
3537
3538
  /**
3539
   * Return a duplicate free copy of the current array.
3540
   *
3541
   * @return static <p>(Mutable)</p>
3542
   */
3543 9
  public function unique()
3544
  {
3545
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3546
3547 9
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce($this->arr...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...
3548 9
        $this->array,
3549 9
        function ($resultArray, $value) {
3550 8
          if (!\in_array($value, $resultArray, true)) {
3551 8
            $resultArray[] = $value;
3552
          }
3553
3554 8
          return $resultArray;
3555 9
        },
3556 9
        []
3557
    );
3558
3559 9 View Code Duplication
    if ($this->array === 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...
3560
      $this->array = [];
3561
    } else {
3562 9
      $this->array = (array)$this->array;
3563
    }
3564
3565 9
    return $this;
3566
  }
3567
3568
  /**
3569
   * Return a duplicate free copy of the current array. (with the old keys)
3570
   *
3571
   * @return static <p>(Mutable)</p>
3572
   */
3573 9
  public function uniqueKeepIndex()
3574
  {
3575
    // INFO: \array_unique() can't handle e.g. "stdClass"-values in an array
3576
3577
    // init
3578 9
    $array = $this->array;
3579
3580 9
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce(\array_key...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...
3581 9
        \array_keys($array),
3582 9
        function ($resultArray, $key) use ($array) {
3583 8
          if (!\in_array($array[$key], $resultArray, true)) {
3584 8
            $resultArray[$key] = $array[$key];
3585
          }
3586
3587 8
          return $resultArray;
3588 9
        },
3589 9
        []
3590
    );
3591
3592 9 View Code Duplication
    if ($this->array === 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...
3593
      $this->array = [];
3594
    } else {
3595 9
      $this->array = (array)$this->array;
3596
    }
3597
3598 9
    return $this;
3599
  }
3600
3601
  /**
3602
   * alias: for "Arrayy->unique()"
3603
   *
3604
   * @see Arrayy::unique()
3605
   *
3606
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
3607
   */
3608 9
  public function uniqueNewIndex()
3609
  {
3610 9
    return $this->unique();
3611
  }
3612
3613
  /**
3614
   * Prepends one or more values to the beginning of array at once.
3615
   *
3616
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3617
   */
3618 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...
3619
  {
3620 4
    if (\func_num_args()) {
3621 4
      $args = \array_merge([&$this->array], \func_get_args());
3622 4
      \array_unshift(...$args);
3623
    }
3624
3625 4
    return $this;
3626
  }
3627
3628
  /**
3629
   * Get all values from a array.
3630
   *
3631
   * @return static <p>(Immutable)</p>
3632
   */
3633 2
  public function values()
3634
  {
3635 2
    return static::create(\array_values((array)$this->array));
3636
  }
3637
3638
  /**
3639
   * Apply the given function to every element in the array, discarding the results.
3640
   *
3641
   * @param \callable $callable
3642
   * @param bool      $recursive <p>Whether array will be walked recursively or no</p>
3643
   *
3644
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3645
   */
3646 35
  public function walk($callable, bool $recursive = false)
3647
  {
3648 35
    if (true === $recursive) {
3649 30
      \array_walk_recursive($this->array, $callable);
3650
    } else {
3651 18
      \array_walk($this->array, $callable);
3652
    }
3653
3654 35
    return $this;
3655
  }
3656
}
3657