Completed
Push — master ( ed33b0...7335c0 )
by Bocharsky
04:31
created

AbstractArray   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 628
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 33
Bugs 4 Features 10
Metric Value
wmc 45
c 33
b 4
f 10
lcom 2
cbo 5
dl 0
loc 628
ccs 109
cts 109
cp 1
rs 8.2788

47 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
chunk() 0 1 ?
clear() 0 1 ?
combineTo() 0 1 ?
combineWith() 0 1 ?
diffWith() 0 1 ?
filter() 0 1 ?
flip() 0 1 ?
map() 0 1 ?
mergeTo() 0 1 ?
mergeWith() 0 1 ?
pad() 0 1 ?
reindex() 0 1 ?
replaceIn() 0 1 ?
replaceWith() 0 1 ?
reverse() 0 1 ?
shuffle() 0 1 ?
slice() 0 1 ?
unique() 0 1 ?
walk() 0 1 ?
A create() 0 4 1
A createFromJson() 0 4 1
A createFromObject() 0 10 2
A createFromString() 0 4 1
A createWithRange() 0 4 1
A contains() 0 4 1
A containsKey() 0 4 1
A count() 0 4 1
A createClone() 0 4 1
A exists() 0 13 3
A find() 0 13 3
A getIterator() 0 4 1
A getKeys() 0 4 1
A getRandom() 0 4 1
A getRandomKey() 0 4 1
A getRandomKeys() 0 15 3
A getRandomValues() 0 11 3
A getValues() 0 4 1
A indexOf() 0 4 1
A isAssoc() 0 17 4
A isEmpty() 0 4 1
A isNumeric() 0 17 4
A offsetExists() 0 4 1
A offsetGet() 0 7 2
A offsetSet() 0 10 2
A offsetUnset() 0 6 1
A reduce() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractArray 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 AbstractArray, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Arrayzy;
4
5
use Arrayzy\Interfaces\ConvertibleInterface;
6
use Arrayzy\Interfaces\DebuggableInterface;
7
use Arrayzy\Interfaces\DoubleEndedQueueInterface;
8
use Arrayzy\Interfaces\SortableInterface;
9
use Arrayzy\Interfaces\TraversableInterface;
10
use Arrayzy\Traits\ConvertibleTrait;
11
use Arrayzy\Traits\DebuggableTrait;
12
use Arrayzy\Traits\DoubleEndedQueueTrait;
13
use Arrayzy\Traits\SortableTrait;
14
use Arrayzy\Traits\TraversableTrait;
15
use ArrayAccess;
16
use ArrayIterator;
17
use Countable;
18
use IteratorAggregate;
19
use Traversable;
20
21
/**
22
 * Defines common methods and method signatures.
23
 *
24
 * @author Victor Bocharsky <[email protected]>
25
 */
26
abstract class AbstractArray implements
27
    ArrayAccess,
28
    ConvertibleInterface,
29
    Countable,
30
    DebuggableInterface,
31
    DoubleEndedQueueInterface,
32
    IteratorAggregate,
33
    SortableInterface,
34
    TraversableInterface
