Passed
Push — 1.x ( d37098...e1cf36 )
by Ulises Jeremias
02:30
created

Sequenceable   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 278
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 278
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 get() 0 7 2
A contains() 0 9 3
A fromArray() 0 3 1
A fromItems() 0 15 3
A insert() 0 11 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 10 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 fromArray(array $array)
50
    {
51
        return new static(SplFixedArray::fromArray($array));
52
    }
53
54
    /**
55
     * @inheritDoc
56
     */
57
    public static function fromItems(Traversable $array)
58
    {
59
        // We can only do it this way if we can count it
60
        if ($array instanceof Countable) {
61
            $sfa = new SplFixedArray(count($array));
62
63
            foreach ($array as $i => $elem) {
64
                $sfa[$i] = $elem;
65
            }
66
67
            return new static($sfa);
68
        }
69
70
        // If we can't count it, it's simplest to iterate into an array first
71
        return static::fromArray(iterator_to_array($array));
72
    }
73
74
    /**
75
     * @inheritDoc
76
     */
77
    public function contains(...$values): bool
78
    {
79
        foreach ($values as $value) {
80
            if (!$this->find($value)) {
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()) {
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)
124
    {
125
        if (!$this->validIndex($index) && $index !== $this->count()) {
126
            throw new OutOfRangeException();
127
        }
128
129
        $slice = $this->slice($index, $this->count());
0 ignored issues
show
Bug introduced by
It seems like slice() 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

129
        /** @scrutinizer ignore-call */ 
130
        $slice = $this->slice($index, $this->count());
Loading history...
130
        $this->setSize($index);
131
132
        $this->pushAll($values);
133
        $this->pushAll($slice);
134
    }
135
136
    /**
137
     * @inheritDoc
138
     */
139
    public function last()
140
    {
141
        if ($this->isEmpty()) {
142
            throw new UnderflowException();
143
        }
144
145
        return $this[$this->count() - 1];
146
    }
147
148
    /**
149
     * @inheritDoc
150
     */
151
    public function pop()
152
    {
153
        if ($this->isEmpty()) {
154
            throw new UnderflowException();
155
        }
156
157
        $value = $this->last();
158
        unset($this[$this->count() - 1]);
159
160
        $this->checkCapacity();
161
162
        return $value;
163
    }
164
165
    /**
166
     * Pushes all values of either an array or traversable object.
167
     */
168
    private function pushAll($values)
169
    {
170
        $size = $this->getSize();
171
172
        foreach ($values as $value) {
173
            $this->setSize(++$size);
174
            $this[$size - 1] = $value;
175
        }
176
177
        $this->checkCapacity();
178
    }
179
180
    /**
181
     * @inheritDoc
182
     */
183
    public function push(...$values)
184
    {
185
        $this->pushAll($values);
186
    }
187
188
    public function toArray(): array
189
    {
190
        return $this->sfa->toArray();
191
    }
192
193
    protected function validIndex(int $index)
194
    {
195
        return $index >= 0 && $index < $this->getSize();
196
    }
197
198
    /**
199
     * Countable
200
     */
201
    public function count(): int
202
    {
203
        return count($this->sfa);
204
    }
205
206
    /**
207
     * Iterator
208
     */
209
    public function current()
210
    {
211
        return $this->sfa->current();
212
    }
213
214
    public function key(): int
215
    {
216
        return $this->sfa->key();
217
    }
218
219
    public function next()
220
    {
221
        return $this->sfa->next();
222
    }
223
224
    public function rewind()
225
    {
226
        return $this->sfa->rewind();
227
    }
228
229
    public function valid()
230
    {
231
        return $this->sfa->valid();
232
    }
233
234
    /**
235
     * ArrayAccess
236
     */
237
    public function offsetExists($offset): bool
238
    {
239
        return is_integer($offset)
240
            && $this->validIndex($offset)
241
            && $this->sfa->offsetExists($offset);
242
    }
243
244
    public function offsetGet($offset)
245
    {
246
        return $this->sfa->offsetGet($offset);
247
    }
248
249
    public function offsetSet($offset, $value)
250
    {
251
        if ($offset === null) {
252
            $this->push($value);
253
        } elseif (is_integer($offset) && $this->validIndex($offset)) {
254
            $this->sfa->offsetSet($offset, $value);
255
        }
256
    }
257
258
    public function offsetUnset($offset)
259
    {
260
        return is_integer($offset)
261
            && $this->validIndex($offset)
262
            && $this->sfa->offsetUnset($offset);
263
    }
264
265
    public function clear()
266
    {
267
        return $this->sfa->clear();
268
    }
269
270
    protected function getMainTraversable(): Traversable
271
    {
272
        return $this->sfa;
273
    }
274
275
    protected function setTraversable(Traversable $traversable)
276
    {
277
        $this->sfa = $traversable;
278
    }
279
280
    /**
281
     * Gets the size of the array.
282
     *
283
     * @return int
284
     */
285
    protected function getSize(): int
286
    {
287
        return $this->sfa->getSize();
288
    }
289
290
    /**
291
     * Change the size of an array to the new size of size.
292
     * If size is less than the current array size, any values after the
293
     * new size will be discarded. If size is greater than the current
294
     * array size, the array will be padded with NULL values.
295
     *
296
     * @param int $size The new array size. This should be a value between 0
297
     * and PHP_INT_MAX.
298
     * @return bool Returns TRUE on success or FALSE on failure.
299
     */
300
    protected function setSize(int $size): bool
301
    {
302
        return $this->sfa->setSize($size);
303
    }
304
305
    abstract protected function checkCapacity();
306
307
    abstract public function isEmpty(): bool;
308
309
    abstract public function find(callable $callback);
310
}
311