Passed
Push — 1.x ( 8f9a67...642986 )
by Ulises Jeremias
02:40
created

Sequenceable   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 255
rs 8.4864
c 0
b 0
f 0
wmc 48

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A first() 0 7 2
A copy() 0 3 1
A fromArray() 0 3 1
A get() 0 7 2
A contains() 0 9 3
A fromItems() 0 15 3
A insert() 0 4 3
A clear() 0 3 1
A setTraversable() 0 3 1
A getSize() 0 3 1
A push() 0 3 1
A offsetSet() 0 6 4
A offsetExists() 0 5 3
A next() 0 3 1
A toArray() 0 3 1
A getMainTraversable() 0 3 1
A setSize() 0 3 1
A offsetGet() 0 3 1
A rewind() 0 3 1
A last() 0 7 2
A validIndex() 0 3 2
A pushAll() 0 9 2
A valid() 0 3 1
A offsetUnset() 0 5 3
A pop() 0 12 2
A current() 0 3 1
A count() 0 3 1
A key() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Sequenceable 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.

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 Sequenceable, and based on these observations, apply Extract Interface, too.

1
<?php namespace Mbh\Collection\Traits;
2
3
use Mbh\Collection\Interfaces\Collection as CollectionInterface;
4
use Mbh\Collection\Interfaces\Sequenceable as SequenceableInterface;
5
use Mbh\Collection\FixedArray;
6
use Mbh\Collection\CallbackHeap;
7
use Mbh\Iterator\SliceIterator;
8
use Mbh\Iterator\ConcatIterator;
9
use SplFixedArray;
10
use SplHeap;
11
use SplStack;
12
use LimitIterator;
13
use Iterator;
14
use ArrayAccess;
15
use Countable;
16
use CallbackFilterIterator;
17
use JsonSerializable;
18
use RuntimeException;
19
use Traversable;
20
use ReflectionClass;
21
use UnderflowException;
22
use OutOfRangeException;
23
24
/**
25
 * MBHFramework
26
 *
27
 * @link      https://github.com/MBHFramework/mbh-framework
28
 * @copyright Copyright (c) 2017 Ulises Jeremias Cornejo Fandos
29
 * @license   https://github.com/MBHFramework/mbh-framework/blob/master/LICENSE (MIT License)
30
 */