35
{
36
    use ConvertibleTrait;
37
38
    use DebuggableTrait;
39
40
    use DoubleEndedQueueTrait;
41
42
    use SortableTrait;
43
44
    use TraversableTrait;
45
46
    /**
47
     * @const string
48
     */
49
    const DEFAULT_SEPARATOR = ', ';
50
51
    /**
52
     * @var array
53
     */
54
    protected $elements = [];
55
56
    /**
57
     * Construct new instance
58
     *
59
     * @param array $elements
60
     */
61 306
    public function __construct(array $elements = [])
62
    {
63 306
        $this->elements = $elements;
64 306
    }
65
66
    // The abstract public method list order by ASC
67
68
    /**
69
     * Split array into chunks.
70
     *
71
     * @param int $size Size of each chunk
72
     * @param bool $preserveKeys Whether array keys are preserved or no
73
     *
74
     * @return static An array of chunks from the original array
75
     */
76
    abstract public function chunk($size, $preserveKeys = false);
77
78
    /**
79
     * Clear array
80
     *
81
     * @return static An empty array.
82
     */
83
    abstract public function clear();
84
85
    /**
86
     * Create an array using this array as values and the other array as keys.
87
     *
88
     * @param array $array Key array
89
     *
90
     * @return static An array with keys from the other.
91
     */
92
    abstract public function combineTo(array $array);
93
94
    /**
95
     * Create an array using this array as keys and the other array as values.
96
     *
97
     * @param array $array Values array
98
     *
99
     * @return static An array with values from the other array
100
     */
101
    abstract public function combineWith(array $array);
102
103
    /**
104
     * Compute the array of values not present in the other array.
105
     *
106
     * @param array $array Array for diff
107
     *
108
     * @return static An array containing all the entries from this array that are not present in $array
109
     */
110
    abstract public function diffWith(array $array);
111
112
    /**
113
     * Filter the array for elements satisfying the predicate $func.
114
     *
115
     * @param callable $func
116
     *
117
     * @return static An array with only element satisfying $func
118
     */
119
    abstract public function filter(callable $func);
120
121
    /**
122
     * Exchanges all array keys with their associated values.
123
     *
124
     * @return static An array with flipped elements
125
     */
126
    abstract public function flip();
127
128
    /**
129
     * Apply the given function to the every element of the array, collecting the results.
130
     *
131
     * @param callable $func
132
     *
133
     * @return static An array with modified elements
134
     */
135
    abstract public function map(callable $func);
136
137
    /**
138
     * Merges array with the provided one. This array is overwriting.
139
     *
140
     * @param array $array Array to merge with (is overwritten)
141
     * @param bool $recursively Whether array will be merged recursively or no
142
     *
143
     * @return static An array with the keys/values from $array added, that weren't present in the original
144
     */
145
    abstract public function mergeTo(array $array, $recursively = false);
146
147
    /**
148
     * Merges this array with the provided one. Latter array is overwriting.
149
     *
150
     * @param array $array Array to merge with (overwrites)
151
     * @param bool $recursively Whether array will be merged recursively or no
152
     *
153
     * @return static An array with the keys/values from $array added
154
     */
155
    abstract public function mergeWith(array $array, $recursively = false);
156
157
    /**
158
     * Pad array to the specified size with a given value.
159
     *
160
     * @param int $size Size of the result array
161
     * @param mixed $value Empty value by default
162
     *
163
     * @return static An array padded to $size with $value
164
     */
165
    abstract public function pad($size, $value);
166
167
    /**
168
     * Reindex the array numerically.
169
     *
170
     * @return $this An array with numerically-indexed elements
171
     */
172
    abstract public function reindex();
173
174
    /**
175
     * Replace the entire array with the other one except keys present in both.
176
     * For keys present in both arrays the value from this array will be used.
177
     *
178
     * @param array $array Array to replace with
179
     * @param bool $recursively Whether array will be replaced recursively or no
180
     *
181
     * @return static An array with keys from $array and values from both.
182
     */
183
    abstract public function replaceIn(array $array, $recursively = false);
184
185
    /**
186
     * Replace values in this array with values in the other array that have the
187
     * same key.
188
     *
189
     * @param array $array Array of replacing values
190
     * @param bool $recursively Whether array will be replaced recursively or no
191
     *
192
     * @return static An array with the same keys but new values
193
     */
194
    abstract public function replaceWith(array $array, $recursively = false);
195
196
    /**
197
     * Reverse the order of the array values.
198
     *
199
     * @param bool $preserveKeys Whether array keys are preserved or no
200
     *
201
     * @return $this An array with the order of the elements reversed
202
     */
203
    abstract public function reverse($preserveKeys = false);
204
205
    /**
206
     * Randomize element order.
207
     *
208
     * @return static An array with the elemant order shuffled
209
     */
210
    abstract public function shuffle();
211
212
    /**
213
     * Extract a slice of the array.
214
     *
215
     * @param int $offset Slice begin index
216
     * @param int|null $length Length of the slice
217
     * @param bool $preserveKeys Whether array keys are preserved or no
218
     *
219
     * @return static A slice of the original array with length $length
220
     */
221
    abstract public function slice($offset, $length = null, $preserveKeys = false);
222
223
    /**
224
     * Removes duplicate values from the array.
225
     *
226
     * @param int|null $sortFlags
227
     *
228
     * @return static An array with only unique elements
229
     */
230
    abstract public function unique($sortFlags = null);
231
232
    /**
233
     * Apply the given function to every element in the array, discarding the results.
234
     *
235
     * @param callable $func
236
     * @param bool $recursively Whether array will be walked recursively or no
237
     *
238
     * @return static The original array with potentially modified elements.
239
     */
240
    abstract public function walk(callable $func, $recursively = false);
241
242
    // The public static method list order by ASC
243
244
    /**
245
     * Create a new instance.
246
     *
247
     * @param array $elements
248
     *
249
     * @return static Returns created instance
250
     */
251 19
    public static function create(array $elements = [])
252
    {
253 19
        return new static($elements);
254
    }
255
256
    /**
257
     * Decode a JSON string to new instance.
258
     *
259
     * @param string $json The JSON string being decoded
260
     * @param int $options Bitmask of JSON decode options
261
     * @param int $depth Specified recursion depth
262
     *
263
     * @return static The created array
264
     */
265 8
    public static function createFromJson($json, $options = 0, $depth = 512)
266
    {
267 8
        return new static(json_decode($json, true, $depth, $options));
268
    }
269
270
    /**
271
     * Create a new instance filled with values from an object implementing ArrayAccess.
272
     *
273
     * @param ArrayAccess $elements Object that implements ArrayAccess
274
     *
275
     * @return static Returns created instance
276
     */
277 8
    public static function createFromObject(ArrayAccess $elements)
278
    {
279 8
        $array = new static();
280
281 8
        foreach ($elements as $key => $value) {
282 6
            $array[$key] = $value;
283 8
        }
284
285 8
        return $array;
286
    }
287
288
    /**
289
     * Explode a string to new instance by specified separator.
290
     *
291
     * @param string $string Converted string
292
     * @param string $separator Element's separator
293
     *
294
     * @return static The created array
295
     */
296 6
    public static function createFromString($string, $separator)
297
    {
298 6
        return new static(explode($separator, $string));
299
    }
300
301
    /**
302
     * Create a new instance containing a range of elements.
303
     *
304
     * @param mixed $low First value of the sequence
305
     * @param mixed $high The sequence is ended upon reaching the end value
306
     * @param int $step Used as the increment between elements in the sequence
307
     *
308
     * @return static The created array
309
     */
310 1
    public static function createWithRange($low, $high, $step = 1)
311
    {
312 1
        return new static(range($low, $high, $step));
313
    }
314
315
    // The public method list order by ASC
316
317
    /**
318
     * Check if the given value exists in the array.
319
     *
320
     * @param mixed $element Value to search for
321
     *
322
     * @return bool Returns true if the given value exists in the array, false otherwise
323
     */
324 4
    public function contains($element)
325
    {
326 4
        return in_array($element, $this->elements, true);
327
    }
328
329
    /**
330
     * Check if the given key/index exists in the array.
331
     *
332
     * @param mixed $key Key/index to search for
333
     *
334
     * @return bool Returns true if the given key/index exists in the array, false otherwise
335
     */
336 4
    public function containsKey($key)
337
    {
338 4
        return array_key_exists($key, $this->elements);
339
    }
340
341
    /**
342
     * Returns the number of values in the array.
343
     *
344
     * @link http://php.net/manual/en/function.count.php
345
     *
346
     * @return int total number of values
347
     */
348 25
    public function count()
349
    {
350 25
        return count($this->elements);
351
    }
352
353
    /**
354
     * Clone current instance to new instance.
355
     *
356
     * @deprecated Should be removed
357
     *
358
     * @return $this Shallow copy of $this
359
     */
360
    public function createClone()
361
    {
362
        return clone $this;
363
    }
364
365
    /**
366
     * Find the given value in the array using a closure
367
     *
368
     * @param callable $func
369
     *
370
     * @return bool Returns true if the given value is found, false otherwise
371
     */
372 4
    public function exists(callable $func)
373
    {
374 4
        $isExists = false;
375
376 4
        foreach ($this->elements as $key => $value) {
377 3
            if ($func($key, $value)) {
378 1
                $isExists = true;
379 1
                break;
380
            }
381 4
        }
382
383 4
        return $isExists;
384
    }
385
386
    /**
387
     * Returns the first occurrence of a value that satisfies the predicate $func.
388
     *
389
     * @param callable $func
390
     *
391
     * @return mixed The first occurrence found
392
     */
393 1
    public function find(callable $func)
394
    {
395 1
        $found = null;
396
397 1
        foreach ($this->elements as $key => $value) {
398 1
            if($func($value, $key)) {
399 1
                $found = $value;
400 1
                break;
401
            }
402 1
        }
403
404 1
        return $found;
405
    }
406
407
    /**
408
     * Create an iterator over this array.
409
     *
410
     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
411
     *
412
     * @return Traversable An instance of an object implementing <b>Iterator</b>
413
     */
414 9
    public function getIterator()
415
    {
416 9
        return new ArrayIterator($this->elements);
417
    }
418
419
    /**
420
     * Return an array all the keys of this array.
421
     *
422
     * @return array An array of all keys
423
     */
424 10
    public function getKeys()
425
    {
426 10
        return array_keys($this->elements);
427
    }
428
429
    /**
430
     * Pick a random value out of this array.
431
     *
432
     * @return mixed Random value of array
433
     *
434
     * @throws \RangeException If array is empty
435
     */
436 3
    public function getRandom()
437
    {
438 3
        return $this->offsetGet($this->getRandomKey());
439
    }
440
441
    /**
442
     * Pick a random key/index from the keys of this array.
443
     *
444
     * @return mixed Random key/index of array
445
     *
446
     * @throws \RangeException If array is empty
447
     */
448 6
    public function getRandomKey()
449
    {
450 6
        return $this->getRandomKeys(1);
451
    }
452
453
    /**
454
     * Pick a given number of random keys/indexes out of this array.
455
     *
456
     * @param int $number The number of keys/indexes (should be <= $this->count())
457
     *
458
     * @return mixed Random keys or key of array
459
     *
460
     * @throws \RangeException
461
     */
462 21
    public function getRandomKeys($number)
463
    {
464 21
        $number = (int) $number;
465
466 21
        $count = $this->count();
467 21
        if ($number === 0 || $number > $count) {
468 3
            throw new \RangeException(sprintf(
469 3
                'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
470 3
                $number,
471
                $count
472 3
            ));
473
        }
474
475 18
        return array_rand($this->elements, $number);
476
    }
477
478
    /**
479
     * Pick a given number of random values with non-duplicate indexes out of the array.
480
     *
481
     * @param int $number The number of values (should be > 1 and < $this->count())
482
     *
483
     * @return array Random values of array
484
     *
485
     * @throws \RangeException
486
     */
487 6
    public function getRandomValues($number)
488
    {
489 6
        $values = [];
490
491 6
        $keys = $number > 1 ? $this->getRandomKeys($number) : [$this->getRandomKeys($number)];
492 6
        foreach ($keys as $key) {
493 6
            $values[] = $this->offsetGet($key);
494 6
        }
495
496 6
        return $values;
497
    }
498
499
    /**
500
     * Return an array of all values from this array numerically indexed.
501
     *
502
     * @return mixed An array of all values
503
     */
504 4
    public function getValues()
505
    {
506 4
        return array_values($this->elements);
507
    }
508
509
    /**
510
     * Search for a given element and return the index of its first occurrence.
511
     *
512
     * @param mixed $element Value to search for
513
     *
514
     * @return mixed The corresponding key/index
515
     */
516 4
    public function indexOf($element)
517
    {
518 4
        return array_search($element, $this->elements, true);
519
    }
520
521
    /**
522
     * Check whether array is associative or not.
523
     *
524
     * @return bool Returns true if associative, false otherwise
525
     */
526 4
    public function isAssoc()
527
    {
528 4
        $isAssoc = true;
529
530 4
        if ($this->isEmpty()) {
531 1
            $isAssoc = false;
532 1
        } else {
533 3
            foreach ($this->getKeys() as $key) {
534 3
                if (!is_string($key)) {
535 2
                    $isAssoc = false;
536 2
                    break;
537
                }
538 3
            }
539
        }
540
541 4
        return $isAssoc;
542
    }
543
544
    /**
545
     * Check whether the array is empty or not.
546
     *
547
     * @return bool Returns true if empty, false otherwise
548
     */
549 12
    public function isEmpty()
550
    {
551 12
        return !$this->elements;
552
    }
553
554
    /**
555
     * Check whether array is numeric or not.
556
     *
557
     * @return bool Returns true if numeric, false otherwise
558
     */
559 4
    public function isNumeric()
560
    {
561 4
        $isNumeric = true;
562
563 4
        if ($this->isEmpty()) {
564 1
            $isNumeric = false;
565 1
        } else {
566 3
            foreach ($this->getKeys() as $key) {
567 3
                if (!is_int($key)) {
568 2
                    $isNumeric = false;
569 2
                    break;
570
                }
571 3
            }
572
        }
573
574 4
        return $isNumeric;
575
    }
576
577
    /**
578
     * Whether an offset exists.
579
     *
580
     * @param mixed $offset An offset to check for.
581
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
582
     *
583
     * @return boolean true on success or false on failure.
584
     */
585 8
    public function offsetExists($offset)
586
    {
587 8
        return isset($this->elements[$offset]);
588
    }
589
590
    /**
591
     * Retrieve the current offset or null.
592
     *
593
     * @param mixed $offset The offset to retrieve.
594
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
595
     *
596
     * @return mixed Can return all value types.
597
     */
598 13
    public function offsetGet($offset)
599
    {
600 13
        return isset($this->elements[$offset])
601 13
            ? $this->elements[$offset]
602 11
            : null
603 13
        ;
604
    }
605
606
    /**
607
     * Set an offset for this array.
608
     *
609
     * @param mixed $offset The offset to assign the value to.
610
     * @param mixed $value The value to set.
611
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
612
     *
613
     * @return $this
614
     */
615 14
    public function offsetSet($offset, $value)
616
    {
617 14
        if (isset($offset)) {
618 10
            $this->elements[$offset] = $value;
619 10
        } else {
620 4
            $this->elements[] = $value;
621
        }
622
623 14
        return $this;
624
    }
625
626
    /**
627
     * Remove a present offset.
628
     *
629
     * @param mixed $offset The offset to unset.
630
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
631
     *
632
     * @return $this
633
     */
634 4
    public function offsetUnset($offset)
635
    {
636 4
        unset($this->elements[$offset]);
637
638 4
        return $this;
639
    }
640
641
    /**
642
     * Reduce the array to a single value iteratively combining all values using $func.
643
     *
644
     * @param callable $func callback ($carry, $item) -> next $carry
645
     * @param mixed|null $initial starting value of the $carry
646
     *
647
     * @return mixed Final value of $carry
648
     */
649 1
    public function reduce(callable $func, $initial = null)
650
    {
651 1
        return array_reduce($this->elements, $func, $initial);
652
    }
653
}
654