GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( 5a4bbb...3fba13 )
by Baptiste
02:51
created

Sequence   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 428
Duplicated Lines 7.01 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 98.55%

Importance

Changes 0
Metric Value
wmc 54
lcom 1
cbo 9
dl 30
loc 428
ccs 136
cts 138
cp 0.9855
rs 7.0642
c 0
b 0
f 0

42 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A size() 0 4 1
A count() 0 4 1
A current() 0 4 1
A key() 0 4 1
A next() 0 4 1
A rewind() 0 4 1
A valid() 0 4 1
A offsetExists() 0 4 1
A offsetGet() 0 4 1
A offsetSet() 0 4 1
A offsetUnset() 0 4 1
A toPrimitive() 0 4 1
A get() 0 8 2
A has() 0 4 1
A diff() 0 9 1
A distinct() 0 4 1
A drop() 0 4 1
A dropEnd() 0 4 1
A equals() 0 4 1
A foreach() 0 8 2
A first() 0 8 2
A last() 0 8 2
A contains() 0 4 1
A indexOf() 0 10 2
A indices() 0 10 2
A map() 0 4 1
A pad() 0 4 1
A partition() 0 17 3
A splitAt() 0 6 1
A take() 0 4 1
A takeEnd() 0 4 1
A append() 0 4 1
A intersect() 0 4 1
A join() 0 4 1
A add() 0 7 1
A sort() 0 7 1
A reduce() 0 4 1
A filter() 0 7 1
B groupBy() 30 30 5
A slice() 0 8 1
A reverse() 0 4 1

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

1
<?php
2
declare(strict_types = 1);
3
4
namespace Innmind\Immutable;
5
6
use Innmind\Immutable\{
7
    Exception\OutOfBoundException,
8
    Exception\LogicException,
9
    Exception\ElementNotFoundException,
10
    Exception\GroupEmptySequenceException
11
};
12
13
/**
14
 * A defined set of ordered elements
15
 */
