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

Stream::reverse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
crap 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace Innmind\Immutable;
5
6
use Innmind\Immutable\Exception\{
7
    LogicException,
8
    GroupEmptySequenceException,
9
    InvalidArgumentException
10
};
11
12
/**
13
 * {@inheritdoc}
14
 */
15
class Stream implements StreamInterface
16
{
17
    use Type;
18
19
    private $type;
20
    private $spec;
21
    private $values;
22
23 228
    public function __construct(string $type)
24
    {
25 228
        $this->type = new Str($type);
26 228
        $this->spec = $this->getSpecificationFor($type);
27 228
        $this->values = new Sequence;
28 228
    }
29
30
    /**
31
     * {@inheritdoc}
32
     */
33 88
    public function type(): Str
34
    {
35 88
        return $this->type;
36
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41 32
    public function size(): int
42
    {
43 32
        return $this->values->size();
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 10
    public function count(): int
50
    {
51 10
        return $this->values->size();
52
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57 86
    public function toPrimitive()
58
    {
59 86
        return $this->values->toPrimitive();
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65 62
    public function current()
66
    {
67 62
        return $this->values->current();
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73 42
    public function key()
74
    {
75 42
        return $this->values->key();
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81 58
    public function next()
82
    {
83 58
        $this->values->next();
84 58
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 62
    public function rewind()
90
    {
91 62
        $this->values->rewind();
92 62
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97 62
    public function valid()
98
    {
99 62
        return $this->values->valid();
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105 2
    public function offsetExists($offset): bool
106
    {
107 2
        return $this->values->offsetExists($offset);
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113 10
    public function offsetGet($offset)
114
    {
115 10
        return $this->get($offset);
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121 2
    public function offsetSet($offset, $value)
122
    {
123 2
        throw new LogicException('You can\'t modify a stream');
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 2
    public function offsetUnset($offset)
130
    {
131 2
        throw new LogicException('You can\'t modify a stream');
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137 44
    public function get(int $index)
138
    {
139 44
        return $this->values->get($index);
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145 4
    public function diff(StreamInterface $stream): StreamInterface
146
    {
147 4
        $this->validate($stream);
148
149 4
        $newStream = clone $this;
150 4
        $newStream->values = $this->values->diff(
151 4
            new Sequence(...$stream)
0 ignored issues
show
Documentation introduced by
new \Innmind\Immutable\Sequence(...$stream) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<self>.

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...
152
        );
153
154 4
        return $newStream;
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160 2
    public function distinct(): StreamInterface
161
    {
162 2
        $stream = clone $this;
163 2
        $stream->values = $this->values->distinct();
164
165 2
        return $stream;
166
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171 16
    public function drop(int $size): StreamInterface
172
    {
173 16
        $stream = clone $this;
174 16
        $stream->values = $this->values->drop($size);
175
176 16
        return $stream;
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182 2
    public function dropEnd(int $size): StreamInterface
183
    {
184 2
        $stream = clone $this;
185 2
        $stream->values = $this->values->dropEnd($size);
186
187 2
        return $stream;
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193 16
    public function equals(StreamInterface $stream): bool
194
    {
195 16
        $this->validate($stream);
196
197 14
        return $this->values->equals(
198 14
            new Sequence(...$stream)
0 ignored issues
show
Documentation introduced by
new \Innmind\Immutable\Sequence(...$stream) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<self>.

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...
199
        );
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205 4
    public function filter(callable $predicate): StreamInterface
206
    {
207 4
        $stream = clone $this;
208 4
        $stream->values = $this->values->filter($predicate);
209
210 4
        return $stream;
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function foreach(callable $function): StreamInterface
217
    {
218 4
        $this->values->foreach($function);
219
220 4
        return $this;
221
    }
222
223
    /**
224
     * {@inheritdoc}
225
     */
226 6 View Code Duplication
    public function groupBy(callable $discriminator): MapInterface
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...
227
    {
228 6
        if ($this->size() === 0) {
229 2
            throw new GroupEmptySequenceException;
230
        }
231
232 4
        $map = null;
233
234 4
        foreach ($this->values as $value) {
235 4
            $key = $discriminator($value);
236
237 4
            if ($map === null) {
238 4
                $map = new Map(
239 4
                    $this->determineType($key),
240 4
                    StreamInterface::class
241
                );
242
            }
243
244 4
            if ($map->contains($key)) {
245 4
                $map = $map->put(
246
                    $key,
247 4
                    $map->get($key)->add($value)
248
                );
249
            } else {
250 4
                $map = $map->put(
251
                    $key,
252 4
                    (new self((string) $this->type))->add($value)
253
                );
254
            }
255
        }
256
257 4
        return $map;
258
    }
259
260
    /**
261
     * {@inheritdoc}
262
     */
263 4
    public function first()
264
    {
265 4
        return $this->values->first();
266
    }
267
268
    /**
269
     * {@inheritdoc}
270
     */
271 4
    public function last()
272
    {
273 4
        return $this->values->last();
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279 98
    public function contains($element): bool
280
    {
281 98
        return $this->values->contains($element);
282
    }
283
284
    /**
285
     * {@inheritdoc}
286
     */
287 38
    public function indexOf($element): int
288
    {
289 38
        return $this->values->indexOf($element);
290
    }
291
292
    /**
293
     * {@inheritdoc}
294
     */
295 2
    public function indices(): StreamInterface
296
    {
297 2
        $stream = new self('int');
298 2
        $stream->values = $this->values->indices();
299
300 2
        return $stream;
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306 6
    public function map(callable $function): StreamInterface
307
    {
308
        return $this
309 6
            ->values
310 6
            ->reduce(
311 6
                new self((string) $this->type),
312 6
                function(self $carry, $element) use($function): StreamInterface {
313 6
                    return $carry->add($function($element));
314 6
                }
315
            );
316
    }
317
318
    /**
319
     * {@inheritdoc}
320
     */
321 4 View Code Duplication
    public function pad(int $size, $element): StreamInterface
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...
322
    {
323 4
        $this->spec->validate($element);
324
325 2
        $stream = clone $this;
326 2
        $stream->values = $this->values->pad($size, $element);
327
328 2
        return $stream;
329
    }
330
331
    /**
332
     * {@inheritdoc}
333
     */
334 4
    public function partition(callable $predicate): MapInterface
335
    {
336 4
        $truthy = new self((string) $this->type);
337 4
        $falsy = new self((string) $this->type);
338
339 4
        foreach ($this->values as $value) {
340 4
            if ($predicate($value) === true) {
341 4
                $truthy = $truthy->add($value);
342
            } else {
343 4
                $falsy = $falsy->add($value);
344
            }
345
        }
346
347 4
        return (new Map('bool', StreamInterface::class))
348 4
            ->put(true, $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
$truthy is of type object<Innmind\Immutable\Stream>, 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...
349 4
            ->put(false, $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
$falsy is of type object<Innmind\Immutable\Stream>, 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...
350
    }
351
352
    /**
353
     * {@inheritdoc}
354
     */
355 6
    public function slice(int $from, int $until): StreamInterface
356
    {
357 6
        $stream = clone $this;
358 6
        $stream->values = $this->values->slice($from, $until);
359
360 6
        return $stream;
361
    }
362
363
    /**
364
     * {@inheritdoc}
365
     */
366 2
    public function splitAt(int $position): StreamInterface
367
    {
368 2
        $stream = new self(StreamInterface::class);
369 2
        $splitted = $this->values->splitAt($position);
370 2
        $first = new self((string) $this->type);
371 2
        $second = new self((string) $this->type);
372 2
        $first->values = $splitted->first();
373 2
        $second->values = $splitted->last();
374
375 2
        return $stream->add($first)->add($second);
2 ignored issues
show
Documentation introduced by
$first is of type object<Innmind\Immutable\Stream>, 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
$second is of type object<Innmind\Immutable\Stream>, 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...
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     */
381 16
    public function take(int $size): StreamInterface
382
    {
383 16
        $stream = clone $this;
384 16
        $stream->values = $this->values->take($size);
385
386 16
        return $stream;
387
    }
388
389
    /**
390
     * {@inheritdoc}
391
     */
392 2
    public function takeEnd(int $size): StreamInterface
393
    {
394 2
        $stream = clone $this;
395 2
        $stream->values = $this->values->takeEnd($size);
396
397 2
        return $stream;
398
    }
399
400
    /**
401
     * {@inheritdoc}
402
     */
403 22 View Code Duplication
    public function append(StreamInterface $stream): StreamInterface
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...
404
    {
405 22
        $this->validate($stream);
406
407 20
        $self = clone $this;
408 20
        $self->values = $this->values->append(
409 20
            new Sequence(...$stream)
0 ignored issues
show
Documentation introduced by
new \Innmind\Immutable\Sequence(...$stream) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<self>.

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...
410
        );
411
412 20
        return $self;
413
    }
414
415
    /**
416
     * {@inheritdoc}
417
     */
418 6 View Code Duplication
    public function intersect(StreamInterface $stream): StreamInterface
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...
419
    {
420 6
        $this->validate($stream);
421
422 4
        $self = clone $this;
423 4
        $self->values = $this->values->intersect(
424 4
            new Sequence(...$stream)
0 ignored issues
show
Documentation introduced by
new \Innmind\Immutable\Sequence(...$stream) is of type object<Innmind\Immutable\Sequence>, but the function expects a object<self>.

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...
425
        );
426
427 4
        return $self;
428
    }
429
430
    /**
431
     * {@inheritdoc}
432
     */
433 8
    public function join(string $separator): Str
434
    {
435 8
        return new Str((string) $this->values->join($separator));
436
    }
437
438
    /**
439
     * {@inheritdoc}
440
     */
441 176 View Code Duplication
    public function add($element): StreamInterface
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...
442
    {
443 176
        $this->spec->validate($element);
444
445 174
        $stream = clone $this;
446 174
        $stream->values = $this->values->add($element);
447
448 174
        return $stream;
449
    }
450
451
    /**
452
     * {@inheritdoc}
453
     */
454 4
    public function sort(callable $function): StreamInterface
455
    {
456 4
        $stream = clone $this;
457 4
        $stream->values = $this->values->sort($function);
458
459 4
        return $stream;
460
    }
461
462
    /**
463
     * {@inheritdoc}
464
     */
465 36
    public function reduce($carry, callable $reducer)
466
    {
467 36
        return $this->values->reduce($carry, $reducer);
468
    }
469
470
    /**
471
     * {@inheritdoc}
472
     */
473 26
    public function clear(): StreamInterface
474
    {
475 26
        $self = clone $this;
476 26
        $self->values = new Sequence;
477
478 26
        return $self;
1 ignored issue
show
Bug Best Practice introduced by
The return type of return $self; (Innmind\Immutable\Stream) is incompatible with the return type declared by the interface Innmind\Immutable\StreamInterface::clear 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...
479
    }
480
481
    /**
482
     * {@inheritdoc}
483
     */
484 2
    public function reverse(): StreamInterface
485
    {
486 2
        $self = clone $this;
487 2
        $self->values = $this->values->reverse();
488
489 2
        return $self;
1 ignored issue
show
Bug Best Practice introduced by
The return type of return $self; (Innmind\Immutable\Stream) is incompatible with the return type declared by the interface Innmind\Immutable\StreamInterface::reverse 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...
490
    }
491
492
    /**
493
     * Make sure the stream is compatible with the current one
494
     *
495
     * @param StreamInterface $stream
496
     *
497
     * @throws InvalidArgumentException
498
     *
499
     * @return void
500
     */
501 44
    private function validate(StreamInterface $stream)
502
    {
503 44
        if (!$stream->type()->equals($this->type)) {
0 ignored issues
show
Documentation introduced by
$this->type is of type object<Innmind\Immutable\Str>, but the function expects a object<self>.

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...
504 6
            throw new InvalidArgumentException(
505 6
                'The 2 streams does not reference the same type'
506
            );
507
        }
508 38
    }
509
}
510