31
32
trait Sequenceable
33
{
34
    protected $sfa = null;
35
36
    /**
37
     * Create an fixed array
38
     *
39
     * @param Traversable $array data
40
     */
41
    protected function __construct(Traversable $array)
42
    {
43
        $this->sfa = $array;
44
    }
45
46
    /**
47
     * @inheritDoc
48
     */
49
    public static function fromItems(Traversable $array)
50
    {
51
        // We can only do it this way if we can count it
52
        if ($array instanceof Countable) {
53
            $sfa = new SplFixedArray(count($array));
54
55
            foreach ($array as $i => $elem) {
56
                $sfa[$i] = $elem;
57
            }
58
59
            return new static($sfa);
60
        }
61
62
        // If we can't count it, it's simplest to iterate into an array first
63
        return static::fromArray(iterator_to_array($array));
64
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69
    public static function fromArray(array $array)
70
    {
71
        return new static(SplFixedArray::fromArray($array));
72
    }
73
74
    /**
75
     * @inheritDoc
76
     */
77
    public function contains(...$values): bool
78
    {
79
        foreach ($values as $value) {
80
            if (!$this->find($value)) {
0 ignored issues
show
Bug introduced by
It seems like find() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

80
            if (!$this->/** @scrutinizer ignore-call */ find($value)) {
Loading history...
81
                return false;
82
            }
83
        }
84
85
        return true;
86
    }
87
88
    /**
89
     * @inheritDoc
90
     */
91
    public function copy()
92
    {
93
        return static::fromArray($this->toArray());
94
    }
95
96
    /**
97
    * @inheritDoc
98
    */
99
    public function first()
100
    {
101
        if ($this->isEmpty()) {
0 ignored issues
show
Bug introduced by
It seems like isEmpty() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
        if ($this->/** @scrutinizer ignore-call */ isEmpty()) {
Loading history...
102
            throw new UnderflowException();
103
        }
104
105
        return $this[0];
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111
    public function get(int $index)
112
    {
113
        if (! $this->validIndex($index)) {
114
            throw new OutOfRangeException();
115
        }
116
117
        return $this[$index];
118
    }
119
120
    /**
121
     * @inheritDoc
122
     */
123
    public function insert(int $index, ...$values)
0 ignored issues
show
Unused Code introduced by
The parameter $values is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

123
    public function insert(int $index, /** @scrutinizer ignore-unused */ ...$values)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
124
    {
125
        if (! $this->validIndex($index) && $index !== count($this)) {
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

125
        if (! $this->validIndex($index) && $index !== count(/** @scrutinizer ignore-type */ $this)) {
Loading history...
126
            throw new OutOfRangeException();
127
        }
128
129
        // array_splice($this->array, $index, 0, $values);
130
    }
131
132
    /**
133
     * @inheritDoc
134
     */
135
    public function last()
136
    {
137
        if ($this->isEmpty()) {
138
            throw new UnderflowException();
139
        }
140
141
        return $this[count($this) - 1];
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
        return $this[count(/** @scrutinizer ignore-type */ $this) - 1];
Loading history...
142
    }
143
144
    /**
145
     * @inheritDoc
146
     */
147
    public function pop()
148
    {
149
        if ($this->isEmpty()) {
150
            throw new UnderflowException();
151
        }
152
153
        $value = $this->last();
154
        unset($this[count($this) - 1]);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

154
        unset($this[count(/** @scrutinizer ignore-type */ $this) - 1]);
Loading history...
155
156
        $this->checkCapacity();
157
158
        return $value;
159
    }
160
161
162
    /**
163
     * Pushes all values of either an array or traversable object.
164
     */
165
    private function pushAll($values)
166
    {
167
        foreach ($values as $value) {
168
            $size = $this->getSize();
169
            $this->setSize($size + 1);
170
            $this[$size] = $value;
171
        }
172
173
        $this->checkCapacity();
174
    }
175
176
    /**
177
     * @inheritDoc
178
     */
179
    public function push(...$values)
180
    {
181
        $this->pushAll($values);
182
    }
183
184
    public function toArray(): array
185
    {
186
        return $this->sfa->toArray();
187
    }
188
189
    protected function validIndex(int $index)
190
    {
191
        return $index >= 0 && $index < $this->getSize();
192
    }
193
194
    /**
195
     * Countable
196
     */
197
    public function count(): int
198
    {
199
        return count($this->sfa);
200
    }
201
202
    /**
203
     * Iterator
204
     */
205
    public function current()
206
    {
207
        return $this->sfa->current();
208
    }
209
210
    public function key(): int
211
    {
212
        return $this->sfa->key();
213
    }
214
215
    public function next()
216
    {
217
        return $this->sfa->next();
218
    }
219
220
    public function rewind()
221
    {
222
        return $this->sfa->rewind();
223
    }
224
225
    public function valid()
226
    {
227
        return $this->sfa->valid();
228
    }
229
230
    /**
231
     * ArrayAccess
232
     */
233
    public function offsetExists($offset): bool
234
    {
235
        return is_integer($offset)
236
            && $this->validIndex($offset)
237
            && $this->sfa->offsetExists($offset);
238
    }
239
240
    public function offsetGet($offset)
241
    {
242
        return $this->sfa->offsetGet($offset);
243
    }
244
245
    public function offsetSet($offset, $value)
246
    {
247
        if ($offset === null) {
248
            $this->push($value);
249
        } elseif (is_integer($offset) && $this->validIndex($offset)) {
250
            $this->sfa->offsetSet($offset, $value);
251
        }
252
    }
253
254
    public function offsetUnset($offset)
255
    {
256
        return is_integer($offset)
257
            && $this->validIndex($offset)
258
            && $this->sfa->offsetUnset($offset);
259
    }
260
261
    public function clear()
262
    {
263
        return $this->sfa->clear();
264
    }
265
266
    protected function getMainTraversable(): Traversable
267
    {
268
        return $this->sfa;
269
    }
270
271
    protected function setTraversable(Traversable $traversable)
272
    {
273
        $this->sfa = $traversable;
274
    }
275
276
    public function getSize(): int
277
    {
278
        return $this->sfa->getSize();
279
    }
280
281
    public function setSize(int $size): bool
282
    {
283
        return $this->sfa->setSize($size);
284
    }
285
286
    abstract protected function checkCapacity();
287
}
288