16
class Sequence implements SequenceInterface
17
{
18
    use Type;
19
20
    private $values;
21
    private $size;
22
23 300
    public function __construct(...$values)
24
    {
25 300
        $this->values = $values;
26 300
        $this->size = count($values);
27 300
    }
28
29
    /**
30
     * {@inheritdoc}
31
     */
32 66
    public function size(): int
33
    {
34 66
        return $this->size;
35
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 2
    public function count(): int
41
    {
42 2
        return $this->size();
43
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48 68
    public function current()
49
    {
50 68
        return current($this->values);
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56 72
    public function key()
57
    {
58 72
        return key($this->values);
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64 68
    public function next()
65
    {
66 68
        next($this->values);
67 68
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72 68
    public function rewind()
73
    {
74 68
        reset($this->values);
75 68
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80 68
    public function valid(): bool
81
    {
82 68
        return $this->key() !== null;
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 2
    public function offsetExists($offset): bool
89
    {
90 2
        return $this->has($offset);
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96 2
    public function offsetGet($offset)
97
    {
98 2
        return $this->get($offset);
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 2
    public function offsetSet($offset, $value)
105
    {
106 2
        throw new LogicException('You can\'t modify a sequence');
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 2
    public function offsetUnset($offset)
113
    {
114 2
        throw new LogicException('You can\'t modify a sequence');
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 136
    public function toPrimitive()
121
    {
122 136
        return $this->values;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 50
    public function get(int $index)
129
    {
130 50
        if (!$this->has($index)) {
131 6
            throw new OutOfBoundException;
132
        }
133
134 44
        return $this->values[$index];
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140 54
    public function has(int $index): bool
141
    {
142 54
        return array_key_exists($index, $this->values);
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148 6
    public function diff(SequenceInterface $seq): SequenceInterface
149
    {
150 6
        return new self(
151 6
            ...array_diff(
152 6
                $this->values,
153 6
                $seq->toPrimitive()
154
            )
155
        );
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161 4
    public function distinct(): SequenceInterface
162
    {
163 4
        return new self(...array_unique($this->values));
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169 18
    public function drop(int $size): SequenceInterface
170
    {
171 18
        return new self(...array_slice($this->values, $size));
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177 4
    public function dropEnd(int $size): SequenceInterface
178
    {
179 4
        return new self(...array_slice($this->values, 0, $this->size() - $size));
180
    }
181
182
    /**
183
     * {@inheritdoc}
184
     */
185 16
    public function equals(SequenceInterface $seq): bool
186
    {
187 16
        return $this->values === $seq->toPrimitive();
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193 6
    public function filter(callable $predicate): SequenceInterface
194
    {
195 6
        return new self(...array_filter(
196 6
            $this->values,
197 6
            $predicate
198
        ));
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204 6
    public function foreach(callable $function): SequenceInterface
205
    {
206 6
        foreach ($this->values as $value) {
207 6
            $function($value);
208
        }
209
210 6
        return $this;
1 ignored issue
show
Bug Best Practice introduced by
The return type of return $this; (Innmind\Immutable\Sequence) is incompatible with the return type declared by the interface Innmind\Immutable\SequenceInterface::foreach of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216 4 View Code Duplication
    public function groupBy(callable $discriminator): MapInterface
217
    {
218 4
        if ($this->size() === 0) {
219 2
            throw new GroupEmptySequenceException;
220
        }
221
222 2
        $map = null;
223
224 2
        foreach ($this->values as $value) {
225 2
            $key = $discriminator($value);
226
227 2
            if ($map === null) {
228 2
                $map = new Map(
229 2
                    $this->determineType($key),
230 2
                    SequenceInterface::class
231
                );
232
            }
233
234 2
            if ($map->contains($key)) {
235 2
                $map = $map->put(
236
                    $key,
237 2
                    $map->get($key)->add($value)
238
                );
239
            } else {
240 2
                $map = $map->put($key, new self($value));
241
            }
242
        }
243
244 2
        return $map;
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250 8
    public function first()
251
    {
252 8
        if ($this->size() === 0) {
253 2
            throw new OutOfBoundException;
254
        }
255
256 6
        return $this->values[0];
257
    }
258
259
    /**
260
     * {@inheritdoc}
261
     */
262 8
    public function last()
263
    {
264 8
        if ($this->size() === 0) {
265 2
            throw new OutOfBoundException;
266
        }
267
268 6
        return $this->values[$this->size() - 1];
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274 100
    public function contains($element): bool
275
    {
276 100
        return in_array($element, $this->values, true);
277
    }
278
279
    /**
280
     * {@inheritdoc}
281
     */
282 42
    public function indexOf($element): int
283
    {
284 42
        $index = array_search($element, $this->values, true);
285
286 42
        if ($index === false) {
287 2
            throw new ElementNotFoundException;
288
        }
289
290 40
        return $index;
291
    }
292
293
    /**
294
     * {@inheritdoc}
295
     */
296 4
    public function indices(): StreamInterface
297
    {
298 4
        $indices = new Stream('int');
299
300 4
        foreach ($this->values as $index => $value) {
301 4
            $indices = $indices->add($index);
1 ignored issue
show
Documentation introduced by
$index is of type integer, but the function expects a object<Innmind\Immutable\T>.

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...
302
        }
303
304 4
        return $indices;
305
    }
306
307
    /**
308
     * {@inheritdoc}
309
     */
310 2
    public function map(callable $function): SequenceInterface
311
    {
312 2
        return new self(...array_map($function, $this->values));
313
    }
314
315
    /**
316
     * {@inheritdoc}
317
     */
318 4
    public function pad(int $size, $element): SequenceInterface
319
    {
320 4
        return new self(...array_pad($this->values, $size, $element));
321
    }
322
323
    /**
324
     * {@inheritdoc}
325
     */
326 2
    public function partition(callable $predicate): MapInterface
327
    {
328 2
        $truthy = [];
329 2
        $falsy = [];
330
331 2
        foreach ($this->values as $value) {
332 2
            if ($predicate($value) === true) {
333 2
                $truthy[] = $value;
334
            } else {
335 2
                $falsy[] = $value;
336
            }
337
        }
338
339 2
        return (new Map('bool', SequenceInterface::class))
340 2
            ->put(true, new self(...$truthy))
2 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a object<Innmind\Immutable\T>.

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...
Documentation introduced by
new self(...$truthy) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<Innmind\Immutable\S>.

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...
341 2
            ->put(false, new self(...$falsy));
2 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a object<Innmind\Immutable\T>.

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...
Documentation introduced by
new self(...$falsy) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<Innmind\Immutable\S>.

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...
342
    }
343
344
    /**
345
     * {@inheritdoc}
346
     */
347 34
    public function slice(int $from, int $until): SequenceInterface
348
    {
349 34
        return new self(...array_slice(
350 34
            $this->values,
351
            $from,
352 34
            $until - $from
353
        ));
354
    }
355
356
    /**
357
     * {@inheritdoc}
358
     */
359 4
    public function splitAt(int $index): StreamInterface
360
    {
361 4
        return (new Stream(SequenceInterface::class))
362 4
            ->add($this->slice(0, $index))
1 ignored issue
show
Documentation introduced by
$this->slice(0, $index) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<Innmind\Immutable\T>.

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...
363 4
            ->add($this->slice($index, $this->size()));
1 ignored issue
show
Documentation introduced by
$this->slice($index, $this->size()) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<Innmind\Immutable\T>.

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...
364
    }
365
366
    /**
367
     * {@inheritdoc}
368
     */
369 18
    public function take(int $size): SequenceInterface
370
    {
371 18
        return $this->slice(0, $size);
372
    }
373
374
    /**
375
     * {@inheritdoc}
376
     */
377 4
    public function takeEnd(int $size): SequenceInterface
378
    {
379 4
        return $this->slice($this->size() - $size, $this->size());
380
    }
381
382
    /**
383
     * {@inheritdoc}
384
     */
385 22
    public function append(SequenceInterface $seq): SequenceInterface
386
    {
387 22
        return new self(...$this->values, ...$seq->toPrimitive());
388
    }
389
390
    /**
391
     * {@inheritdoc}
392
     */
393 6
    public function intersect(SequenceInterface $seq): SequenceInterface
394
    {
395 6
        return new self(...array_intersect($this->values, $seq->toPrimitive()));
396
    }
397
398
    /**
399
     * {@inheritdoc}
400
     */
401 10
    public function join(string $separator): Str
402
    {
403 10
        return new Str(implode($separator, $this->values));
404
    }
405
406
    /**
407
     * {@inheritdoc}
408
     */
409 176
    public function add($element): SequenceInterface
410
    {
411 176
        $values = $this->values;
412 176
        $values[] = $element;
413
414 176
        return new self(...$values);
415
    }
416
417
    /**
418
     * {@inheritdoc}
419
     */
420 6
    public function sort(callable $function): SequenceInterface
421
    {
422 6
        $values = $this->values;
423 6
        usort($values, $function);
424
425 6
        return new self(...$values);
426
    }
427
428
    /**
429
     * {@inheritdoc}
430
     */
431 44
    public function reduce($carry, callable $reducer)
432
    {
433 44
        return array_reduce($this->values, $reducer, $carry);
434
    }
435
436
    /**
437
     * {@inheritdoc}
438
     */
439 4
    public function reverse(): SequenceInterface
440
    {
441 4
        return new self(...array_reverse($this->values));
442
    }
443
}
444